Commit 8c0ea19e132c160e50fcb00ae43a7502bb90f380

Con Kolivas 2013-10-05T09:31:36

Submitting an ntime offset nonce needs to be done on a copy of the work instead of the original so abstract out shared components as much as possible, minimising strdups in copy_work and make submit_work_async work take copied work, cleaning up code in the process.

diff --git a/cgminer.c b/cgminer.c
index 5d0667d..650db80 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -3511,9 +3511,23 @@ static void *submit_work_thread(void __maybe_unused *userdata)
 }
 #endif /* HAVE_LIBCURL */
 
+/* Return an adjusted ntime if we're submitting work that a device has
+ * internally offset the ntime. */
+static char *offset_ntime(const char *ntime, int noffset)
+{
+	unsigned char bin[4];
+	uint32_t h32, *be32 = (uint32_t *)bin;
+
+	hex2bin(bin, ntime, 4);
+	h32 = be32toh(*be32) + noffset;
+	*be32 = htobe32(h32);
+
+	return bin2hex(bin, 4);
+}
+
 /* Duplicates any dynamically allocated arrays within the work struct to
  * prevent a copied work struct from freeing ram belonging to another struct */
-void __copy_work(struct work *work, struct work *base_work)
+static void _copy_work(struct work *work, const struct work *base_work, int noffset)
 {
 	int id = work->id;
 
@@ -3526,8 +3540,12 @@ void __copy_work(struct work *work, struct work *base_work)
 		work->job_id = strdup(base_work->job_id);
 	if (base_work->nonce1)
 		work->nonce1 = strdup(base_work->nonce1);
-	if (base_work->ntime)
-		work->ntime = strdup(base_work->ntime);
+	if (base_work->ntime) {
+		if (noffset)
+			work->ntime = offset_ntime(base_work->ntime, noffset);
+		else
+			work->ntime = strdup(base_work->ntime);
+	}
 	if (base_work->coinbase)
 		work->coinbase = strdup(base_work->coinbase);
 }
@@ -3538,7 +3556,7 @@ struct work *copy_work(struct work *base_work)
 {
 	struct work *work = make_work();
 
-	__copy_work(work, base_work);
+	_copy_work(work, base_work, 0);
 
 	return work;
 }
@@ -5972,14 +5990,13 @@ static struct work *get_work(struct thr_info *thr, const int thr_id)
 	return work;
 }
 
-static void submit_work_async(struct work *work_in, struct timeval *tv_work_found)
+/* Submit a copy of the tested, statistic recorded work item asynchronously */
+static void submit_work_async(struct work *work)
 {
-	struct work *work = copy_work(work_in);
 	struct pool *pool = work->pool;
 	pthread_t submit_thread;
 
-	if (tv_work_found)
-		copy_time(&work->tv_work_found, tv_work_found);
+	cgtime(&work->tv_work_found);
 
 	if (stale_work(work, true)) {
 		if (opt_submit_stale)
@@ -6018,6 +6035,9 @@ static void submit_work_async(struct work *work_in, struct timeval *tv_work_foun
 
 void inc_hw_errors(struct thr_info *thr)
 {
+	applog(LOG_INFO, "%s%d: invalid nonce - HW error", thr->cgpu->drv->name,
+	       thr->cgpu->device_id);
+
 	mutex_lock(&stats_lock);
 	hw_errors++;
 	thr->cgpu->hw_errors++;
@@ -6042,12 +6062,8 @@ bool test_nonce(struct work *work, uint32_t nonce)
 	return (be32toh(hash2_32[7]) <= diff1targ);
 }
 
-/* To be used once the work has been tested to be meet diff1 and has had its
- * nonce adjusted. */
-void submit_tested_work(struct thr_info *thr, struct work *work)
+static void update_work_stats(struct thr_info *thr, struct work *work)
 {
-	struct timeval tv_work_found;
-
 	work->share_diff = share_diff(work);
 
 	mutex_lock(&stats_lock);
@@ -6056,50 +6072,63 @@ void submit_tested_work(struct thr_info *thr, struct work *work)
 	work->pool->diff1 += work->device_diff;
 	thr->cgpu->last_device_valid_work = time(NULL);
 	mutex_unlock(&stats_lock);
+}
+
+/* To be used once the work has been tested to be meet diff1 and has had its
+ * nonce adjusted. */
+void submit_tested_work(struct thr_info *thr, struct work *work)
+{
+	struct work *work_out;
+	update_work_stats(thr, work);
 
 	if (!fulltest(work->hash2, work->target)) {
 		applog(LOG_INFO, "Share below target");
 		return;
 	}
-
-	cgtime(&tv_work_found);
-	submit_work_async(work, &tv_work_found);
+	work_out = copy_work(work);
+	submit_work_async(work_out);
 }
 
 /* Returns true if nonce for work was a valid share */
 bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
 {
-	bool ret = true;
-
 	if (test_nonce(work, nonce))
 		submit_tested_work(thr, work);
 	else {
-		applog(LOG_INFO, "%s%d: invalid nonce - HW error",
-		       thr->cgpu->drv->name, thr->cgpu->device_id);
-
 		inc_hw_errors(thr);
-		ret = false;
+		return false;
 	}
 
-	return ret;
+	return true;
 }
 
 /* Allows drivers to submit work items where the driver has changed the ntime
  * value by noffset. Must be only used with a work protocol that does not ntime
- * roll itself intrinsically to generate work (eg stratum). */
-bool submit_noffset_nonce(struct thr_info *thr, struct work *work, uint32_t nonce,
+ * roll itself intrinsically to generate work (eg stratum). We do not touch
+ * the original work struct, but the copy of it only. */
+bool submit_noffset_nonce(struct thr_info *thr, struct work *work_in, uint32_t nonce,
 			  int noffset)
 {
-	unsigned char bin[4];
-	uint32_t h32, *be32 = (uint32_t *)bin;
+	struct work *work = make_work();
+	bool ret = false;
 
-	hex2bin(bin, work->ntime, 4);
-	h32 = be32toh(*be32) + noffset;
-	*be32 = htobe32(h32);
-	free(work->ntime);
-	work->ntime = bin2hex(bin, 4);
+	_copy_work(work, work_in, noffset);
+	if (!test_nonce(work, nonce)) {
+		inc_hw_errors(thr);
+		goto out;
+	}
+	ret = true;
+	update_work_stats(thr, work);
+	if (!fulltest(work->hash2, work->target)) {
+		applog(LOG_INFO, "Share below target");
+		goto  out;
+	}
+	submit_work_async(work);
 
-	return submit_nonce(thr, work, nonce);
+out:
+	if (!ret)
+		free_work(work);
+	return ret;
 }
 
 static inline bool abandon_work(struct work *work, struct timeval *wdiff, uint64_t hashes)
diff --git a/miner.h b/miner.h
index 9c49a35..87cb808 100644
--- a/miner.h
+++ b/miner.h
@@ -1419,7 +1419,6 @@ extern void adl(void);
 extern void app_restart(void);
 extern void clean_work(struct work *work);
 extern void free_work(struct work *work);
-extern void __copy_work(struct work *work, struct work *base_work);
 extern struct work *copy_work(struct work *base_work);
 extern struct thr_info *get_thread(int thr_id);
 extern struct cgpu_info *get_devices(int id);