Make a separate thread for work submission that returns immediately so that miner threads aren't kept waiting when submitting results to slow pools.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
diff --git a/cpu-miner.c b/cpu-miner.c
index 3391feb..bc9ea8c 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;
}