diff --git a/cpu-miner.c b/cpu-miner.c index 3391febe..bc9ea8c3 100644 --- a/cpu-miner.c +++ b/cpu-miner.c @@ -326,20 +326,12 @@ err_out: return false; } -static bool submit_upstream_work(CURL *curl, const struct work *work) +static bool submit_upstream_work(CURL *curl, char *hexstr) { - char *hexstr = NULL; json_t *val, *res; char s[345]; bool rc = false; - /* build hex string */ - hexstr = bin2hex(work->data, sizeof(work->data)); - if (unlikely(!hexstr)) { - applog(LOG_ERR, "submit_upstream_work OOM"); - goto out; - } - /* build JSON-RPC request */ sprintf(s, "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}\r\n", @@ -357,6 +349,9 @@ static bool submit_upstream_work(CURL *curl, const struct work *work) res = json_object_get(val, "result"); + /* Theoretically threads could race when modifying accepted and + * rejected values but the chance of two submits completing at the + * same time is zero so there is no point adding extra locking */ if (json_is_true(res)) { accepted++; applog(LOG_INFO, "PROOF OF WORK RESULT: true (yay!!!)"); @@ -370,7 +365,6 @@ static bool submit_upstream_work(CURL *curl, const struct work *work) rc = true; out: - free(hexstr); return rc; } @@ -411,21 +405,29 @@ static void workio_cmd_free(struct workio_cmd *wc) free(wc); } -static bool workio_get_work(struct workio_cmd *wc, CURL *curl) +static bool workio_get_work(struct workio_cmd *wc) { struct work *ret_work; int failures = 0; + bool ret = false; + CURL *curl; ret_work = calloc(1, sizeof(*ret_work)); if (!ret_work) - return false; + goto out; + + curl = curl_easy_init(); + if (unlikely(!curl)) { + applog(LOG_ERR, "CURL initialization failed"); + return ret; + } /* obtain new work from bitcoin via JSON-RPC */ while (!get_upstream_work(curl, ret_work)) { if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { applog(LOG_ERR, "json_rpc_call failed, terminating workio thread"); free(ret_work); - return false; + goto out; } /* pause, then restart work-request loop */ @@ -434,22 +436,33 @@ static bool workio_get_work(struct workio_cmd *wc, CURL *curl) sleep(opt_fail_pause); } + ret = true; /* send work to requesting thread */ if (!tq_push(wc->thr->q, ret_work)) free(ret_work); - return true; +out: + curl_easy_cleanup(curl); + return ret; } -static bool workio_submit_work(struct workio_cmd *wc, CURL *curl) +static void *submit_thread(void *userdata) { + char *hexstr = (char *)userdata; int failures = 0; + CURL *curl; + + curl = curl_easy_init(); + if (unlikely(!curl)) { + applog(LOG_ERR, "CURL initialization failed"); + return NULL; + } /* submit solution to bitcoin via JSON-RPC */ - while (!submit_upstream_work(curl, wc->u.work)) { + while (!submit_upstream_work(curl, hexstr)) { if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) { applog(LOG_ERR, "...terminating workio thread"); - return false; + exit (1); } /* pause, then restart work-request loop */ @@ -458,21 +471,43 @@ static bool workio_submit_work(struct workio_cmd *wc, CURL *curl) sleep(opt_fail_pause); } + free(hexstr); +out: + curl_easy_cleanup(curl); +} + +/* Work is submitted asynchronously by creating a thread for each submit + * thus avoiding the mining threads having to wait till work is submitted + * before they can continue working. */ +static bool workio_submit_work(struct workio_cmd *wc) +{ + struct work *work; + pthread_t thr; + char *hexstr; + pid_t child; + + work = wc->u.work; + + /* build hex string */ + hexstr = bin2hex(work->data, sizeof(work->data)); + if (unlikely(!hexstr)) { + applog(LOG_ERR, "workio_submit_work OOM"); + return false; + } + + if (pthread_create(&thr, NULL, submit_thread, (void *)hexstr)) { + applog(LOG_ERR, "Failed to create submit_thread"); + return false; + } + return true; } static void *workio_thread(void *userdata) { struct thr_info *mythr = userdata; - CURL *curl; bool ok = true; - curl = curl_easy_init(); - if (unlikely(!curl)) { - applog(LOG_ERR, "CURL initialization failed"); - return NULL; - } - while (ok) { struct workio_cmd *wc; @@ -486,10 +521,10 @@ static void *workio_thread(void *userdata) /* process workio_cmd */ switch (wc->cmd) { case WC_GET_WORK: - ok = workio_get_work(wc, curl); + ok = workio_get_work(wc); break; case WC_SUBMIT_WORK: - ok = workio_submit_work(wc, curl); + ok = workio_submit_work(wc); break; default: /* should never happen */ @@ -501,7 +536,6 @@ static void *workio_thread(void *userdata) } tq_freeze(mythr->q); - curl_easy_cleanup(curl); return NULL; }