If work has been cloned it is already at the head of the list and when being reinserted into the queue it should be placed back at the head of the list.
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
diff --git a/main.c b/main.c
index 139ce46..3f87c34 100644
--- a/main.c
+++ b/main.c
@@ -1478,7 +1478,16 @@ static void *stage_thread(void *userdata)
if (!work->cloned && !work->clone)
gettimeofday(&work->tv_staged, NULL);
- if (unlikely(!tq_push(getq, work))) {
+ /* If the work is cloned it has already gone to get_work once
+ * so it must be used ASAP before it goes stale so put it at
+ * the head of the list */
+ if (work->cloned) {
+ if (unlikely(!tq_push_head(getq, work))) {
+ applog(LOG_ERR, "Failed to tq_push work in stage_thread");
+ ok = false;
+ break;
+ }
+ } else if (unlikely(!tq_push(getq, work))) {
applog(LOG_ERR, "Failed to tq_push work in stage_thread");
ok = false;
break;
diff --git a/miner.h b/miner.h
index 0b6eacb..53e2069 100644
--- a/miner.h
+++ b/miner.h
@@ -346,6 +346,7 @@ extern void vapplog(int prio, const char *fmt, va_list ap);
extern void applog(int prio, const char *fmt, ...);
extern struct thread_q *tq_new(void);
extern void tq_free(struct thread_q *tq);
+extern bool tq_push_head(struct thread_q *tq, void *data);
extern bool tq_push(struct thread_q *tq, void *data);
extern void *tq_pop(struct thread_q *tq, const struct timespec *abstime);
extern void tq_freeze(struct thread_q *tq);
diff --git a/util.c b/util.c
index f726b4a..1b2295e 100644
--- a/util.c
+++ b/util.c
@@ -618,6 +618,33 @@ void tq_thaw(struct thread_q *tq)
tq_freezethaw(tq, false);
}
+bool tq_push_head(struct thread_q *tq, void *data)
+{
+ struct tq_ent *ent;
+ bool rc = true;
+
+ ent = calloc(1, sizeof(*ent));
+ if (!ent)
+ return false;
+
+ ent->data = data;
+ INIT_LIST_HEAD(&ent->q_node);
+
+ mutex_lock(&tq->mutex);
+
+ if (!tq->frozen) {
+ list_add(&ent->q_node, &tq->q);
+ } else {
+ free(ent);
+ rc = false;
+ }
+
+ pthread_cond_signal(&tq->cond);
+ mutex_unlock(&tq->mutex);
+
+ return rc;
+}
+
bool tq_push(struct thread_q *tq, void *data)
{
struct tq_ent *ent;