Commit b7a177532dd53523a7f50429875d615bc7bdb83a

Con Kolivas 2011-06-25T09:56:37

Make a separate thread for work submission that returns immediately so that miner threads aren't kept waiting when submitting results to slow pools.

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;
 }