Commit 2257b5023a96c60c1adcdd89c8adbf60aa484ac5

Con Kolivas 2011-12-27T11:37:30

Simplify longpoll changeover to just check which pool it should grab its next longpoll from. This should prevent locking hangs and thread cancellation crashes.

diff --git a/main.c b/main.c
index 0da6078..14509dd 100644
--- a/main.c
+++ b/main.c
@@ -2732,8 +2732,6 @@ static struct pool *priority_pool(int choice)
 	return ret;
 }
 
-static void restart_longpoll(void);
-
 static void switch_pools(struct pool *selected)
 {
 	struct pool *pool, *last_pool;
@@ -2786,12 +2784,8 @@ static void switch_pools(struct pool *selected)
 	pool = currentpool;
 	mutex_unlock(&control_lock);
 
-	if (pool != last_pool) {
+	if (pool != last_pool)
 		applog(LOG_WARNING, "Switching to %s", pool->rpc_url);
-		/* Only switch longpoll if the new pool also supports LP */
-		if (pool->hdr_path)
-			restart_longpoll();
-	}
 
 	/* Reset the queued amount to allow more to be queued for the new pool */
 	mutex_lock(&qd_lock);
@@ -3395,6 +3389,9 @@ retry:
 	opt_loginput = false;
 }
 
+static void start_longpoll(void);
+static void stop_longpoll(void);
+
 static void set_options(void)
 {
 	int selected;
@@ -3421,7 +3418,11 @@ retry:
 	} else if (!strncasecmp(&input, "l", 1)) {
 		want_longpoll ^= true;
 		applog(LOG_WARNING, "Longpoll %s", want_longpoll ? "enabled" : "disabled");
-		restart_longpoll();
+		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");
@@ -4898,12 +4899,15 @@ static struct pool *select_longpoll_pool(void)
 
 static void *longpoll_thread(void *userdata)
 {
-	struct thr_info *mythr = userdata;
-	CURL *curl = NULL;
 	char *copy_start, *hdr_path, *lp_url = NULL;
+	struct thr_info *mythr = userdata;
+	struct timeval start, end;
 	bool need_slash = false;
+	struct pool *sp, *pool;
+	CURL *curl = NULL;
 	int failures = 0;
-	struct pool *pool;
+	bool rolltime;
+	json_t *val;
 
 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 	pthread_detach(pthread_self());
@@ -4915,7 +4919,9 @@ static void *longpoll_thread(void *userdata)
 	}
 
 	tq_pop(mythr->q, NULL);
+
 	pool = select_longpoll_pool();
+new_longpoll:
 	if (!pool->hdr_path) {
 		applog(LOG_WARNING, "No long-poll found on any pool server");
 		goto out;
@@ -4926,15 +4932,13 @@ static void *longpoll_thread(void *userdata)
 	if (strstr(hdr_path, "://")) {
 		lp_url = hdr_path;
 		hdr_path = NULL;
-	}
-
-	/* absolute path, on current server */
-	else {
+	} else {
+		/* absolute path, on current server */
 		copy_start = (*hdr_path == '/') ? (hdr_path + 1) : hdr_path;
 		if (pool->rpc_url[strlen(pool->rpc_url) - 1] != '/')
 			need_slash = true;
 
-		lp_url = alloca(strlen(pool->rpc_url) + strlen(copy_start) + 2);
+		lp_url = malloc(strlen(pool->rpc_url) + strlen(copy_start) + 2);
 		if (!lp_url)
 			goto out;
 
@@ -4945,10 +4949,6 @@ static void *longpoll_thread(void *userdata)
 	applog(LOG_WARNING, "Long-polling activated for %s", lp_url);
 
 	while (1) {
-		struct timeval start, end;
-		bool rolltime;
-		json_t *val;
-
 		gettimeofday(&start, NULL);
 		val = json_rpc_call(curl, lp_url, pool->rpc_userpass, rpc_req,
 				    false, true, &rolltime, pool);
@@ -4965,26 +4965,28 @@ static void *longpoll_thread(void *userdata)
 			if (end.tv_sec - start.tv_sec > 30)
 				continue;
 			if (opt_retries == -1 || failures++ < opt_retries) {
-				sleep(30);
 				applog(LOG_WARNING,
 					"longpoll failed for %s, sleeping for 30s", lp_url);
+				sleep(30);
 			} else {
 				applog(LOG_ERR,
 					"longpoll failed for %s, ending thread", lp_url);
 				goto out;
 			}
 		}
+		sp = select_longpoll_pool();
+		if (sp != pool) {
+			if (likely(lp_url))
+				free(lp_url);
+			pool = sp;
+			goto new_longpoll;
+		}
 	}
 
 out:
 	if (curl)
 		curl_easy_cleanup(curl);
 
-	/* Wait indefinitely if longpoll is flagged as existing, thus making
-	 * this thread only die if killed from elsewhere, usually in
-	 * thr_info_cancel */
-	if (have_longpoll)
-		tq_pop(mythr->q, NULL);
 	tq_freeze(mythr->q);
 	return NULL;
 }
@@ -5010,14 +5012,6 @@ static void start_longpoll(void)
 	tq_push(thr_info[longpoll_thr_id].q, &ping);
 }
 
-static void restart_longpoll(void)
-{
-	if (have_longpoll)
-		stop_longpoll();
-	if (want_longpoll)
-		start_longpoll();
-}
-
 static void *reinit_cpu(void *userdata)
 {
 	pthread_detach(pthread_self());
diff --git a/miner.h b/miner.h
index 6101006..1a83158 100644
--- a/miner.h
+++ b/miner.h
@@ -453,7 +453,6 @@ extern int total_getworks, total_stale, total_discarded;
 extern unsigned int local_work;
 extern unsigned int total_go, total_ro;
 extern int opt_log_interval;
-extern pthread_mutex_t control_lock;
 
 #ifdef HAVE_OPENCL
 typedef struct {
diff --git a/util.c b/util.c
index f3287bc..3df1fb3 100644
--- a/util.c
+++ b/util.c
@@ -669,9 +669,7 @@ int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*start) (
 {
 	int ret;
 
-	mutex_lock(&control_lock);
 	ret = pthread_create(&thr->pth, attr, start, arg);
-	mutex_unlock(&control_lock);
 	return ret;
 }
 
@@ -683,14 +681,11 @@ void thr_info_cancel(struct thr_info *thr)
 	if (thr->q)
 		tq_freeze(thr->q);
 
-	/* control_lock protects thr->pth */
-	mutex_lock(&control_lock);
 	if (thr->pth) {
 			if (!pthread_cancel(thr->pth))
 				pthread_join(thr->pth, NULL);
 			thr->pth = 0L;
 	}
-	mutex_unlock(&control_lock);
 }
 
 bool get_dondata(char **url, char **userpass)