|
|
@@ -81,7 +81,6 @@ int gpu_threads;
|
|
|
|
|
|
bool opt_protocol = false;
|
|
|
static bool opt_benchmark;
|
|
|
-static bool want_longpoll = true;
|
|
|
static bool have_longpoll = false;
|
|
|
static bool want_per_device_stats = false;
|
|
|
bool use_syslog = false;
|
|
|
@@ -144,7 +143,6 @@ char *cgminer_path;
|
|
|
|
|
|
struct thr_info *thr_info;
|
|
|
static int work_thr_id;
|
|
|
-int longpoll_thr_id;
|
|
|
static int stage_thr_id;
|
|
|
static int watchpool_thr_id;
|
|
|
static int watchdog_thr_id;
|
|
|
@@ -428,16 +426,6 @@ bool pool_tclear(struct pool *pool, bool *var)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static bool pool_isset(struct pool *pool, bool *var)
|
|
|
-{
|
|
|
- bool ret;
|
|
|
-
|
|
|
- mutex_lock(&pool->pool_lock);
|
|
|
- ret = *var;
|
|
|
- mutex_unlock(&pool->pool_lock);
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
struct pool *current_pool(void)
|
|
|
{
|
|
|
struct pool *pool;
|
|
|
@@ -850,9 +838,6 @@ static struct opt_table opt_config_table[] = {
|
|
|
opt_hidden
|
|
|
#endif
|
|
|
),
|
|
|
- OPT_WITHOUT_ARG("--no-longpoll",
|
|
|
- opt_set_invbool, &want_longpoll,
|
|
|
- "Disable X-Long-Polling support"),
|
|
|
OPT_WITHOUT_ARG("--no-restart",
|
|
|
opt_set_invbool, &opt_restart,
|
|
|
#ifdef HAVE_OPENCL
|
|
|
@@ -1646,11 +1631,6 @@ static bool submit_upstream_work(const struct work *work)
|
|
|
|
|
|
applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, sd);
|
|
|
|
|
|
- /* Force a fresh connection in case there are dead persistent
|
|
|
- * connections to this pool */
|
|
|
- if (pool_isset(pool, &pool->submit_fail))
|
|
|
- curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
|
|
|
-
|
|
|
/* issue JSON-RPC request */
|
|
|
val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, s, false, false, &rolltime, pool, true);
|
|
|
if (unlikely(!val)) {
|
|
|
@@ -1826,12 +1806,8 @@ retry:
|
|
|
}
|
|
|
|
|
|
rc = work_decode(json_object_get(val, "result"), work);
|
|
|
- if (!rc && retries < 3) {
|
|
|
- /* Force a fresh connection in case there are dead persistent
|
|
|
- * connections */
|
|
|
- curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
|
|
|
+ if (!rc && retries < 3)
|
|
|
goto retry;
|
|
|
- }
|
|
|
work->pool = pool;
|
|
|
work->longpoll = false;
|
|
|
total_getworks++;
|
|
|
@@ -1947,11 +1923,6 @@ static void __kill_work(void)
|
|
|
thr = &thr_info[stage_thr_id];
|
|
|
thr_info_cancel(thr);
|
|
|
|
|
|
- applog(LOG_DEBUG, "Killing off longpoll thread");
|
|
|
- thr = &thr_info[longpoll_thr_id];
|
|
|
- if (have_longpoll)
|
|
|
- thr_info_cancel(thr);
|
|
|
-
|
|
|
applog(LOG_DEBUG, "Killing off API thread");
|
|
|
thr = &thr_info[api_thr_id];
|
|
|
thr_info_cancel(thr);
|
|
|
@@ -1999,9 +1970,6 @@ static void sighandler(int __maybe_unused sig)
|
|
|
kill_work();
|
|
|
}
|
|
|
|
|
|
-static void start_longpoll(void);
|
|
|
-static void stop_longpoll(void);
|
|
|
-
|
|
|
/* One get work thread is created per pool, so as to use one curl handle for
|
|
|
* all getwork reqeusts from the same pool, minimising connections opened, but
|
|
|
* separate from the submit work curl handle to not delay share submissions due
|
|
|
@@ -2027,12 +1995,6 @@ static void *get_work_thread(void *userdata)
|
|
|
struct work *ret_work;
|
|
|
int failures = 0;
|
|
|
|
|
|
- if (unlikely(want_longpoll && !pool->is_lp && pool == current_pool() &&
|
|
|
- pool->hdr_path && !pool_tset(pool, &pool->lp_sent))) {
|
|
|
- stop_longpoll();
|
|
|
- start_longpoll();
|
|
|
- }
|
|
|
-
|
|
|
ret_work = make_work();
|
|
|
|
|
|
if (wc->thr)
|
|
|
@@ -2129,10 +2091,10 @@ static void *submit_work_thread(void *userdata)
|
|
|
int failures = 0;
|
|
|
|
|
|
if (stale_work(work, true)) {
|
|
|
- if (opt_submit_stale)
|
|
|
- applog(LOG_NOTICE, "Stale share detected, submitting as user requested");
|
|
|
- else if (pool->submit_old)
|
|
|
+ if (pool->submit_old)
|
|
|
applog(LOG_NOTICE, "Stale share detected, submitting as pool requested");
|
|
|
+ else if (opt_submit_stale)
|
|
|
+ applog(LOG_NOTICE, "Stale share detected, submitting as user requested");
|
|
|
else {
|
|
|
applog(LOG_NOTICE, "Stale share detected, discarding");
|
|
|
sharelog("discard", work);
|
|
|
@@ -2145,8 +2107,8 @@ static void *submit_work_thread(void *userdata)
|
|
|
|
|
|
/* submit solution to bitcoin via JSON-RPC */
|
|
|
while (!submit_upstream_work(work)) {
|
|
|
- if (!opt_submit_stale && stale_work(work, true)) {
|
|
|
- applog(LOG_NOTICE, "Stale share detected, discarding");
|
|
|
+ if (!opt_submit_stale && stale_work(work, true) && !pool->submit_old) {
|
|
|
+ applog(LOG_NOTICE, "Stale share detected on submit retry, discarding");
|
|
|
total_stale++;
|
|
|
pool->stale_shares++;
|
|
|
break;
|
|
|
@@ -2580,6 +2542,7 @@ void remove_pool(struct pool *pool)
|
|
|
}
|
|
|
/* Give it an invalid number */
|
|
|
pool->pool_no = total_pools;
|
|
|
+ pool->removed = true;
|
|
|
total_pools--;
|
|
|
}
|
|
|
|
|
|
@@ -2949,7 +2912,6 @@ static void set_options(void)
|
|
|
immedok(logwin, true);
|
|
|
clear_logwin();
|
|
|
retry:
|
|
|
- wlogprint("\n[L]ongpoll: %s\n", want_longpoll ? "On" : "Off");
|
|
|
wlogprint("[Q]ueue: %d\n[S]cantime: %d\n[E]xpiry: %d\n[R]etries: %d\n"
|
|
|
"[P]ause: %d\n[W]rite config file\n[B]FGMiner restart\n",
|
|
|
opt_queue, opt_scantime, opt_expiry, opt_retries, opt_fail_pause);
|
|
|
@@ -2964,15 +2926,6 @@ retry:
|
|
|
}
|
|
|
opt_queue = selected;
|
|
|
goto retry;
|
|
|
- } else if (!strncasecmp(&input, "l", 1)) {
|
|
|
- want_longpoll ^= true;
|
|
|
- applog(LOG_WARNING, "Longpoll %s", want_longpoll ? "enabled" : "disabled");
|
|
|
- if (!want_longpoll) {
|
|
|
- if (have_longpoll)
|
|
|
- stop_longpoll();
|
|
|
- } else
|
|
|
- start_longpoll();
|
|
|
- goto retry;
|
|
|
} else if (!strncasecmp(&input, "s", 1)) {
|
|
|
selected = curses_int("Set scantime in seconds");
|
|
|
if (selected < 0 || selected > 9999) {
|
|
|
@@ -3266,6 +3219,8 @@ out_unlock:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void *longpoll_thread(void *userdata);
|
|
|
+
|
|
|
static bool pool_active(struct pool *pool, bool pinging)
|
|
|
{
|
|
|
bool ret = false;
|
|
|
@@ -3308,9 +3263,8 @@ static bool pool_active(struct pool *pool, bool pinging)
|
|
|
}
|
|
|
json_decref(val);
|
|
|
|
|
|
- /* We may be updating the url after the pool has died */
|
|
|
if (pool->lp_url)
|
|
|
- free(pool->lp_url);
|
|
|
+ goto out;
|
|
|
|
|
|
/* Decipher the longpoll URL, if any, and store it in ->lp_url */
|
|
|
if (pool->hdr_path) {
|
|
|
@@ -3337,13 +3291,19 @@ static bool pool_active(struct pool *pool, bool pinging)
|
|
|
}
|
|
|
} else
|
|
|
pool->lp_url = NULL;
|
|
|
+
|
|
|
+ if (!pool->lp_started) {
|
|
|
+ pool->lp_started = true;
|
|
|
+ if (unlikely(pthread_create(&pool->longpoll_thread, NULL, longpoll_thread, (void *)pool)))
|
|
|
+ quit(1, "Failed to create pool longpoll thread");
|
|
|
+ }
|
|
|
} else {
|
|
|
applog(LOG_DEBUG, "FAILED to retrieve work from pool %u %s",
|
|
|
pool->pool_no, pool->rpc_url);
|
|
|
if (!pinging)
|
|
|
applog(LOG_WARNING, "Pool %u slow/down or URL or credentials invalid", pool->pool_no);
|
|
|
}
|
|
|
-
|
|
|
+out:
|
|
|
curl_easy_cleanup(curl);
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -3842,19 +3802,28 @@ enum {
|
|
|
/* Stage another work item from the work returned in a longpoll */
|
|
|
static void convert_to_work(json_t *val, bool rolltime, struct pool *pool)
|
|
|
{
|
|
|
+ struct pool *cp = current_pool();
|
|
|
struct work *work, *work_clone;
|
|
|
bool rc;
|
|
|
|
|
|
+ /* Don't use as work if we have failover-only enabled */
|
|
|
+ if (pool != cp && opt_fail_only)
|
|
|
+ return;
|
|
|
+
|
|
|
work = make_work();
|
|
|
|
|
|
- rc= work_decode(json_object_get(val, "result"), work);
|
|
|
+ rc = work_decode(json_object_get(val, "result"), work);
|
|
|
if (unlikely(!rc)) {
|
|
|
applog(LOG_ERR, "Could not convert longpoll data to work");
|
|
|
+ free_work(work);
|
|
|
return;
|
|
|
}
|
|
|
work->pool = pool;
|
|
|
work->rolltime = rolltime;
|
|
|
- work->longpoll = true;
|
|
|
+
|
|
|
+ /* Only flag this as longpoll work if the pool is the current pool */
|
|
|
+ if (pool == cp)
|
|
|
+ work->longpoll = true;
|
|
|
|
|
|
/* We'll be checking this work item twice, but we already know it's
|
|
|
* from a new block so explicitly force the new block detection now
|
|
|
@@ -3886,9 +3855,8 @@ static void convert_to_work(json_t *val, bool rolltime, struct pool *pool)
|
|
|
/* If we want longpoll, enable it for the chosen default pool, or, if
|
|
|
* the pool does not support longpoll, find the first one that does
|
|
|
* and use its longpoll support */
|
|
|
-static struct pool *select_longpoll_pool(void)
|
|
|
+static struct pool *select_longpoll_pool(struct pool *cp)
|
|
|
{
|
|
|
- struct pool *cp = current_pool();
|
|
|
int i;
|
|
|
|
|
|
if (cp->hdr_path)
|
|
|
@@ -3904,37 +3872,37 @@ static struct pool *select_longpoll_pool(void)
|
|
|
|
|
|
static void *longpoll_thread(void *userdata)
|
|
|
{
|
|
|
- struct thr_info *mythr = userdata;
|
|
|
+ struct pool *cp = (struct pool *)userdata;
|
|
|
+ /* This *pool is the source of the actual longpoll, not the pool we've
|
|
|
+ * tied it to */
|
|
|
+ struct pool *pool = NULL;
|
|
|
struct timeval start, end;
|
|
|
- struct pool *sp, *pool;
|
|
|
CURL *curl = NULL;
|
|
|
int failures = 0;
|
|
|
bool rolltime;
|
|
|
|
|
|
- pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
|
|
-
|
|
|
curl = curl_easy_init();
|
|
|
if (unlikely(!curl)) {
|
|
|
applog(LOG_ERR, "CURL initialisation failed");
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- tq_pop(mythr->q, NULL);
|
|
|
-
|
|
|
- pool = select_longpoll_pool();
|
|
|
+retry_pool:
|
|
|
+ pool = select_longpoll_pool(cp);
|
|
|
if (!pool) {
|
|
|
- applog(LOG_WARNING, "No long-poll found on any pool server");
|
|
|
+ applog(LOG_WARNING, "No suitable long-poll found for pool %s", cp->rpc_url);
|
|
|
while (!pool) {
|
|
|
- sleep(30);
|
|
|
- pool = select_longpoll_pool();
|
|
|
+ sleep(60);
|
|
|
+ pool = select_longpoll_pool(cp);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- pool->is_lp = true;
|
|
|
- have_longpoll = true;
|
|
|
- applog(LOG_WARNING, "Long-polling activated for %s", pool->lp_url);
|
|
|
+ if (cp == pool)
|
|
|
+ applog(LOG_WARNING, "Long-polling activated for %s", pool->lp_url);
|
|
|
+ else
|
|
|
+ applog(LOG_WARNING, "Long-polling activated for pool %s via %s", cp->rpc_url, pool->lp_url);
|
|
|
|
|
|
- while (1) {
|
|
|
+ while (42) {
|
|
|
json_t *val, *soval;
|
|
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
@@ -3973,45 +3941,23 @@ static void *longpoll_thread(void *userdata)
|
|
|
goto out;
|
|
|
}
|
|
|
}
|
|
|
- sp = select_longpoll_pool();
|
|
|
- if (sp != pool) {
|
|
|
- pool->is_lp = false;
|
|
|
- pool = sp;
|
|
|
- pool->is_lp = true;
|
|
|
- applog(LOG_WARNING, "Long-polling changed to %s", pool->lp_url);
|
|
|
+ if (pool != cp) {
|
|
|
+ pool = select_longpoll_pool(cp);
|
|
|
+ if (unlikely(!pool))
|
|
|
+ goto retry_pool;
|
|
|
}
|
|
|
+
|
|
|
+ if (unlikely(pool->removed))
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
out:
|
|
|
if (curl)
|
|
|
curl_easy_cleanup(curl);
|
|
|
|
|
|
- tq_freeze(mythr->q);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-static void stop_longpoll(void)
|
|
|
-{
|
|
|
- struct thr_info *thr = &thr_info[longpoll_thr_id];
|
|
|
-
|
|
|
- thr_info_cancel(thr);
|
|
|
- if (have_longpoll)
|
|
|
- pthread_join(thr->pth, NULL);
|
|
|
- have_longpoll = false;
|
|
|
- tq_freeze(thr->q);
|
|
|
-}
|
|
|
-
|
|
|
-static void start_longpoll(void)
|
|
|
-{
|
|
|
- struct thr_info *thr = &thr_info[longpoll_thr_id];
|
|
|
-
|
|
|
- tq_thaw(thr->q);
|
|
|
- if (unlikely(thr_info_create(thr, NULL, longpoll_thread, thr)))
|
|
|
- quit(1, "longpoll thread create failed");
|
|
|
- applog(LOG_DEBUG, "Pushing ping to longpoll thread");
|
|
|
- tq_push(thr_info[longpoll_thr_id].q, &ping);
|
|
|
-}
|
|
|
-
|
|
|
void reinit_device(struct cgpu_info *cgpu)
|
|
|
{
|
|
|
if (cgpu->api->reinit_device)
|
|
|
@@ -4703,7 +4649,6 @@ int main(int argc, char *argv[])
|
|
|
if (opt_benchmark) {
|
|
|
struct pool *pool;
|
|
|
|
|
|
- want_longpoll = false;
|
|
|
pool = calloc(sizeof(struct pool), 1);
|
|
|
pool->pool_no = 0;
|
|
|
pools[total_pools++] = pool;
|
|
|
@@ -4897,7 +4842,7 @@ int main(int argc, char *argv[])
|
|
|
fork_monitor();
|
|
|
#endif // defined(unix)
|
|
|
|
|
|
- total_threads = mining_threads + 8;
|
|
|
+ total_threads = mining_threads + 7;
|
|
|
work_restart = calloc(total_threads, sizeof(*work_restart));
|
|
|
if (!work_restart)
|
|
|
quit(1, "Failed to calloc work_restart");
|
|
|
@@ -4918,15 +4863,7 @@ int main(int argc, char *argv[])
|
|
|
if (thr_info_create(thr, NULL, workio_thread, thr))
|
|
|
quit(1, "workio thread create failed");
|
|
|
|
|
|
- /* init longpoll thread info */
|
|
|
- longpoll_thr_id = mining_threads + 1;
|
|
|
- thr = &thr_info[longpoll_thr_id];
|
|
|
- thr->id = longpoll_thr_id;
|
|
|
- thr->q = tq_new();
|
|
|
- if (!thr->q)
|
|
|
- quit(1, "Failed to tq_new");
|
|
|
-
|
|
|
- stage_thr_id = mining_threads + 2;
|
|
|
+ stage_thr_id = mining_threads + 1;
|
|
|
thr = &thr_info[stage_thr_id];
|
|
|
thr->q = tq_new();
|
|
|
if (!thr->q)
|
|
|
@@ -4995,9 +4932,6 @@ int main(int argc, char *argv[])
|
|
|
}
|
|
|
} while (!pools_active);
|
|
|
|
|
|
- if (want_longpoll)
|
|
|
- start_longpoll();
|
|
|
-
|
|
|
begin_bench:
|
|
|
total_mhashes_done = 0;
|
|
|
for (i = 0; i < total_devices; i++) {
|
|
|
@@ -5065,14 +4999,14 @@ begin_bench:
|
|
|
gettimeofday(&total_tv_start, NULL);
|
|
|
gettimeofday(&total_tv_end, NULL);
|
|
|
|
|
|
- watchpool_thr_id = mining_threads + 3;
|
|
|
+ watchpool_thr_id = mining_threads + 2;
|
|
|
thr = &thr_info[watchpool_thr_id];
|
|
|
/* start watchpool thread */
|
|
|
if (thr_info_create(thr, NULL, watchpool_thread, NULL))
|
|
|
quit(1, "watchpool thread create failed");
|
|
|
pthread_detach(thr->pth);
|
|
|
|
|
|
- watchdog_thr_id = mining_threads + 4;
|
|
|
+ watchdog_thr_id = mining_threads + 3;
|
|
|
thr = &thr_info[watchdog_thr_id];
|
|
|
/* start watchdog thread */
|
|
|
if (thr_info_create(thr, NULL, watchdog_thread, NULL))
|
|
|
@@ -5080,7 +5014,7 @@ begin_bench:
|
|
|
pthread_detach(thr->pth);
|
|
|
|
|
|
/* Create reinit gpu thread */
|
|
|
- gpur_thr_id = mining_threads + 5;
|
|
|
+ gpur_thr_id = mining_threads + 4;
|
|
|
thr = &thr_info[gpur_thr_id];
|
|
|
thr->q = tq_new();
|
|
|
if (!thr->q)
|
|
|
@@ -5089,7 +5023,7 @@ begin_bench:
|
|
|
quit(1, "reinit_gpu thread create failed");
|
|
|
|
|
|
/* Create API socket thread */
|
|
|
- api_thr_id = mining_threads + 6;
|
|
|
+ api_thr_id = mining_threads + 5;
|
|
|
thr = &thr_info[api_thr_id];
|
|
|
if (thr_info_create(thr, NULL, api_thread, thr))
|
|
|
quit(1, "API thread create failed");
|
|
|
@@ -5099,7 +5033,7 @@ begin_bench:
|
|
|
/* Create curses input thread for keyboard input. Create this last so
|
|
|
* that we know all threads are created since this can call kill_work
|
|
|
* to try and shut down ll previous threads. */
|
|
|
- input_thr_id = mining_threads + 7;
|
|
|
+ input_thr_id = mining_threads + 6;
|
|
|
thr = &thr_info[input_thr_id];
|
|
|
if (thr_info_create(thr, NULL, input_thread, thr))
|
|
|
quit(1, "input thread create failed");
|