Commit 42ea29ca4eb0bda94e18460ed00295a17c8dcc8b

Con Kolivas 2012-06-25T00:58:18

Use a queueing bool set under control_lock to prevent multiple calls to queue_request racing.

diff --git a/cgminer.c b/cgminer.c
index a3d22b0..a186ff1 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -2428,7 +2428,7 @@ static void subtract_queued(int work_units)
 	mutex_unlock(&qd_lock);
 }
 
-static int discard_stale(void)
+static void discard_stale(void)
 {
 	struct work *work, *tmp;
 	int stale = 0, nonclone = 0;
@@ -2451,21 +2451,18 @@ static int discard_stale(void)
 
 	/* Dec queued outside the loop to not have recursive locks */
 	subtract_queued(nonclone);
-
-	return stale;
 }
 
 static bool queue_request(struct thr_info *thr, bool needed);
 
 static void restart_threads(void)
 {
-	int i, stale;
+	int i;
 
 	/* Discard staged work that is now stale */
-	stale = discard_stale();
+	discard_stale();
 
-	for (i = 0; i < stale; i++)
-		queue_request(NULL, true);
+	queue_request(NULL, true);
 
 	for (i = 0; i < mining_threads; i++)
 		work_restart[i].restart = 1;
@@ -3527,12 +3524,41 @@ static void pool_resus(struct pool *pool)
 
 static time_t requested_tv_sec;
 
+static bool control_tset(bool *var)
+{
+	bool ret;
+
+	mutex_lock(&control_lock);
+	ret = *var;
+	*var = true;
+	mutex_unlock(&control_lock);
+
+	return ret;
+}
+
+static void control_tclear(bool *var)
+{
+	mutex_lock(&control_lock);
+	*var = false;
+	mutex_unlock(&control_lock);
+}
+
+static bool queueing;
+
 static bool queue_request(struct thr_info *thr, bool needed)
 {
-	int toq, rq = requests_queued(), rs = requests_staged();
 	struct workio_cmd *wc;
 	struct timeval now;
 	time_t scan_post;
+	int toq, rq, rs;
+	bool ret = true;
+
+	/* Prevent multiple requests being executed at once */
+	if (control_tset(&queueing))
+		return ret;
+
+	rq = requests_queued();
+	rs = requests_staged();
 
 	/* Grab more work every 2/3 of the scan time to avoid all work expiring
 	 * at the same time */
@@ -3547,7 +3573,7 @@ static bool queue_request(struct thr_info *thr, bool needed)
 	if ((rq >= mining_threads || rs >= mining_threads) &&
 	    rq > staged_extras + opt_queue &&
 	    now.tv_sec - requested_tv_sec < scan_post)
-		return true;
+		goto out;
 
 	requested_tv_sec = now.tv_sec;
 
@@ -3563,14 +3589,12 @@ static bool queue_request(struct thr_info *thr, bool needed)
 		wc = calloc(1, sizeof(*wc));
 		if (unlikely(!wc)) {
 			applog(LOG_ERR, "Failed to calloc wc in queue_request");
-			return false;
+			ret = false;
+			break;
 		}
 
 		wc->cmd = WC_GET_WORK;
-		if (thr)
-			wc->thr = thr;
-		else
-			wc->thr = NULL;
+		wc->thr = thr;
 
 		/* If we're queueing work faster than we can stage it, consider the
 		 * system lagging and allow work to be gathered from another pool if
@@ -3584,12 +3608,16 @@ static bool queue_request(struct thr_info *thr, bool needed)
 		if (unlikely(!tq_push(thr_info[work_thr_id].q, wc))) {
 			applog(LOG_ERR, "Failed to tq_push in queue_request");
 			workio_cmd_free(wc);
-			return false;
+			ret = false;
+			break;
 		}
 
 	} while (--toq > 0);
 
-	return true;
+out:
+	control_tclear(&queueing);
+
+	return ret;
 }
 
 static struct work *hash_pop(const struct timespec *abstime)