Browse Source

Merge branch 'cg_merges_20130818a' into bfgminer

Conflicts:
	README.ASIC
Luke Dashjr 12 years ago
parent
commit
d316f7b14a
17 changed files with 458 additions and 248 deletions
  1. 9 0
      README.ASIC
  2. 4 0
      README.RPC
  3. 35 2
      api-example.py
  4. 1 2
      driver-avalon.c
  5. 2 3
      driver-bitforce.c
  6. 0 1
      driver-icarus.c
  7. 3 5
      driver-modminer.c
  8. 37 27
      driver-opencl.c
  9. 3 3
      driver-x6500.c
  10. 0 2
      driver-ztex.c
  11. 2 2
      logging.c
  12. 22 0
      logging.h
  13. 211 155
      miner.c
  14. 53 13
      miner.h
  15. 23 0
      miner.php
  16. 43 33
      util.c
  17. 10 0
      util.h

+ 9 - 0
README.ASIC

@@ -78,6 +78,15 @@ with a unique username per blade. It will then show up as a SGW device and
 should work more or less like any other miner.
 
 
+BLOCK ERUPTER USB
+-----------------
+
+These will autodetect if supported by the device; otherwise, you need to use
+the '--scan-serial erupter:*' option to tell BFGMiner what device to probe. They
+communicate with the Icarus protocol, which has some additional options in
+README.FPGA
+
+
 ---
 
 This code is provided entirely free of charge by the programmer in his spare

+ 4 - 0
README.RPC

@@ -430,7 +430,11 @@ Feature Changelog for external applications using the API:
 API V1.25.3
 
 Modified API commands:
+ 'devs', 'pga', 'gpu' - add 'Device Hardware%' and 'Device Rejected%'
+ 'pools' - add 'Pool Rejected%' and 'Pool Stale%'
  'setconfig' - add 'http-port' number
+ 'summary' - add 'Device Hardware%', 'Device Rejected%', 'Pool Rejected%',
+                 'Pool Stale%'
 
 Removed output limitation:
  All replies can now be longer than the previous limitation of 64k, and will

+ 35 - 2
api-example.py

@@ -60,7 +60,7 @@ static const char SEPARATOR = '|';
 #define SEPSTR "|"
 static const char GPUSEP = ',';
 
-static const char *APIVERSION = "1.25";
+static const char *APIVERSION = "1.25.3";
 static const char *DEAD = "Dead";
 static const char *SICK = "Sick";
 static const char *NOSTART = "NoStart";
@@ -450,7 +450,7 @@ struct CODES {
  { SEVERITY_ERR,   MSG_MISVAL,	PARAM_NONE,	"Missing comma after GPU number" },
  { SEVERITY_ERR,   MSG_NOADL,	PARAM_NONE,	"ADL is not available" },
  { SEVERITY_ERR,   MSG_NOGPUADL,PARAM_GPU,	"GPU %d does not have ADL" },
- { SEVERITY_ERR,   MSG_INVINT,	PARAM_STR,	"Invalid intensity (%s) - must be '" _DYNAMIC  "' or range " _MIN_INTENSITY_STR " - " _MAX_INTENSITY_STR },
+ { SEVERITY_ERR,   MSG_INVINT,	PARAM_STR,	"Invalid intensity (%s) - must be '" _DYNAMIC  "' or range " MIN_SHA_INTENSITY_STR " - " MAX_SCRYPT_INTENSITY_STR },
  { SEVERITY_INFO,  MSG_GPUINT,	PARAM_BOTH,	"GPU %d set new intensity to %s" },
  { SEVERITY_SUCC,  MSG_MINECONFIG,PARAM_NONE,	"BFGMiner config" },
 #ifdef HAVE_OPENCL
@@ -814,6 +814,7 @@ static struct api_data *api_add_data_full(struct api_data *root, char *name, enu
 			case API_FREQ:
 			case API_HS:
 			case API_DIFF:
+			case API_PERCENT:
 				api_data->data = (void *)malloc(sizeof(double));
 				*((double *)(api_data->data)) = *((double *)data);
 				break;
@@ -954,6 +955,11 @@ struct api_data *api_add_json(struct api_data *root, char *name, json_t *data, b
 	return api_add_data_full(root, name, API_JSON, (void *)data, copy_data);
 }
 
+struct api_data *api_add_percent(struct api_data *root, char *name, double *data, bool copy_data)
+{
+	return api_add_data_full(root, name, API_PERCENT, (void *)data, copy_data);
+}
+
 static struct api_data *print_data(struct api_data *root, char *buf, bool isjson, bool precom)
 {
 	struct api_data *tmp;
@@ -1051,6 +1057,9 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
 				strcpy(buf, escape);
 				free(escape);
 				break;
+			case API_PERCENT:
+				sprintf(buf, "%.4f", *((double *)(root->data)) * 100.0);
+				break;
 			default:
 				applog(LOG_ERR, "API: unknown2 data type %d ignored", root->type);
 				sprintf(buf, "%s%s%s", quote, UNKNOWN, quote);
@@ -1475,6 +1484,12 @@ static void devstatus_an(struct io_data *io_data, struct cgpu_info *cgpu, bool i
 	root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false);
 	root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false);
 	root = api_add_time(root, "Last Valid Work", &(cgpu->last_device_valid_work), false);
+	double hwp = (cgpu->hw_errors + cgpu->diff1) ?
+			(double)(cgpu->hw_errors) / (double)(cgpu->hw_errors + cgpu->diff1) : 0;
+	root = api_add_percent(root, "Device Hardware%", &hwp, false);
+	double rejp = cgpu->diff1 ?
+			(double)(cgpu->diff_rejected) / (double)(cgpu->diff1) : 0;
+	root = api_add_percent(root, "Device Rejected%", &rejp, false);
 
 	if (cgpu->drv->get_api_extra_device_status)
 		root = api_add_extra(root, cgpu->drv->get_api_extra_device_status(cgpu));
@@ -1884,6 +1899,12 @@ static void poolstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m
 		root = api_add_uint64(root, "Best Share", &(pool->best_diff), true);
 		if (pool->admin_msg)
 			root = api_add_escape(root, "Message", pool->admin_msg, true);
+		double rejp = (pool->diff_accepted + pool->diff_rejected + pool->diff_stale) ?
+				(double)(pool->diff_rejected) / (double)(pool->diff_accepted + pool->diff_rejected + pool->diff_stale) : 0;
+		root = api_add_percent(root, "Pool Rejected%", &rejp, false);
+		double stalep = (pool->diff_accepted + pool->diff_rejected + pool->diff_stale) ?
+				(double)(pool->diff_stale) / (double)(pool->diff_accepted + pool->diff_rejected + pool->diff_stale) : 0;
+		root = api_add_percent(root, "Pool Stale%", &stalep, false);
 
 		root = print_data(root, buf, isjson, isjson && (i > 0));
 		io_add(io_data, buf);
@@ -1940,6 +1961,18 @@ static void summary(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __mayb
 	root = api_add_diff(root, "Difficulty Rejected", &(total_diff_rejected), true);
 	root = api_add_diff(root, "Difficulty Stale", &(total_diff_stale), true);
 	root = api_add_uint64(root, "Best Share", &(best_diff), true);
+	double hwp = (hw_errors + total_diff1) ?
+			(double)(hw_errors) / (double)(hw_errors + total_diff1) : 0;
+	root = api_add_percent(root, "Device Hardware%", &hwp, false);
+	double rejp = total_diff1 ?
+			(double)(total_diff_rejected) / (double)(total_diff1) : 0;
+	root = api_add_percent(root, "Device Rejected%", &rejp, false);
+	double prejp = (total_diff_accepted + total_diff_rejected + total_diff_stale) ?
+			(double)(total_diff_rejected) / (double)(total_diff_accepted + total_diff_rejected + total_diff_stale) : 0;
+	root = api_add_percent(root, "Pool Rejected%", &prejp, false);
+	double stalep = (total_diff_accepted + total_diff_rejected + total_diff_stale) ?
+			(double)(total_diff_stale) / (double)(total_diff_accepted + total_diff_rejected + total_diff_stale) : 0;
+	root = api_add_percent(root, "Pool Stale%", &stalep, false);
 
 	mutex_unlock(&hash_lock);
 

+ 1 - 2
driver-avalon.c

@@ -667,13 +667,12 @@ static bool avalon_prepare(struct thr_info *thr)
 	avalon->works = calloc(info->miner_count * sizeof(struct work *),
 			       AVALON_ARRAY_SIZE);
 	if (!avalon->works)
-		quit(1, "Failed to calloc avalon works in avalon_prepare");
+		quithere(1, "Failed to calloc avalon works");
 	if (avalon->device_fd == -1)
 		avalon_init(avalon);
 	else
 		__avalon_init(avalon);
 
-	get_now_datestamp(avalon->init);
 	avalon->status = LIFE_INIT2;
 	return true;
 }

+ 2 - 3
driver-bitforce.c

@@ -370,7 +370,6 @@ static bool bitforce_thread_prepare(struct thr_info *thr)
 	bitforce->device_fd = fdDev;
 
 	applog(LOG_INFO, "%s: Opened %s", bitforce->dev_repr, bitforce->device_path);
-	get_now_datestamp(bitforce->init);
 
 	return true;
 }
@@ -697,9 +696,9 @@ bool bitforce_job_prepare(struct thr_info *thr, struct work *work, __maybe_unuse
 	switch (data->proto)
 	{
 		case BFP_BQUEUE:
-			quit(1, "%"PRIpreprv": Impossible BFP_BQUEUE in bitforce_job_prepare", bitforce->proc_repr);
+			quithere(1, "%"PRIpreprv": Impossible BFP_BQUEUE", bitforce->proc_repr);
 		case BFP_PQUEUE:
-			quit(1, "%"PRIpreprv": Impossible BFP_PQUEUE in bitforce_job_prepare", bitforce->proc_repr);
+			quithere(1, "%"PRIpreprv": Impossible BFP_PQUEUE", bitforce->proc_repr);
 		case BFP_RANGE:
 		{
 			uint32_t *ob_nonce = (uint32_t*)&(ob_dt[32]);

+ 0 - 1
driver-icarus.c

@@ -657,7 +657,6 @@ static bool icarus_prepare(struct thr_info *thr)
 	icarus->device_fd = fd;
 
 	applog(LOG_INFO, "Opened Icarus on %s", icarus->device_path);
-	get_now_datestamp(icarus->init);
 
 	struct icarus_state *state;
 	thr->cgpu_data = state = calloc(1, sizeof(*state));

+ 3 - 5
driver-modminer.c

@@ -276,8 +276,6 @@ modminer_device_prepare(struct cgpu_info *modminer)
 	modminer->device->device_fd = fd;
 	applog(LOG_INFO, "%s: Opened %s", modminer->dev_repr, modminer->device_path);
 
-	get_now_datestamp(modminer->init);
-
 	return true;
 }
 
@@ -454,11 +452,11 @@ modminer_fpga_init(struct thr_info *thr)
 }
 
 static
-bool get_modminer_upload_percent(char *buf, struct cgpu_info *modminer, __maybe_unused bool per_processor)
+bool get_modminer_upload_percent(char *buf, size_t bufsz, struct cgpu_info *modminer, __maybe_unused bool per_processor)
 {
 	char pdone = ((struct modminer_fpga_state*)(modminer->device->thr[0]->cgpu_data))->pdone;
 	if (pdone != 101) {
-		tailsprintf(buf, "%3d%% ", pdone);
+		tailsprintf(buf, bufsz, "%3d%% ", pdone);
 		return true;
 	}
 	return false;
@@ -843,7 +841,7 @@ struct device_drv modminer_drv = {
 	.dname = "modminer",
 	.name = "MMQ",
 	.drv_detect = modminer_detect,
-	.override_statline_temp = get_modminer_upload_percent,
+	.override_statline_temp2 = get_modminer_upload_percent,
 	.get_stats = modminer_get_stats,
 	.get_api_extra_device_status = get_modminer_drv_extra_device_status,
 	.set_device = modminer_set_device,

+ 37 - 27
driver-opencl.c

@@ -751,7 +751,7 @@ char *set_intensity(char *arg)
 	else {
 		gpus[device].dynamic = false;
 		val = atoi(nextptr);
-		if (val < MIN_INTENSITY || val > MAX_INTENSITY)
+		if (val < MIN_INTENSITY || val > MAX_GPU_INTENSITY)
 			return "Invalid value passed to set intensity";
 		tt = &gpus[device].intensity;
 		*tt = val;
@@ -765,7 +765,7 @@ char *set_intensity(char *arg)
 		else {
 			gpus[device].dynamic = false;
 			val = atoi(nextptr);
-			if (val < MIN_INTENSITY || val > MAX_INTENSITY)
+			if (val < MIN_INTENSITY || val > MAX_GPU_INTENSITY)
 				return "Invalid value passed to set intensity";
 
 			tt = &gpus[device].intensity;
@@ -846,7 +846,7 @@ void opencl_wlogprint_status(struct cgpu_info *cgpu)
 	char logline[255];
 	strcpy(logline, ""); // In case it has no data
 	
-	tailsprintf(logline, "I:%s%d  ", (cgpu->dynamic ? "d" : ""), cgpu->intensity);
+	tailsprintf(logline, sizeof(logline), "I:%s%d  ", (cgpu->dynamic ? "d" : ""), cgpu->intensity);
 #ifdef HAVE_ADL
 	if (cgpu->has_adl) {
 		int engineclock = 0, memclock = 0, activity = 0, fanspeed = 0, fanpercent = 0, powertune = 0;
@@ -854,27 +854,29 @@ void opencl_wlogprint_status(struct cgpu_info *cgpu)
 
 		if (gpu_stats(cgpu->device_id, &temp, &engineclock, &memclock, &vddc, &activity, &fanspeed, &fanpercent, &powertune)) {
 			if (fanspeed != -1 || fanpercent != -1) {
-				tailsprintf(logline, "F: ");
+				tailsprintf(logline, sizeof(logline), "F: ");
+				if (fanspeed > 9999)
+					fanspeed = 9999;
 				if (fanpercent != -1)
 				{
-					tailsprintf(logline, "%d%% ", fanpercent);
+					tailsprintf(logline, sizeof(logline), "%d%% ", fanpercent);
 					if (fanspeed != -1)
-						tailsprintf(logline, "(%d RPM) ", fanspeed);
+						tailsprintf(logline, sizeof(logline), "(%d RPM) ", fanspeed);
 				}
 				else
-					tailsprintf(logline, "%d RPM ", fanspeed);
-				tailsprintf(logline, " ");
+					tailsprintf(logline, sizeof(logline), "%d RPM ", fanspeed);
+				tailsprintf(logline, sizeof(logline), " ");
 			}
 			if (engineclock != -1)
-				tailsprintf(logline, "E: %d MHz  ", engineclock);
+				tailsprintf(logline, sizeof(logline), "E: %d MHz  ", engineclock);
 			if (memclock != -1)
-				tailsprintf(logline, "M: %d MHz  ", memclock);
+				tailsprintf(logline, sizeof(logline), "M: %d MHz  ", memclock);
 			if (vddc != -1)
-				tailsprintf(logline, "V: %.3fV  ", vddc);
+				tailsprintf(logline, sizeof(logline), "V: %.3fV  ", vddc);
 			if (activity != -1)
-				tailsprintf(logline, "A: %d%%  ", activity);
+				tailsprintf(logline, sizeof(logline), "A: %d%%  ", activity);
 			if (powertune != -1)
-				tailsprintf(logline, "P: %d%%", powertune);
+				tailsprintf(logline, sizeof(logline), "P: %d%%", powertune);
 		}
 	}
 #endif
@@ -888,29 +890,29 @@ void opencl_wlogprint_status(struct cgpu_info *cgpu)
 		if (thr->cgpu != cgpu)
 			continue;
 		
-		get_datestamp(checkin, time(NULL) - timer_elapsed(&thr->last, NULL));
+		get_datestamp(checkin, sizeof(checkin), time(NULL) - timer_elapsed(&thr->last, NULL));
 		displayed_rolling = thr->rolling;
 		if (!mhash_base)
 			displayed_rolling *= 1000;
-		sprintf(logline, "Thread %d: %.1f %sh/s %s ", i, displayed_rolling, mhash_base ? "M" : "K" , cgpu->deven != DEV_DISABLED ? "Enabled" : "Disabled");
+		snprintf(logline, sizeof(logline), "Thread %d: %.1f %sh/s %s ", i, displayed_rolling, mhash_base ? "M" : "K" , cgpu->deven != DEV_DISABLED ? "Enabled" : "Disabled");
 		switch (cgpu->status) {
 			default:
 			case LIFE_WELL:
-				tailsprintf(logline, "ALIVE");
+				tailsprintf(logline, sizeof(logline), "ALIVE");
 				break;
 			case LIFE_SICK:
-				tailsprintf(logline, "SICK reported in %s", checkin);
+				tailsprintf(logline, sizeof(logline), "SICK reported in %s", checkin);
 				break;
 			case LIFE_DEAD:
-				tailsprintf(logline, "DEAD reported in %s", checkin);
+				tailsprintf(logline, sizeof(logline), "DEAD reported in %s", checkin);
 				break;
 			case LIFE_INIT:
 			case LIFE_NOSTART:
-				tailsprintf(logline, "Never started");
+				tailsprintf(logline, sizeof(logline), "Never started");
 				break;
 		}
 		if (thr->pause)
-			tailsprintf(logline, " paused");
+			tailsprintf(logline, sizeof(logline), " paused");
 		wlogprint("%s\n", logline);
 	}
 }
@@ -935,7 +937,15 @@ const char *opencl_tui_handle_choice(struct cgpu_info *cgpu, int input)
 			int intensity;
 			char *intvar;
 
-			intvar = curses_input("Set GPU scan intensity (d or " _MIN_INTENSITY_STR " -> " _MAX_INTENSITY_STR ")");
+			if (opt_scrypt) {
+				intvar = curses_input("Set GPU scan intensity (d or "
+						      MIN_SCRYPT_INTENSITY_STR " -> "
+						      MAX_SCRYPT_INTENSITY_STR ")");
+			} else {
+				intvar = curses_input("Set GPU scan intensity (d or "
+						      MIN_SHA_INTENSITY_STR " -> "
+						      MAX_SHA_INTENSITY_STR ")");
+			}
 			if (!intvar)
 				return "Invalid intensity\n";
 			if (!strncasecmp(intvar, "d", 1)) {
@@ -961,7 +971,7 @@ const char *opencl_tui_handle_choice(struct cgpu_info *cgpu, int input)
 			char logline[256];
 			
 			clear_logwin();
-			get_statline3(logline, cgpu, true, true);
+			get_statline3(logline, sizeof(logline), cgpu, true, true);
 			wattron(logwin, A_BOLD);
 			wlogprint("%s", logline);
 			wattroff(logwin, A_BOLD);
@@ -1296,7 +1306,7 @@ select_cgpu:
 
 		thr->q = tq_new();
 		if (!thr->q)
-			quit(1, "Failed to tq_new in reinit_gpu");
+			quithere(1, "Failed to tq_new");
 
 		/* Lose this ram cause we may dereference in the dying thread! */
 		//free(clState);
@@ -1316,7 +1326,7 @@ select_cgpu:
 		applog(LOG_WARNING, "Thread %d restarted", thr_id);
 	}
 
-	get_now_datestamp(sel_cgpu->init);
+	get_now_datestamp(sel_cgpu->init, sizeof(sel_cgpu->init));
 
 	proc_enable(cgpu);
 
@@ -1424,7 +1434,7 @@ static void reinit_opencl_device(struct cgpu_info *gpu)
 
 // FIXME: Legacy (called by TUI) for side effects
 static
-bool override_opencl_statline_temp(char *buf, struct cgpu_info *gpu, __maybe_unused bool per_processor)
+bool override_opencl_statline_temp(char *buf, size_t bufsz, struct cgpu_info *gpu, __maybe_unused bool per_processor)
 {
 #ifdef HAVE_SENSORS
 	struct opencl_device_data *data = gpu->device_data;
@@ -1568,7 +1578,7 @@ static bool opencl_thread_prepare(struct thr_info *thr)
 		}
 	}
 	applog(LOG_INFO, "initCl() finished. Found %s", name);
-	get_now_datestamp(cgpu->init);
+	get_now_datestamp(cgpu->init, sizeof(cgpu->init));
 
 	have_opencl = true;
 
@@ -1757,7 +1767,7 @@ struct device_drv opencl_api = {
 	.name = "OCL",
 	.drv_detect = opencl_detect,
 	.reinit_device = reinit_opencl_device,
-	.override_statline_temp = override_opencl_statline_temp,
+	.override_statline_temp2 = override_opencl_statline_temp,
 #ifdef HAVE_CURSES
 	.proc_wlogprint_status = opencl_wlogprint_status,
 	.proc_tui_wlogprint_choices = opencl_tui_wlogprint_choices,

+ 3 - 3
driver-x6500.c

@@ -552,11 +552,11 @@ static bool x6500_get_stats(struct cgpu_info *x6500)
 }
 
 static
-bool get_x6500_upload_percent(char *buf, struct cgpu_info *x6500, __maybe_unused bool per_processor)
+bool get_x6500_upload_percent(char *buf, size_t bufsz, struct cgpu_info *x6500, __maybe_unused bool per_processor)
 {
 	unsigned char pdone = *((unsigned char*)x6500->device_data - 1);
 	if (pdone != 101) {
-		tailsprintf(buf, "%3d%% ", pdone);
+		tailsprintf(buf, bufsz, "%3d%% ", pdone);
 		return true;
 	}
 	return false;
@@ -822,7 +822,7 @@ struct device_drv x6500_api = {
 	.thread_prepare = x6500_prepare,
 	.thread_init = x6500_thread_init,
 	.get_stats = x6500_get_stats,
-	.override_statline_temp = get_x6500_upload_percent,
+	.override_statline_temp2 = get_x6500_upload_percent,
 	.get_api_extra_device_status = get_x6500_api_extra_device_status,
 	.set_device = x6500_set_device,
 #ifdef HAVE_CURSES

+ 0 - 2
driver-ztex.c

@@ -342,8 +342,6 @@ static bool ztex_prepare(struct thr_info *thr)
 	struct cgpu_info *cgpu = thr->cgpu;
 	struct libztex_device *ztex = cgpu->device_ztex;
 
-	get_now_datestamp(cgpu->init);
-	
 	{
 		char *fpganame = malloc(LIBZTEX_SNSTRING_LEN+3+1);
 		sprintf(fpganame, "%s-%u", ztex->snString, cgpu->proc_id+1);

+ 2 - 2
logging.c

@@ -69,7 +69,7 @@ void _applog(int prio, const char *str)
 			bfg_gettimeofday(&tv);
 			localtime_r(&tv.tv_sec, &tm);
 			
-			sprintf(datetime, "[%d-%02d-%02d %02d:%02d:%02d.%06ld]",
+			snprintf(datetime, sizeof(datetime), "[%d-%02d-%02d %02d:%02d:%02d.%06ld]",
 				tm.tm_year + 1900,
 				tm.tm_mon + 1,
 				tm.tm_mday,
@@ -79,7 +79,7 @@ void _applog(int prio, const char *str)
 				(long)tv.tv_usec);
 		}
 		else
-			get_now_datestamp(datetime);
+			get_now_datestamp(datetime, sizeof(datetime));
 
 		if (writetofile || writetocon)
 		{

+ 22 - 0
logging.h

@@ -43,6 +43,8 @@ extern int opt_log_level;
 
 extern void _applog(int prio, const char *str);
 
+#define IN_FMT_FFL " in %s %s():%d"
+
 #define applog(prio, fmt, ...) do { \
 	if (opt_debug || prio != LOG_DEBUG) { \
 			char tmp42[LOGBUFSIZ]; \
@@ -68,6 +70,26 @@ extern void _bfg_clean_up(void);
 	_quit(status); \
 } while (0)
 
+#define quithere(status, fmt, ...) do { \
+	if (fmt) { \
+		char tmp42[LOGBUFSIZ]; \
+		snprintf(tmp42, sizeof(tmp42), fmt IN_FMT_FFL, \
+				##__VA_ARGS__, __FILE__, __func__, __LINE__); \
+		_applog(LOG_ERR, tmp42); \
+	} \
+	_quit(status); \
+} while (0)
+
+#define quitfrom(status, _file, _func, _line, fmt, ...) do { \
+	if (fmt) { \
+		char tmp42[LOGBUFSIZ]; \
+		snprintf(tmp42, sizeof(tmp42), fmt IN_FMT_FFL, \
+				##__VA_ARGS__, _file, _func, _line); \
+		_applog(LOG_ERR, tmp42); \
+	} \
+	_quit(status); \
+} while (0)
+
 #ifdef HAVE_CURSES
 
 #define wlog(fmt, ...) do { \

+ 211 - 155
miner.c

@@ -421,7 +421,7 @@ static bool should_run(void)
 	return within_range;
 }
 
-void get_datestamp(char *f, time_t tt)
+void get_datestamp(char *f, size_t fsiz, time_t tt)
 {
 	struct tm _tm;
 	struct tm *tm = &_tm;
@@ -430,7 +430,7 @@ void get_datestamp(char *f, time_t tt)
 		tt = time(NULL);
 
 	localtime_r(&tt, tm);
-	sprintf(f, "[%d-%02d-%02d %02d:%02d:%02d]",
+	snprintf(f, fsiz, "[%d-%02d-%02d %02d:%02d:%02d]",
 		tm->tm_year + 1900,
 		tm->tm_mon + 1,
 		tm->tm_mday,
@@ -439,13 +439,14 @@ void get_datestamp(char *f, time_t tt)
 		tm->tm_sec);
 }
 
-void get_timestamp(char *f, time_t tt)
+static
+void get_timestamp(char *f, size_t fsiz, time_t tt)
 {
 	struct tm _tm;
 	struct tm *tm = &_tm;
 
 	localtime_r(&tt, tm);
-	sprintf(f, "[%02d:%02d:%02d]",
+	snprintf(f, fsiz, "[%02d:%02d:%02d]",
 		tm->tm_hour,
 		tm->tm_min,
 		tm->tm_sec);
@@ -1507,10 +1508,18 @@ static struct opt_table opt_config_table[] = {
 	OPT_WITH_ARG("--lookup-gap",
 		     set_lookup_gap, NULL, NULL,
 		     "Set GPU lookup gap for scrypt mining, comma separated"),
-#endif
 	OPT_WITH_ARG("--intensity|-I",
 		     set_intensity, NULL, NULL,
-		     "Intensity of GPU scanning (d or " _MIN_INTENSITY_STR " -> " _MAX_INTENSITY_STR ", default: d to maintain desktop interactivity)"),
+		     "Intensity of GPU scanning (d or " MIN_SHA_INTENSITY_STR
+		     " -> " MAX_SCRYPT_INTENSITY_STR
+		     ",default: d to maintain desktop interactivity)"),
+#else
+	OPT_WITH_ARG("--intensity|-I",
+		     set_intensity, NULL, NULL,
+		     "Intensity of GPU scanning (d or " MIN_SHA_INTENSITY_STR
+		     " -> " MAX_SHA_INTENSITY_STR
+		     ",default: d to maintain desktop interactivity)"),
+#endif
 #endif
 #if defined(HAVE_OPENCL) || defined(USE_MODMINER) || defined(USE_X6500) || defined(USE_ZTEX)
 	OPT_WITH_ARG("--kernel-path|-K",
@@ -1851,7 +1860,7 @@ static char *parse_config(json_t *config, bool fileconf)
 					applog(LOG_ERR, "Invalid config option %s: %s", p, err);
 					fileconf_load = -1;
 				} else {
-					sprintf(err_buf, "Parsing JSON option %s: %s",
+					snprintf(err_buf, sizeof(err_buf), "Parsing JSON option %s: %s",
 						p, err);
 					return err_buf;
 				}
@@ -1874,6 +1883,7 @@ static char *load_config(const char *arg, void __maybe_unused *unused)
 	json_error_t err;
 	json_t *config;
 	char *json_error;
+	size_t siz;
 
 	if (!cnfbuf)
 		cnfbuf = strdup(arg);
@@ -1887,11 +1897,12 @@ static char *load_config(const char *arg, void __maybe_unused *unused)
 	config = json_load_file(arg, &err);
 #endif
 	if (!json_is_object(config)) {
-		json_error = malloc(JSON_LOAD_ERROR_LEN + strlen(arg) + strlen(err.text));
+		siz = JSON_LOAD_ERROR_LEN + strlen(arg) + strlen(err.text);
+		json_error = malloc(siz);
 		if (!json_error)
 			quit(1, "Malloc failure in json error");
 
-		sprintf(json_error, JSON_LOAD_ERROR, arg, err.text);
+		snprintf(json_error, siz, JSON_LOAD_ERROR, arg, err.text);
 		return json_error;
 	}
 
@@ -2083,7 +2094,8 @@ void __update_block_title(const unsigned char *hash_swap)
 		free(current_hash);
 		current_hash = malloc(3 /* ... */ + 16 /* block hash segment */ + 1);
 		bin2hex(tmp, &hash_swap[24], 8);
-		sprintf(current_hash, "...%s", tmp);
+		memset(current_hash, '.', 3);
+		memcpy(&current_hash[3], tmp, 17);
 		known_blkheight_current = false;
 	} else if (likely(known_blkheight_current)) {
 		return;
@@ -2092,7 +2104,7 @@ void __update_block_title(const unsigned char *hash_swap)
 		// FIXME: The block number will overflow this sometime around AD 2025-2027
 		if (known_blkheight < 1000000) {
 			memmove(&current_hash[3], &current_hash[11], 8);
-			sprintf(&current_hash[11], " #%6u", known_blkheight);
+			snprintf(&current_hash[11], 20-11, " #%6u", known_blkheight);
 		}
 		known_blkheight_current = true;
 	}
@@ -2291,24 +2303,15 @@ int dev_from_id(int thr_id)
 	return cgpu->device_id;
 }
 
-/* Make the change in the recent value adjust dynamically when the difference
- * is large, but damp it when the values are closer together. This allows the
- * value to change quickly, but not fluctuate too dramatically when it has
- * stabilised. */
-void decay_time(double *f, double fadd)
+/* Create an exponentially decaying average over the opt_log_interval */
+void decay_time(double *f, double fadd, double fsecs)
 {
-	double ratio = 0;
-
-	if (likely(*f > 0)) {
-		ratio = fadd / *f;
-		if (ratio > 1)
-			ratio = 1 / ratio;
-	}
+	double ftotal, fprop;
 
-	if (ratio > 0.63)
-		*f = (fadd * 0.58 + *f) / 1.58;
-	else
-		*f = (fadd + *f * 0.58) / 1.58;
+	fprop = 1.0 - 1 / (exp(fsecs / (double)opt_log_interval));
+	ftotal = 1.0 + fprop;
+	*f += (fadd * fprop);
+	*f /= ftotal;
 }
 
 static int __total_staged(void)
@@ -2382,12 +2385,13 @@ int my_cancellable_getch(void)
 }
 #endif
 
-void tailsprintf(char *f, const char *fmt, ...)
+void tailsprintf(char *buf, size_t bufsz, const char *fmt, ...)
 {
 	va_list ap;
-
+	size_t presz = strlen(buf);
+	
 	va_start(ap, fmt);
-	vsprintf(f + strlen(f), fmt, ap);
+	vsnprintf(&buf[presz], bufsz - presz, fmt, ap);
 	va_end(ap);
 }
 
@@ -2428,7 +2432,7 @@ double cgpu_utility(struct cgpu_info *cgpu)
 
 /* Convert a uint64_t value into a truncated string for displaying with its
  * associated suitable for Mega, Giga etc. Buf array needs to be long enough */
-static void suffix_string(uint64_t val, char *buf, int sigdigits)
+static void suffix_string(uint64_t val, char *buf, size_t bufsiz, int sigdigits)
 {
 	const double  dkilo = 1000.0;
 	const uint64_t kilo = 1000ull;
@@ -2444,26 +2448,26 @@ static void suffix_string(uint64_t val, char *buf, int sigdigits)
 	if (val >= exa) {
 		val /= peta;
 		dval = (double)val / dkilo;
-		sprintf(suffix, "E");
+		strcpy(suffix, "E");
 	} else if (val >= peta) {
 		val /= tera;
 		dval = (double)val / dkilo;
-		sprintf(suffix, "P");
+		strcpy(suffix, "P");
 	} else if (val >= tera) {
 		val /= giga;
 		dval = (double)val / dkilo;
-		sprintf(suffix, "T");
+		strcpy(suffix, "T");
 	} else if (val >= giga) {
 		val /= mega;
 		dval = (double)val / dkilo;
-		sprintf(suffix, "G");
+		strcpy(suffix, "G");
 	} else if (val >= mega) {
 		val /= kilo;
 		dval = (double)val / dkilo;
-		sprintf(suffix, "M");
+		strcpy(suffix, "M");
 	} else if (val >= kilo) {
 		dval = (double)val / dkilo;
-		sprintf(suffix, "k");
+		strcpy(suffix, "k");
 	} else {
 		dval = val;
 		decimal = false;
@@ -2471,15 +2475,15 @@ static void suffix_string(uint64_t val, char *buf, int sigdigits)
 
 	if (!sigdigits) {
 		if (decimal)
-			sprintf(buf, "%.3g%s", dval, suffix);
+			snprintf(buf, bufsiz, "%.3g%s", dval, suffix);
 		else
-			sprintf(buf, "%d%s", (unsigned int)dval, suffix);
+			snprintf(buf, bufsiz, "%d%s", (unsigned int)dval, suffix);
 	} else {
 		/* Always show sigdigits + 1, padded on right with zeroes
 		 * followed by suffix */
 		int ndigits = sigdigits - 1 - (dval > 0.0 ? floor(log10(dval)) : 0);
 
-		sprintf(buf, "%*.*f%s", sigdigits + 1, ndigits, dval, suffix);
+		snprintf(buf, bufsiz, "%*.*f%s", sigdigits + 1, ndigits, dval, suffix);
 	}
 }
 
@@ -2514,9 +2518,12 @@ enum h2bs_fmt {
 static const size_t h2bs_fmt_size[] = {6, 10, 11};
 
 static
-char *format_unit(char *buf, bool floatprec, const char *measurement, enum h2bs_fmt fmt, float hashrate, signed char unitin)
+int format_unit2(char *buf, size_t sz, bool floatprec, const char *measurement, enum h2bs_fmt fmt, float hashrate, signed char unitin)
 {
+	char *s = buf;
 	unsigned char prec, i, unit;
+	int rv = 0;
+	
 	if (unitin == -1)
 	{
 		unit = 0;
@@ -2534,35 +2541,31 @@ char *format_unit(char *buf, bool floatprec, const char *measurement, enum h2bs_
 			prec = 1;
 		else
 			prec = 2;
-		sprintf(buf, "%5.*f", prec, hashrate);
-		i = 5;
+		_SNP("%5.*f", prec, hashrate);
 	}
 	else
-	{
-		sprintf(buf, "%3d", (int)hashrate);
-		i = 3;
-	}
+		_SNP("%3d", (int)hashrate);
 	
 	switch (fmt) {
 	case H2B_SPACED:
-		buf[i++] = ' ';
+		_SNP(" ");
 	case H2B_SHORT:
-		buf[i++] = _unitchar[unit];
-		strcpy(&buf[i], measurement);
+		_SNP("%c%s", _unitchar[unit], measurement);
 	default:
 		break;
 	}
 	
-	return buf;
+	return rv;
 }
 
 static
-char *_multi_format_unit(char **buflist, bool floatprec, const char *measurement, enum h2bs_fmt fmt, const char *delim, int count, const float *numbers, bool isarray)
+char *_multi_format_unit(char **buflist, size_t *bufszlist, bool floatprec, const char *measurement, enum h2bs_fmt fmt, const char *delim, int count, const float *numbers, bool isarray)
 {
 	unsigned char unit = 0;
 	int i;
 	size_t delimsz;
 	char *buf = buflist[0];
+	size_t bufsz = bufszlist[0];
 	size_t itemwidth = (floatprec ? 5 : 3);
 	
 	if (!isarray)
@@ -2574,43 +2577,59 @@ char *_multi_format_unit(char **buflist, bool floatprec, const char *measurement
 	--count;
 	for (i = 0; i < count; ++i)
 	{
-		format_unit(buf, floatprec, NULL, H2B_NOUNIT, numbers[i], unit);
+		format_unit2(buf, bufsz, floatprec, NULL, H2B_NOUNIT, numbers[i], unit);
 		if (isarray)
+		{
 			buf = buflist[i + 1];
+			bufsz = bufszlist[i + 1];
+		}
 		else
 		{
 			buf += itemwidth;
+			bufsz -= itemwidth;
+			if (delimsz > bufsz)
+				delimsz = bufsz;
 			memcpy(buf, delim, delimsz);
 			buf += delimsz;
+			bufsz -= delimsz;
 		}
 	}
 	
 	// Last entry has the unit
-	format_unit(buf, floatprec, measurement, fmt, numbers[count], unit);
+	format_unit2(buf, bufsz, floatprec, measurement, fmt, numbers[count], unit);
 	
 	return buflist[0];
 }
-#define multi_format_unit(buf, floatprec, measurement, fmt, delim, count, ...)  _multi_format_unit((char *[]){buf}, floatprec, measurement, fmt, delim, count, (float[]){ __VA_ARGS__ }, false)
-#define multi_format_unit_array(buflist, floatprec, measurement, fmt, count, ...)  (void)_multi_format_unit(buflist, floatprec, measurement, fmt, NULL, count, (float[]){ __VA_ARGS__ }, true)
+#define multi_format_unit2(buf, bufsz, floatprec, measurement, fmt, delim, count, ...)  _multi_format_unit((char *[]){buf}, (size_t[]){bufsz}, floatprec, measurement, fmt, delim, count, (float[]){ __VA_ARGS__ }, false)
+#define multi_format_unit_array2(buflist, bufszlist, floatprec, measurement, fmt, count, ...)  (void)_multi_format_unit(buflist, bufszlist, floatprec, measurement, fmt, NULL, count, (float[]){ __VA_ARGS__ }, true)
 
-static const char *
-percentf2(double p, double t, char *buf)
+static
+int percentf3(char * const buf, size_t sz, double p, const double t)
 {
+	char *s = buf;
+	int rv = 0;
 	if (!p)
-		return "none";
+		_SNP("none");
+	else
 	if (t <= p)
-		return "100%";
+		_SNP("100%%");
+	else
+	{
+
 	p /= t;
 	if (p < 0.01)
-		sprintf(buf, ".%02.0f%%", p * 10000);  // ".01%"
+		_SNP(".%02.0f%%", p * 10000);  // ".01%"
 	else
 	if (p < 0.1)
-		sprintf(buf, "%.1f%%", p * 100);  // "9.1%"
+		_SNP("%.1f%%", p * 100);  // "9.1%"
 	else
-		sprintf(buf, "%3.0f%%", p * 100);  // " 99%"
-	return buf;
+		_SNP("%3.0f%%", p * 100);  // " 99%"
+
+	}
+	
+	return rv;
 }
-#define percentf(p, t, buf)  percentf2(p, p + t, buf)
+#define percentf4(buf, bufsz, p, t)  percentf3(buf, bufsz, p, p + t)
 
 #ifdef HAVE_CURSES
 static void adj_width(int var, int *length);
@@ -2620,7 +2639,7 @@ static void adj_width(int var, int *length);
 static int awidth = 1, rwidth = 1, swidth = 1, hwwidth = 1;
 
 static
-void format_statline(char *buf, const char *cHr, const char *aHr, const char *uHr, int accepted, int rejected, int stale, int wnotaccepted, int waccepted, int hwerrs, int badnonces, int allnonces)
+void format_statline(char *buf, size_t bufsz, const char *cHr, const char *aHr, const char *uHr, int accepted, int rejected, int stale, int wnotaccepted, int waccepted, int hwerrs, int badnonces, int allnonces)
 {
 	char rejpcbuf[6];
 	char bnbuf[6];
@@ -2629,40 +2648,42 @@ void format_statline(char *buf, const char *cHr, const char *aHr, const char *uH
 	adj_width(rejected, &rwidth);
 	adj_width(stale, &swidth);
 	adj_width(hwerrs, &hwwidth);
+	percentf4(rejpcbuf, sizeof(rejpcbuf), wnotaccepted, waccepted);
+	percentf3(bnbuf, sizeof(bnbuf), badnonces, allnonces);
 	
-	tailsprintf(buf, "%s/%s/%s | A:%*d R:%*d+%*d(%s) HW:%*d/%s",
+	tailsprintf(buf, bufsz, "%s/%s/%s | A:%*d R:%*d+%*d(%s) HW:%*d/%s",
 	            cHr, aHr, uHr,
 	            awidth, accepted,
 	            rwidth, rejected,
 	            swidth, stale,
-	            percentf(wnotaccepted, waccepted, rejpcbuf),
+	            rejpcbuf,
 	            hwwidth, hwerrs,
-	            percentf2(badnonces, allnonces, bnbuf)
+	            bnbuf
 	);
 }
 #endif
 
 static inline
-void temperature_column_tail(char *buf, bool maybe_unicode, const float * const temp)
+void temperature_column(char *buf, size_t bufsz, bool maybe_unicode, const float * const temp)
 {
 	if (!(use_unicode && have_unicode_degrees))
 		maybe_unicode = false;
 	if (temp && *temp > 0.)
 		if (maybe_unicode)
-			sprintf(buf, "%4.1f\xb0""C", *temp);
+			snprintf(buf, bufsz, "%4.1f\xb0""C", *temp);
 		else
-			sprintf(buf, "%4.1fC", *temp);
+			snprintf(buf, bufsz, "%4.1fC", *temp);
 	else
 	{
 		if (temp)
-			strcpy(buf, "     ");
+			snprintf(buf, bufsz, "     ");
 		if (maybe_unicode)
-			strcat(buf, " ");
+			tailsprintf(buf, bufsz, " ");
 	}
-	strcat(buf, " | ");
+	tailsprintf(buf, bufsz, " | ");
 }
 
-void get_statline3(char *buf, struct cgpu_info *cgpu, bool for_curses, bool opt_show_procs)
+void get_statline3(char *buf, size_t bufsz, struct cgpu_info *cgpu, bool for_curses, bool opt_show_procs)
 {
 #ifndef HAVE_CURSES
 	assert(for_curses == false);
@@ -2712,8 +2733,9 @@ void get_statline3(char *buf, struct cgpu_info *cgpu, bool for_curses, bool opt_
 			allnonces += slave->diff1;
 		}
 	
-	multi_format_unit_array(
+	multi_format_unit_array2(
 		((char*[]){cHr, aHr, uHr}),
+		((size_t[]){h2bs_fmt_size[H2B_NOUNIT], h2bs_fmt_size[H2B_NOUNIT], h2bs_fmt_size[hashrate_style]}),
 		true, "h/s", hashrate_style,
 		3,
 		1e6*rolling,
@@ -2725,33 +2747,38 @@ void get_statline3(char *buf, struct cgpu_info *cgpu, bool for_curses, bool opt_
 	if (for_curses)
 	{
 		if (opt_show_procs)
-			sprintf(buf, " %"PRIprepr": ", cgpu->proc_repr);
+			snprintf(buf, bufsz, " %"PRIprepr": ", cgpu->proc_repr);
 		else
-			sprintf(buf, " %s: ", cgpu->dev_repr);
+			snprintf(buf, bufsz, " %s: ", cgpu->dev_repr);
 	}
 	else
 #endif
-		sprintf(buf, "%s ", opt_show_procs ? cgpu->proc_repr_ns : cgpu->dev_repr_ns);
+		snprintf(buf, bufsz, "%s ", opt_show_procs ? cgpu->proc_repr_ns : cgpu->dev_repr_ns);
 	
 	if (unlikely(cgpu->status == LIFE_INIT))
 	{
-		tailsprintf(buf, "Initializing...");
+		tailsprintf(buf, bufsz, "Initializing...");
 		return;
 	}
 	
-	if (likely(cgpu->status != LIFE_DEAD2) && drv->override_statline_temp && drv->override_statline_temp(buf, cgpu, opt_show_procs))
-		temperature_column_tail(&buf[strlen(buf)], for_curses, NULL);
-	else
 	{
-		float temp = cgpu->temp;
-		if (!opt_show_procs)
+		const size_t bufln = strlen(buf);
+		const size_t abufsz = (bufln >= bufsz) ? 0 : (bufsz - bufln);
+		
+		if (likely(cgpu->status != LIFE_DEAD2) && drv->override_statline_temp2 && drv->override_statline_temp2(buf, bufsz, cgpu, opt_show_procs))
+			temperature_column(&buf[bufln], abufsz, for_curses, NULL);
+		else
 		{
-			// Find the highest temperature of all processors
-			for (struct cgpu_info *proc = cgpu; proc; proc = proc->next_proc)
-				if (proc->temp > temp)
-					temp = proc->temp;
+			float temp = cgpu->temp;
+			if (!opt_show_procs)
+			{
+				// Find the highest temperature of all processors
+				for (struct cgpu_info *proc = cgpu; proc; proc = proc->next_proc)
+					if (proc->temp > temp)
+						temp = proc->temp;
+			}
+			temperature_column(&buf[bufln], abufsz, for_curses, &temp);
 		}
-		temperature_column_tail(&buf[strlen(buf)], for_curses, &temp);
 	}
 	
 #ifdef HAVE_CURSES
@@ -2795,7 +2822,7 @@ void get_statline3(char *buf, struct cgpu_info *cgpu, bool for_curses, bool opt_
 		if (unlikely(all_off))
 			cHrStatsI = 2;
 		
-		format_statline(buf,
+		format_statline(buf, bufsz,
 		                cHrStatsOpt[cHrStatsI],
 		                aHr, uHr,
 		                accepted, rejected, stale,
@@ -2806,21 +2833,23 @@ void get_statline3(char *buf, struct cgpu_info *cgpu, bool for_curses, bool opt_
 	else
 #endif
 	{
-		tailsprintf(buf, "%ds:%s avg:%s u:%s | A:%d R:%d+%d(%s) HW:%d/%s",
+		percentf4(rejpcbuf, sizeof(rejpcbuf), wnotaccepted, waccepted);
+		percentf3(bnbuf, sizeof(bnbuf), badnonces, allnonces);
+		tailsprintf(buf, bufsz, "%ds:%s avg:%s u:%s | A:%d R:%d+%d(%s) HW:%d/%s",
 			opt_log_interval,
 			cHr, aHr, uHr,
 			accepted,
 			rejected,
 			stale,
-			percentf(wnotaccepted, waccepted, rejpcbuf),
+			rejpcbuf,
 			hwerrs,
-			percentf2(badnonces, allnonces, bnbuf)
+			bnbuf
 		);
 	}
 }
 
-#define get_statline(buf, cgpu)               get_statline3(buf, cgpu, false, opt_show_procs)
-#define get_statline2(buf, cgpu, for_curses)  get_statline3(buf, cgpu, for_curses, opt_show_procs)
+#define get_statline(buf, bufsz, cgpu)               get_statline3(buf, bufsz, cgpu, false, opt_show_procs)
+#define get_statline2(buf, bufsz, cgpu, for_curses)  get_statline3(buf, bufsz, cgpu, for_curses, opt_show_procs)
 
 static void text_print_status(int thr_id)
 {
@@ -2829,7 +2858,7 @@ static void text_print_status(int thr_id)
 
 	cgpu = get_thr_cgpu(thr_id);
 	if (cgpu) {
-		get_statline(logline, cgpu);
+		get_statline(logline, sizeof(logline), cgpu);
 		printf("%s\n", logline);
 	}
 }
@@ -2920,6 +2949,18 @@ void bfg_hline(WINDOW *win, int y)
 
 static int menu_attr = A_REVERSE;
 
+#define CURBUFSIZ 256
+#define cg_mvwprintw(win, y, x, fmt, ...) do { \
+	char tmp42[CURBUFSIZ]; \
+	snprintf(tmp42, sizeof(tmp42), fmt, ##__VA_ARGS__); \
+	mvwprintw(win, y, x, "%s", tmp42); \
+} while (0)
+#define cg_wprintw(win, fmt, ...) do { \
+	char tmp42[CURBUFSIZ]; \
+	snprintf(tmp42, sizeof(tmp42), fmt, ##__VA_ARGS__); \
+	wprintw(win, "%s", tmp42); \
+} while (0)
+
 /* Must be called with curses mutex lock held and curses_active */
 static void curses_print_status(void)
 {
@@ -2932,7 +2973,7 @@ static void curses_print_status(void)
 	efficiency = total_bytes_xfer ? total_diff_accepted * 2048. / total_bytes_xfer : 0.0;
 
 	wattron(statuswin, A_BOLD);
-	mvwprintw(statuswin, 0, 0, " " PACKAGE " version " VERSION " - Started: %s", datestamp);
+	cg_mvwprintw(statuswin, 0, 0, " " PACKAGE " version " VERSION " - Started: %s", datestamp);
 	timer_set_now(&now);
 	{
 		unsigned int days, hours;
@@ -2944,7 +2985,7 @@ static void curses_print_status(void)
 		d = div(d.rem, 3600);
 		hours = d.quot;
 		d = div(d.rem, 60);
-		wprintw(statuswin, " - [%3u day%c %02d:%02d:%02d]"
+		cg_wprintw(statuswin, " - [%3u day%c %02d:%02d:%02d]"
 			, days
 			, (days == 1) ? ' ' : 's'
 			, hours
@@ -2960,12 +3001,13 @@ static void curses_print_status(void)
 	utility = total_accepted / total_secs * 60;
 
 	char bwstr[12];
-	mvwprintw(statuswin, 4, 0, " ST:%d  F:%d  NB:%d  AS:%d  BW:[%s]  E:%.2f  U:%.1f/m  BS:%s",
+	cg_mvwprintw(statuswin, 4, 0, " ST:%d  F:%d  NB:%d  AS:%d  BW:[%s]  E:%.2f  U:%.1f/m  BS:%s",
 		__total_staged(),
 		total_go + total_ro,
 		new_blocks,
 		total_submitting,
-		multi_format_unit(bwstr, false, "B/s", H2B_SHORT, "/", 2,
+		multi_format_unit2(bwstr, sizeof(bwstr),
+		                   false, "B/s", H2B_SHORT, "/", 2,
 		                  (float)(total_bytes_rcvd / total_secs),
 		                  (float)(total_bytes_sent / total_secs)),
 		efficiency,
@@ -2973,17 +3015,17 @@ static void curses_print_status(void)
 		best_share);
 	wclrtoeol(statuswin);
 	if ((pool_strategy == POOL_LOADBALANCE  || pool_strategy == POOL_BALANCE) && total_pools > 1) {
-		mvwprintw(statuswin, 2, 0, " Connected to multiple pools with%s LP",
+		cg_mvwprintw(statuswin, 2, 0, " Connected to multiple pools with%s LP",
 			have_longpoll ? "": "out");
 	} else if (pool->has_stratum) {
-		mvwprintw(statuswin, 2, 0, " Connected to %s diff %s with stratum as user %s",
+		cg_mvwprintw(statuswin, 2, 0, " Connected to %s diff %s with stratum as user %s",
 			pool->sockaddr_url, pool->diff, pool->rpc_user);
 	} else {
-		mvwprintw(statuswin, 2, 0, " Connected to %s diff %s with%s LP as user %s",
+		cg_mvwprintw(statuswin, 2, 0, " Connected to %s diff %s with%s LP as user %s",
 			pool->sockaddr_url, pool->diff, have_longpoll ? "": "out", pool->rpc_user);
 	}
 	wclrtoeol(statuswin);
-	mvwprintw(statuswin, 3, 0, " Block: %s  Diff:%s (%s)  Started: %s",
+	cg_mvwprintw(statuswin, 3, 0, " Block: %s  Diff:%s (%s)  Started: %s",
 		  current_hash, block_diff, net_hashrate, blocktime);
 	
 	logdiv = statusy - 1;
@@ -3006,7 +3048,7 @@ static void curses_print_status(void)
 #endif
 	
 	wattron(statuswin, menu_attr);
-	mvwprintw(statuswin, 1, 0, " [M]anage devices [P]ool management [S]ettings [D]isplay options  [H]elp [Q]uit ");
+	cg_mvwprintw(statuswin, 1, 0, " [M]anage devices [P]ool management [S]ettings [D]isplay options  [H]elp [Q]uit ");
 	wattroff(statuswin, menu_attr);
 }
 
@@ -3045,7 +3087,7 @@ static void curses_print_devstatus(struct cgpu_info *cgpu)
 	if (wmove(statuswin, ypos, 0) == ERR)
 		return;
 	
-	get_statline2(logline, cgpu, true);
+	get_statline2(logline, sizeof(logline), cgpu, true);
 	if (selecting_device && (opt_show_procs ? (selected_device == cgpu->cgminer_id) : (devices[selected_device]->device == cgpu)))
 		wattron(statuswin, A_REVERSE);
 	bfg_waddstr(statuswin, logline);
@@ -3253,11 +3295,11 @@ void share_result_msg(const struct work *work, const char *disp, const char *rea
 	
 	cgpu = get_thr_cgpu(work->thr_id);
 	
-	suffix_string(work->share_diff, shrdiffdisp, 0);
-	suffix_string(tgtdiff, tgtdiffdisp, 0);
+	suffix_string(work->share_diff, shrdiffdisp, sizeof(shrdiffdisp), 0);
+	suffix_string(tgtdiff, tgtdiffdisp, sizeof(tgtdiffdisp), 0);
 	
 	if (total_pools > 1)
-		sprintf(where, " pool %d", work->pool->pool_no);
+		snprintf(where, sizeof(where), " pool %d", work->pool->pool_no);
 	else
 		where[0] = '\0';
 	
@@ -3385,7 +3427,7 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work,
 
 			strcpy(reason, "");
 			if (total_pools > 1)
-				sprintf(where, "pool %d", work->pool->pool_no);
+				snprintf(where, sizeof(where), "pool %d", work->pool->pool_no);
 			else
 				strcpy(where, "");
 
@@ -3534,8 +3576,8 @@ static bool submit_upstream_work_completed(struct work *work, bool resubmit, str
 			memcpy(&tm_submit_reply, tm, sizeof(struct tm));
 
 			if (work->clone) {
-				sprintf(workclone, "C:%1.3f",
-					tdiff((struct timeval *)&(work->tv_cloned),
+				snprintf(workclone, sizeof(workclone), "C:%1.3f",
+						tdiff((struct timeval *)&(work->tv_cloned),
 						(struct timeval *)&(work->tv_getwork_reply)));
 			}
 			else
@@ -3544,7 +3586,8 @@ static bool submit_upstream_work_completed(struct work *work, bool resubmit, str
 			if (work->work_difficulty < 1)
 				diffplaces = 6;
 
-			sprintf(worktime, " <-%08lx.%08lx M:%c D:%1.*f G:%02d:%02d:%02d:%1.3f %s (%1.3f) W:%1.3f (%1.3f) S:%1.3f R:%02d:%02d:%02d",
+			snprintf(worktime, sizeof(worktime),
+				" <-%08lx.%08lx M:%c D:%1.*f G:%02d:%02d:%02d:%1.3f %s (%1.3f) W:%1.3f (%1.3f) S:%1.3f R:%02d:%02d:%02d",
 				(unsigned long)swab32(*(uint32_t *)&(work->data[opt_scrypt ? 32 : 28])),
 				(unsigned long)swab32(*(uint32_t *)&(work->data[opt_scrypt ? 28 : 24])),
 				work->getwork_mode, diffplaces, work->work_difficulty,
@@ -3566,7 +3609,7 @@ static bool submit_upstream_work_completed(struct work *work, bool resubmit, str
 
 		cgpu = get_thr_cgpu(thr_id);
 		
-		get_statline(logline, cgpu);
+		get_statline(logline, sizeof(logline), cgpu);
 		applog(LOG_INFO, "%s", logline);
 	}
 
@@ -3694,7 +3737,7 @@ static void calc_diff(struct work *work, int known)
 	difficulty = work->work_difficulty;
 
 	pool_stats->last_diff = difficulty;
-	suffix_string((uint64_t)difficulty, work->pool->diff, 0);
+	suffix_string((uint64_t)difficulty, work->pool->diff, sizeof(work->pool->diff), 0);
 
 	if (difficulty == pool_stats->min_diff)
 		pool_stats->min_diff_count++;
@@ -4159,7 +4202,7 @@ static void push_curl_entry(struct curl_ent *ce, struct pool *pool)
 {
 	mutex_lock(&pool->pool_lock);
 	if (!ce || !ce->curl)
-		quit(1, "Attempted to add NULL in push_curl_entry");
+		quithere(1, "Attempted to add NULL");
 	LL_PREPEND(pool->curllist, ce);
 	cgtime(&ce->tv);
 	pthread_cond_broadcast(&pool->cr_cond);
@@ -4460,7 +4503,7 @@ static uint64_t share_diff(const struct work *work)
 	if (unlikely(ret > best_diff)) {
 		new_best = true;
 		best_diff = ret;
-		suffix_string(best_diff, best_share, 0);
+		suffix_string(best_diff, best_share, sizeof(best_share), 0);
 	}
 	if (unlikely(ret > work->pool->best_diff))
 		work->pool->best_diff = ret;
@@ -4798,7 +4841,7 @@ next_write_sws_del:
 			sshare_id =
 			sshare->id = swork_id++;
 			HASH_ADD_INT(stratum_shares, id, sshare);
-			sprintf(s, "{\"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\": %d, \"method\": \"mining.submit\"}",
+			snprintf(s, 1024, "{\"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\": %d, \"method\": \"mining.submit\"}",
 				pool->rpc_user, work->job_id, nonce2hex, ntimehex, noncehex, sshare->id);
 			mutex_unlock(&sshare_lock);
 			
@@ -5204,7 +5247,7 @@ static void set_curblock(char *hexstr, unsigned char *hash)
 	free(current_fullhash);
 	current_fullhash = malloc(65);
 	bin2hex(current_fullhash, hash_swap, 32);
-	get_timestamp(blocktime, block_time);
+	get_timestamp(blocktime, sizeof(blocktime), block_time);
 	cg_wunlock(&ch_lock);
 
 	applog(LOG_INFO, "New block: %s diff %s (%s)", current_hash, block_diff, net_hashrate);
@@ -5250,8 +5293,9 @@ static void set_blockdiff(const struct work *work)
 	diff = target_diff(target);
 	diff64 = diff;
 
-	suffix_string(diff64, block_diff, 0);
-	format_unit(net_hashrate, true, "h/s", H2B_SHORT, diff * 7158278, -1);
+	suffix_string(diff64, block_diff, sizeof(block_diff), 0);
+	format_unit2(net_hashrate, sizeof(net_hashrate),
+	             true, "h/s", H2B_SHORT, diff * 7158278, -1);
 	if (unlikely(current_diff != diff))
 		applog(LOG_NOTICE, "Network difficulty changed to %s (%s)", block_diff, net_hashrate);
 	current_diff = diff;
@@ -5486,10 +5530,10 @@ static void display_pool_summary(struct pool *pool)
 		wlog(" Rejected difficulty shares: %1.f\n", pool->diff_rejected);
 		pool_secs = timer_elapsed(&pool->cgminer_stats.start_tv, NULL);
 		wlog(" Network transfer: %s  (%s)\n",
-		     multi_format_unit(xfer, true, "B", H2B_SPACED, " / ", 2,
+		     multi_format_unit2(xfer, sizeof(xfer), true, "B", H2B_SPACED, " / ", 2,
 		                       (float)pool->cgminer_pool_stats.net_bytes_received,
 		                       (float)pool->cgminer_pool_stats.net_bytes_sent),
-		     multi_format_unit(bw, true, "B/s", H2B_SPACED, " / ", 2,
+		     multi_format_unit2(bw, sizeof(bw), true, "B/s", H2B_SPACED, " / ", 2,
 		                       (float)(pool->cgminer_pool_stats.net_bytes_received / pool_secs),
 		                       (float)(pool->cgminer_pool_stats.net_bytes_sent / pool_secs)));
 		uint64_t pool_bytes_xfer = pool->cgminer_pool_stats.net_bytes_received + pool->cgminer_pool_stats.net_bytes_sent;
@@ -5795,7 +5839,7 @@ void zero_bestshare(void)
 
 	best_diff = 0;
 	memset(best_share, 0, 8);
-	suffix_string(best_diff, best_share, 0);
+	suffix_string(best_diff, best_share, sizeof(best_share), 0);
 
 	for (i = 0; i < total_pools; i++) {
 		struct pool *pool = pools[i];
@@ -6297,7 +6341,7 @@ retry:
 		char *str, filename[PATH_MAX], prompt[PATH_MAX + 50];
 
 		default_save_file(filename);
-		sprintf(prompt, "Config filename to write (Enter for default) [%s]", filename);
+		snprintf(prompt, sizeof(prompt), "Config filename to write (Enter for default) [%s]", filename);
 		str = curses_input(prompt);
 		if (strcmp(str, "-1")) {
 			struct stat statbuf;
@@ -6356,7 +6400,7 @@ refresh:
 	clear_logwin();
 	wlogprint("Select processor to manage using up/down arrow keys\n");
 	
-	get_statline3(logline, cgpu, true, true);
+	get_statline3(logline, sizeof(logline), cgpu, true, true);
 	wattron(logwin, A_BOLD);
 	wlogprint("%s", logline);
 	wattroff(logwin, A_BOLD);
@@ -6640,12 +6684,12 @@ static void hashmeter(int thr_id, struct timeval *diff,
 			thr_id, hashes_done, hashes_done / 1000 / secs);
 
 		/* Rolling average for each thread and each device */
-		decay_time(&thr->rolling, local_mhashes / secs);
+		decay_time(&thr->rolling, local_mhashes / secs, secs);
 		for (i = 0; i < threadobj; i++)
 			thread_rolling += cgpu->thr[i]->rolling;
 
 		mutex_lock(&hash_lock);
-		decay_time(&cgpu->rolling, thread_rolling);
+		decay_time(&cgpu->rolling, thread_rolling, secs);
 		cgpu->total_mhashes += local_mhashes;
 		mutex_unlock(&hash_lock);
 
@@ -6663,7 +6707,7 @@ static void hashmeter(int thr_id, struct timeval *diff,
 
 				*last_msg_tv = now;
 
-				get_statline(logline, cgpu);
+				get_statline(logline, sizeof(logline), cgpu);
 				if (!curses_active) {
 					printf("%s          \r", logline);
 					fflush(stdout);
@@ -6687,15 +6731,16 @@ static void hashmeter(int thr_id, struct timeval *diff,
 	cgtime(&total_tv_end);
 
 	local_secs = (double)total_diff.tv_sec + ((double)total_diff.tv_usec / 1000000.0);
-	decay_time(&rolling, local_mhashes_done / local_secs);
+	decay_time(&rolling, local_mhashes_done / local_secs, local_secs);
 	global_hashrate = roundl(rolling) * 1000000;
 
 	timersub(&total_tv_end, &total_tv_start, &total_diff);
 	total_secs = (double)total_diff.tv_sec +
 		((double)total_diff.tv_usec / 1000000.0);
 
-	multi_format_unit_array(
+	multi_format_unit_array2(
 		((char*[]){cHr, aHr, uHr}),
+		((size_t[]){h2bs_fmt_size[H2B_NOUNIT], h2bs_fmt_size[H2B_NOUNIT], h2bs_fmt_size[H2B_SPACED]}),
 		true, "h/s", H2B_SHORT,
 		3,
 		1e6*rolling,
@@ -6738,9 +6783,9 @@ static void hashmeter(int thr_id, struct timeval *diff,
 		}
 		
 		if (working_devs == working_procs)
-			sprintf(statusline, "%s%d        ", bad ? "\2" : "", working_devs);
+			snprintf(statusline, sizeof(statusline), "%s%d        ", bad ? "\2" : "", working_devs);
 		else
-			sprintf(statusline, "%s%d/%d     ", bad ? "\2" : "", working_devs, working_procs);
+			snprintf(statusline, sizeof(statusline), "%s%d/%d     ", bad ? "\2" : "", working_devs, working_procs);
 		
 		divx = 7;
 		if (opt_show_procs && !opt_compact)
@@ -6753,9 +6798,9 @@ static void hashmeter(int thr_id, struct timeval *diff,
 			++divx;
 		}
 		
-		temperature_column_tail(&statusline[divx], true, &temp);
+		temperature_column(&statusline[divx], sizeof(statusline)-divx, true, &temp);
 		
-		format_statline(statusline,
+		format_statline(statusline, sizeof(statusline),
 		                cHr, aHr,
 		                uHr,
 		                total_accepted,
@@ -6771,7 +6816,11 @@ static void hashmeter(int thr_id, struct timeval *diff,
 	memmove(&uHr[6], &uHr[5], strlen(&uHr[5]) + 1);
 	uHr[5] = ' ';
 	
-	sprintf(logstatusline, "%s%ds:%s avg:%s u:%s | A:%d R:%d+%d(%s) HW:%d/%s",
+	percentf4(rejpcbuf, sizeof(rejpcbuf), total_diff_rejected + total_diff_stale, total_diff_accepted);
+	percentf3(bnbuf, sizeof(bnbuf), total_bad_nonces, total_diff1);
+	
+	snprintf(logstatusline, sizeof(logstatusline),
+	         "%s%ds:%s avg:%s u:%s | A:%d R:%d+%d(%s) HW:%d/%s",
 		want_per_device_stats ? "ALL " : "",
 		opt_log_interval,
 		cHr, aHr,
@@ -6779,9 +6828,9 @@ static void hashmeter(int thr_id, struct timeval *diff,
 		total_accepted,
 		total_rejected,
 		total_stale,
-		percentf(total_diff_rejected + total_diff_stale, total_diff_accepted, rejpcbuf),
+		rejpcbuf,
 		hw_errors,
-		percentf2(total_bad_nonces, total_diff1, bnbuf)
+		bnbuf
 	);
 
 
@@ -6807,7 +6856,8 @@ void hashmeter2(struct thr_info *thr)
 	cgtime(&tv_now);
 	timersub(&tv_now, &thr->tv_lastupdate, &tv_elapsed);
 	/* Update the hashmeter at most 5 times per second */
-	if (tv_elapsed.tv_sec > 0 || tv_elapsed.tv_usec > 200) {
+	if ((thr->hashes_done && (tv_elapsed.tv_sec > 0 || tv_elapsed.tv_usec > 200000)) ||
+	    tv_elapsed.tv_sec >= opt_log_interval) {
 		hashmeter(thr->id, &tv_elapsed, thr->hashes_done);
 		thr->hashes_done = 0;
 		thr->tv_lastupdate = tv_now;
@@ -7664,8 +7714,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 
 	clean_work(work);
 
-	/* Use intermediate lock to update the one pool variable */
-	cg_ilock(&pool->data_lock);
+	cg_wlock(&pool->data_lock);
 
 	/* Generate coinbase */
 	bytes_resize(&work->nonce2, pool->n2size);
@@ -7685,7 +7734,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	pool->nonce2++;
 
 	/* Downgrade to a read lock to read off the pool variables */
-	cg_dlock(&pool->data_lock);
+	cg_dwlock(&pool->data_lock);
 
 	/* Generate merkle root */
 	gen_hash(coinbase, merkle_root, bytes_len(&pool->swork.coinbase));
@@ -8796,7 +8845,7 @@ static void log_print_status(struct cgpu_info *cgpu)
 {
 	char logline[255];
 
-	get_statline(logline, cgpu);
+	get_statline(logline, sizeof(logline), cgpu);
 	applog(LOG_WARNING, "%s", logline);
 }
 
@@ -8838,10 +8887,10 @@ void print_summary(void)
 	applog(LOG_WARNING, "Rejected difficulty shares: %1.f", total_diff_rejected);
 	applog(LOG_WARNING, "Hardware errors: %d", hw_errors);
 	applog(LOG_WARNING, "Network transfer: %s  (%s)",
-	       multi_format_unit(xfer, true, "B", H2B_SPACED, " / ", 2,
+	       multi_format_unit2(xfer, sizeof(xfer), true, "B", H2B_SPACED, " / ", 2,
 	                         (float)total_bytes_rcvd,
 	                         (float)total_bytes_sent),
-	       multi_format_unit(bw, true, "B/s", H2B_SPACED, " / ", 2,
+	       multi_format_unit2(bw, sizeof(bw), true, "B/s", H2B_SPACED, " / ", 2,
 	                         (float)(total_bytes_rcvd / total_secs),
 	                         (float)(total_bytes_sent / total_secs)));
 	applog(LOG_WARNING, "Efficiency (accepted shares * difficulty / 2 KB): %.2f", efficiency);
@@ -8869,10 +8918,10 @@ void print_summary(void)
 			applog(LOG_WARNING, " Rejected difficulty shares: %1.f", pool->diff_rejected);
 			pool_secs = timer_elapsed(&pool->cgminer_stats.start_tv, NULL);
 			applog(LOG_WARNING, " Network transfer: %s  (%s)",
-			       multi_format_unit(xfer, true, "B", H2B_SPACED, " / ", 2,
+			       multi_format_unit2(xfer, sizeof(xfer), true, "B", H2B_SPACED, " / ", 2,
 			                         (float)pool->cgminer_pool_stats.net_bytes_received,
 			                         (float)pool->cgminer_pool_stats.net_bytes_sent),
-			       multi_format_unit(bw, true, "B/s", H2B_SPACED, " / ", 2,
+			       multi_format_unit2(bw, sizeof(bw), true, "B/s", H2B_SPACED, " / ", 2,
 			                         (float)(pool->cgminer_pool_stats.net_bytes_received / pool_secs),
 			                         (float)(pool->cgminer_pool_stats.net_bytes_sent / pool_secs)));
 			uint64_t pool_bytes_xfer = pool->cgminer_pool_stats.net_bytes_received + pool->cgminer_pool_stats.net_bytes_sent;
@@ -9008,13 +9057,16 @@ static void *test_pool_thread(void *arg)
  * active it returns false. */
 bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass)
 {
+	size_t siz;
+
 	pool->rpc_url = url;
 	pool->rpc_user = user;
 	pool->rpc_pass = pass;
-	pool->rpc_userpass = malloc(strlen(pool->rpc_user) + strlen(pool->rpc_pass) + 2);
+	siz = strlen(pool->rpc_user) + strlen(pool->rpc_pass) + 2;
+	pool->rpc_userpass = malloc(siz);
 	if (!pool->rpc_userpass)
 		quit(1, "Failed to malloc userpass");
-	sprintf(pool->rpc_userpass, "%s:%s", pool->rpc_user, pool->rpc_pass);
+	snprintf(pool->rpc_userpass, siz, "%s:%s", pool->rpc_user, pool->rpc_pass);
 
 	pool->testing = true;
 	pool->idle = true;
@@ -9641,7 +9693,7 @@ int main(int argc, char *argv[])
 
 	notifier_init(submit_waiting_notifier);
 
-	sprintf(packagename, "%s %s", PACKAGE, VERSION);
+	snprintf(packagename, sizeof(packagename), "%s %s", PACKAGE, VERSION);
 
 #ifdef WANT_CPUMINE
 	init_max_name_len();
@@ -9727,6 +9779,8 @@ int main(int argc, char *argv[])
 	if (opt_benchmark) {
 		struct pool *pool;
 
+		if (opt_scrypt)
+			quit(1, "Cannot use benchmark mode with scrypt");
 		want_longpoll = false;
 		pool = add_pool();
 		pool->rpc_url = malloc(255);
@@ -9885,6 +9939,7 @@ int main(int argc, char *argv[])
 
 	for (i = 0; i < total_pools; i++) {
 		struct pool *pool = pools[i];
+		size_t siz;
 
 		pool->cgminer_stats.getwork_wait_min.tv_sec = MIN_SEC_UNSET;
 		pool->cgminer_pool_stats.getwork_wait_min.tv_sec = MIN_SEC_UNSET;
@@ -9895,10 +9950,11 @@ int main(int argc, char *argv[])
 		if (!pool->rpc_userpass) {
 			if (!pool->rpc_user || !pool->rpc_pass)
 				quit(1, "No login credentials supplied for pool %u %s", i, pool->rpc_url);
-			pool->rpc_userpass = malloc(strlen(pool->rpc_user) + strlen(pool->rpc_pass) + 2);
+			siz = strlen(pool->rpc_user) + strlen(pool->rpc_pass) + 2;
+			pool->rpc_userpass = malloc(siz);
 			if (!pool->rpc_userpass)
 				quit(1, "Failed to malloc userpass");
-			sprintf(pool->rpc_userpass, "%s:%s", pool->rpc_user, pool->rpc_pass);
+			snprintf(pool->rpc_userpass, siz, "%s:%s", pool->rpc_user, pool->rpc_pass);
 		}
 	}
 	/* Set the currentpool to pool with priority 0 */
@@ -10021,7 +10077,7 @@ begin_bench:
 		localtime_r(&miner_start_ts, &schedstart.tm);
 	if (schedstop.tm.tm_sec)
 		localtime_r(&miner_start_ts, &schedstop .tm);
-	get_datestamp(datestamp, miner_start_ts);
+	get_datestamp(datestamp, sizeof(datestamp), miner_start_ts);
 
 	// Initialise processors and threads
 	k = 0;

+ 53 - 13
miner.h

@@ -26,6 +26,7 @@
 #include <pthread.h>
 #include <jansson.h>
 #include <curl/curl.h>
+#include <sched.h>
 
 #include <blkmaker.h>
 #include <blktemplate.h>
@@ -290,7 +291,7 @@ struct device_drv {
 
 	// Processor-specific functions
 	void (*reinit_device)(struct cgpu_info *);
-	bool (*override_statline_temp)(char *buf, struct cgpu_info *, bool per_processor);
+	bool (*override_statline_temp2)(char *buf, size_t bufsz, struct cgpu_info *, bool per_processor);
 	struct api_data* (*get_api_extra_device_detail)(struct cgpu_info *);
 	struct api_data* (*get_api_extra_device_status)(struct cgpu_info *);
 	struct api_data *(*get_api_stats)(struct cgpu_info *);
@@ -734,12 +735,18 @@ static inline void mutex_lock(pthread_mutex_t *lock)
 		quit(1, "WTF MUTEX ERROR ON LOCK!");
 }
 
-static inline void mutex_unlock(pthread_mutex_t *lock)
+static inline void mutex_unlock_noyield(pthread_mutex_t *lock)
 {
 	if (unlikely(pthread_mutex_unlock(lock)))
 		quit(1, "WTF MUTEX ERROR ON UNLOCK!");
 }
 
+static inline void mutex_unlock(pthread_mutex_t *lock)
+{
+	mutex_unlock_noyield(lock);
+	sched_yield();
+}
+
 static inline int mutex_trylock(pthread_mutex_t *lock)
 {
 	return pthread_mutex_trylock(lock);
@@ -763,14 +770,26 @@ static inline void rw_unlock(pthread_rwlock_t *lock)
 		quit(1, "WTF RWLOCK ERROR ON UNLOCK!");
 }
 
+static inline void rd_unlock_noyield(pthread_rwlock_t *lock)
+{
+	rw_unlock(lock);
+}
+
+static inline void wr_unlock_noyield(pthread_rwlock_t *lock)
+{
+	rw_unlock(lock);
+}
+
 static inline void rd_unlock(pthread_rwlock_t *lock)
 {
 	rw_unlock(lock);
+	sched_yield();
 }
 
 static inline void wr_unlock(pthread_rwlock_t *lock)
 {
 	rw_unlock(lock);
+	sched_yield();
 }
 
 static inline void mutex_init(pthread_mutex_t *lock)
@@ -804,7 +823,7 @@ static inline void cg_rlock(cglock_t *lock)
 {
 	mutex_lock(&lock->mutex);
 	rd_lock(&lock->rwlock);
-	mutex_unlock(&lock->mutex);
+	mutex_unlock_noyield(&lock->mutex);
 }
 
 /* Intermediate variant of cglock */
@@ -826,6 +845,14 @@ static inline void cg_wlock(cglock_t *lock)
 	wr_lock(&lock->rwlock);
 }
 
+/* Downgrade write variant to a read lock */
+static inline void cg_dwlock(cglock_t *lock)
+{
+	wr_unlock_noyield(&lock->rwlock);
+	rd_lock(&lock->rwlock);
+	mutex_unlock_noyield(&lock->mutex);
+}
+
 /* Downgrade intermediate variant to a read lock */
 static inline void cg_dlock(cglock_t *lock)
 {
@@ -969,14 +996,26 @@ extern bool add_pool_details(struct pool *pool, bool live, char *url, char *user
 #define MAX_GPUDEVICES 16
 #define MAX_DEVICES 4096
 
-#define MIN_INTENSITY -10
-#define _MIN_INTENSITY_STR "-10"
+#define MIN_SHA_INTENSITY -10
+#define MIN_SHA_INTENSITY_STR "-10"
+#define MAX_SHA_INTENSITY 14
+#define MAX_SHA_INTENSITY_STR "14"
+#define MIN_SCRYPT_INTENSITY 8
+#define MIN_SCRYPT_INTENSITY_STR "8"
+#define MAX_SCRYPT_INTENSITY 20
+#define MAX_SCRYPT_INTENSITY_STR "20"
 #ifdef USE_SCRYPT
-#define MAX_INTENSITY 20
-#define _MAX_INTENSITY_STR "20"
+#define MIN_INTENSITY (opt_scrypt ? MIN_SCRYPT_INTENSITY : MIN_SHA_INTENSITY)
+#define MIN_INTENSITY_STR (opt_scrypt ? MIN_SCRYPT_INTENSITY_STR : MIN_SHA_INTENSITY_STR)
+#define MAX_INTENSITY (opt_scrypt ? MAX_SCRYPT_INTENSITY : MAX_SHA_INTENSITY)
+#define MAX_INTENSITY_STR (opt_scrypt ? MAX_SCRYPT_INTENSITY_STR : MAX_SHA_INTENSITY_STR)
+#define MAX_GPU_INTENSITY MAX_SCRYPT_INTENSITY
 #else
-#define MAX_INTENSITY 14
-#define _MAX_INTENSITY_STR "14"
+#define MIN_INTENSITY MIN_SHA_INTENSITY
+#define MIN_INTENSITY_STR MIN_SHA_INTENSITY_STR
+#define MAX_INTENSITY MAX_SHA_INTENSITY
+#define MAX_INTENSITY_STR MAX_SHA_INTENSITY_STR
+#define MAX_GPU_INTENSITY MAX_SHA_INTENSITY
 #endif
 
 extern struct string_elist *scan_devices;
@@ -1280,8 +1319,8 @@ struct work {
 	struct work *next;
 };
 
-extern void get_datestamp(char *, time_t);
-#define get_now_datestamp(buf)  get_datestamp(buf, INVALID_TIMESTAMP)
+extern void get_datestamp(char *, size_t, time_t);
+#define get_now_datestamp(buf, bufsz)  get_datestamp(buf, bufsz, INVALID_TIMESTAMP)
 extern void inc_hw_errors2(struct thr_info *thr, const struct work *work, const uint32_t *bad_nonce_p);
 extern void inc_hw_errors(struct thr_info *, const struct work *, const uint32_t bad_nonce);
 #define inc_hw_errors_only(thr)  inc_hw_errors(thr, NULL, 0)
@@ -1300,8 +1339,8 @@ extern struct work *find_queued_work_bymidstate(struct cgpu_info *cgpu, char *mi
 extern void work_completed(struct cgpu_info *cgpu, struct work *work);
 extern bool abandon_work(struct work *, struct timeval *work_runtime, uint64_t hashes);
 extern void hash_queued_work(struct thr_info *mythr);
-extern void get_statline3(char *buf, struct cgpu_info *, bool for_curses, bool opt_show_procs);
-extern void tailsprintf(char *f, const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 2, 3);
+extern void get_statline3(char *buf, size_t bufsz, struct cgpu_info *, bool for_curses, bool opt_show_procs);
+extern void tailsprintf(char *buf, size_t bufsz, const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 3, 4);
 extern void _wlog(const char *str);
 extern void _wlogprint(const char *str);
 extern int curses_int(const char *query);
@@ -1361,6 +1400,7 @@ enum api_data_type {
 	API_HS,
 	API_DIFF,
 	API_JSON,
+	API_PERCENT
 };
 
 struct api_data {

+ 23 - 0
miner.php

@@ -751,7 +751,11 @@ function fmt($section, $name, $value, $when, $alldata)
 	case 'DEVS.Temperature':
 		$ret = $value.'&deg;C';
 		if (!isset($alldata['GPU']))
+		{
+			if ($value == 0)
+				$ret = '&nbsp;';
 			break;
+		}
 	case 'GPU.GPU Clock':
 	case 'DEVS.GPU Clock':
 	case 'GPU.Memory Clock':
@@ -938,6 +942,25 @@ function fmt($section, $name, $value, $when, $alldata)
 		if ($value != '')
 			$ret = number_format((float)$value, 2);
 		break;
+	case 'DEVS.Device Hardware%':
+	case 'DEVS.Device Rejected%':
+	case 'PGA.Device Hardware%':
+	case 'PGA.Device Rejected%':
+	case 'GPU.Device Hardware%':
+	case 'GPU.Device Rejected%':
+	case 'POOL.Pool Rejected%':
+	case 'POOL.Pool Stale%':
+	case 'SUMMARY.Device Hardware%':
+	case 'SUMMARY.Device Rejected%':
+	case 'SUMMARY.Pool Rejected%':
+	case 'SUMMARY.Pool Stale%':
+		if ($value != '')
+			$ret = number_format((float)$value, 2) . '%';
+		break;
+	case 'SUMMARY.Best Share':
+		if ($value != '')
+			$ret = number_format((float)$value);
+		break;
 	}
 
  if ($section == 'NOTIFY' && substr($name, 0, 1) == '*' && $value != '0')

+ 43 - 33
util.c

@@ -54,6 +54,8 @@
 #include "compat.h"
 #include "util.h"
 
+#define DEFAULT_SOCKWAIT 60
+
 bool successful_connect = false;
 struct timeval nettime;
 
@@ -1403,19 +1405,18 @@ bool _stratum_send(struct pool *pool, char *s, ssize_t len, bool force)
 	return (ret == SEND_OK);
 }
 
-static bool socket_full(struct pool *pool, bool wait)
+static bool socket_full(struct pool *pool, int wait)
 {
 	SOCKETTYPE sock = pool->sock;
 	struct timeval timeout;
 	fd_set rd;
 
+	if (unlikely(wait < 0))
+		wait = 0;
 	FD_ZERO(&rd);
 	FD_SET(sock, &rd);
 	timeout.tv_usec = 0;
-	if (wait)
-		timeout.tv_sec = 60;
-	else
-		timeout.tv_sec = 1;
+	timeout.tv_sec = wait;
 	if (select(sock + 1, &rd, NULL, NULL, &timeout) > 0)
 		return true;
 	return false;
@@ -1427,7 +1428,7 @@ bool sock_full(struct pool *pool)
 	if (strlen(pool->sockbuf))
 		return true;
 
-	return (socket_full(pool, false));
+	return (socket_full(pool, 0));
 }
 
 static void clear_sockbuf(struct pool *pool)
@@ -1467,7 +1468,7 @@ static void recalloc_sock(struct pool *pool, size_t len)
 	// applog(LOG_DEBUG, "Recallocing pool sockbuf to %lu", (unsigned long)new);
 	pool->sockbuf = realloc(pool->sockbuf, new);
 	if (!pool->sockbuf)
-		quit(1, "Failed to realloc pool sockbuf in recalloc_sock");
+		quithere(1, "Failed to realloc pool sockbuf");
 	memset(pool->sockbuf + old, 0, new - old);
 	pool->sockbuf_size = new;
 }
@@ -1476,14 +1477,15 @@ static void recalloc_sock(struct pool *pool, size_t len)
  * from the socket and returns that as a malloced char */
 char *recv_line(struct pool *pool)
 {
-	ssize_t len, buflen;
 	char *tok, *sret = NULL;
+	ssize_t len, buflen;
+	int waited = 0;
 
 	if (!strstr(pool->sockbuf, "\n")) {
 		struct timeval rstart, now;
 
 		cgtime(&rstart);
-		if (!socket_full(pool, true)) {
+		if (!socket_full(pool, DEFAULT_SOCKWAIT)) {
 			applog(LOG_DEBUG, "Timed out waiting for data on socket_full");
 			goto out;
 		}
@@ -1500,11 +1502,13 @@ char *recv_line(struct pool *pool)
 				suspend_stratum(pool);
 				break;
 			}
+			cgtime(&now);
+			waited = tdiff(&now, &rstart);
 			if (n < 0) {
 				//Save errno from being overweitten bei socket_ commands 
 				int socket_recv_errno;
 				socket_recv_errno = SOCKERR;
-				if (!sock_blocks() || !socket_full(pool, true)) {
+				if (!sock_blocks() || !socket_full(pool, DEFAULT_SOCKWAIT - waited)) {
 					applog(LOG_DEBUG, "Failed to recv sock in recv_line: %s", bfg_strerror(socket_recv_errno, BST_SOCKET));
 					suspend_stratum(pool);
 					break;
@@ -1514,8 +1518,7 @@ char *recv_line(struct pool *pool)
 				recalloc_sock(pool, slen);
 				strcat(pool->sockbuf, s);
 			}
-			cgtime(&now);
-		} while (tdiff(&now, &rstart) < 60 && !strstr(pool->sockbuf, "\n"));
+		} while (waited < DEFAULT_SOCKWAIT && !strstr(pool->sockbuf, "\n"));
 	}
 
 	buflen = strlen(pool->sockbuf);
@@ -1571,18 +1574,18 @@ char *json_dumps_ANY(json_t *json, size_t flags)
 	size_t len;
 	
 	if (!tmp)
-		quit(1, "json_dumps_ANY failed to allocate json array");
+		quithere(1, "Failed to allocate json array");
 	if (json_array_append(tmp, json))
-		quit(1, "json_dumps_ANY failed to append temporary array");
+		quithere(1, "Failed to append temporary array");
 	s = json_dumps(tmp, flags);
 	if (!s)
 		return NULL;
 	for (i = 0; s[i] != '['; ++i)
 		if (unlikely(!(s[i] && isCspace(s[i]))))
-			quit(1, "json_dumps_ANY failed to find opening bracket in array dump");
+			quithere(1, "Failed to find opening bracket in array dump");
 	len = strlen(&s[++i]) - 1;
 	if (unlikely(s[i+len] != ']'))
-		quit(1, "json_dumps_ANY failed to find closing bracket in array dump");
+		quithere(1, "Failed to find closing bracket in array dump");
 	rv = malloc(len + 1);
 	memcpy(rv, &s[i], len);
 	rv[len] = '\0';
@@ -1977,7 +1980,7 @@ static bool setup_stratum_curl(struct pool *pool)
 		curl_easy_cleanup(pool->stratum_curl);
 	pool->stratum_curl = curl_easy_init();
 	if (unlikely(!pool->stratum_curl))
-		quit(1, "Failed to curl_easy_init in initiate_stratum");
+		quithere(1, "Failed to curl_easy_init");
 	if (pool->sockbuf)
 		pool->sockbuf[0] = '\0';
 
@@ -1986,7 +1989,7 @@ static bool setup_stratum_curl(struct pool *pool)
 	if (!pool->sockbuf) {
 		pool->sockbuf = calloc(RBUFSIZE, 1);
 		if (!pool->sockbuf)
-			quit(1, "Failed to calloc pool sockbuf in initiate_stratum");
+			quithere(1, "Failed to calloc pool sockbuf");
 		pool->sockbuf_size = RBUFSIZE;
 	}
 
@@ -2133,7 +2136,7 @@ resend:
 
 	recvd = true;
 	
-	if (!socket_full(pool, true)) {
+	if (!socket_full(pool, DEFAULT_SOCKWAIT)) {
 		applog(LOG_DEBUG, "Timed out waiting for response in initiate_stratum");
 		goto out;
 	}
@@ -2309,7 +2312,7 @@ void *realloc_strcat(char *ptr, char *s)
 
 	ret = malloc(len);
 	if (unlikely(!ret))
-		quit(1, "Failed to malloc in realloc_strcat");
+		quithere(1, "Failed to malloc");
 
 	sprintf(ret, "%s%s", ptr, s);
 	free(ptr);
@@ -2396,16 +2399,16 @@ struct bfgtls_data *get_bfgtls()
 	
 	bfgtls = malloc(sizeof(*bfgtls));
 	if (!bfgtls)
-		quit(1, "malloc bfgtls failed");
+		quithere(1, "malloc bfgtls failed");
 	p = malloc(64);
 	if (!p)
-		quit(1, "malloc bfg_strerror_result failed");
+		quithere(1, "malloc bfg_strerror_result failed");
 	*bfgtls = (struct bfgtls_data){
 		.bfg_strerror_resultsz = 64,
 		.bfg_strerror_result = p,
 	};
 	if (pthread_setspecific(key_bfgtls, bfgtls))
-		quit(1, "pthread_setspecific failed");
+		quithere(1, "pthread_setspecific failed");
 	
 	return bfgtls;
 }
@@ -2413,7 +2416,7 @@ struct bfgtls_data *get_bfgtls()
 void bfg_init_threadlocal()
 {
 	if (pthread_key_create(&key_bfgtls, NULL))
-		quit(1, "pthread_key_create failed");
+		quithere(1, "pthread_key_create failed");
 }
 
 static
@@ -2426,7 +2429,7 @@ bool bfg_grow_buffer(char ** const bufp, size_t * const bufszp, size_t minimum)
 		*bufszp = 2;
 	*bufp = realloc(*bufp, *bufszp);
 	if (unlikely(!*bufp))
-		quit(1, "realloc failed in bfg_grow_buffer");
+		quithere(1, "realloc failed");
 	
 	return true;
 }
@@ -2533,10 +2536,12 @@ void notifier_init(notifier_t pipefd)
 	SOCKET listener, connecter, acceptor;
 	listener = socket(AF_INET, SOCK_STREAM, 0);
 	if (listener == INVALID_SOCKET)
-		quit(1, "Failed to create listener socket in create_notifier: %s", WindowsErrorStr(WSAGetLastError()));
+		quit(1, "Failed to create listener socket"IN_FMT_FFL": %s",
+		     __FILE__, __func__, __LINE__, WindowsErrorStr(WSAGetLastError()));
 	connecter = socket(AF_INET, SOCK_STREAM, 0);
 	if (connecter == INVALID_SOCKET)
-		quit(1, "Failed to create connect socket in create_notifier: %s", WindowsErrorStr(WSAGetLastError()));
+		quit(1, "Failed to create connect socket"IN_FMT_FFL": %s",
+		     __FILE__, __func__, __LINE__, WindowsErrorStr(WSAGetLastError()));
 	struct sockaddr_in inaddr = {
 		.sin_family = AF_INET,
 		.sin_addr = {
@@ -2549,25 +2554,30 @@ void notifier_init(notifier_t pipefd)
 		setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse));
 	}
 	if (bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr)) == SOCKET_ERROR)
-		quit(1, "Failed to bind listener socket in create_notifier: %s", WindowsErrorStr(WSAGetLastError()));
+		quit(1, "Failed to bind listener socket"IN_FMT_FFL": %s",
+		     __FILE__, __func__, __LINE__, WindowsErrorStr(WSAGetLastError()));
 	socklen_t inaddr_sz = sizeof(inaddr);
 	if (getsockname(listener, (struct sockaddr*)&inaddr, &inaddr_sz) == SOCKET_ERROR)
-		quit(1, "Failed to getsockname in create_notifier: %s", WindowsErrorStr(WSAGetLastError()));
+		quit(1, "Failed to getsockname"IN_FMT_FFL": %s",
+		     __FILE__, __func__, __LINE__, WindowsErrorStr(WSAGetLastError()));
 	if (listen(listener, 1) == SOCKET_ERROR)
-		quit(1, "Failed to listen in create_notifier: %s", WindowsErrorStr(WSAGetLastError()));
+		quit(1, "Failed to listen"IN_FMT_FFL": %s",
+		     __FILE__, __func__, __LINE__, WindowsErrorStr(WSAGetLastError()));
 	inaddr.sin_family = AF_INET;
 	inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 	if (connect(connecter, (struct sockaddr*)&inaddr, inaddr_sz) == SOCKET_ERROR)
-		quit(1, "Failed to connect in create_notifier: %s", WindowsErrorStr(WSAGetLastError()));
+		quit(1, "Failed to connect"IN_FMT_FFL": %s",
+		     __FILE__, __func__, __LINE__, WindowsErrorStr(WSAGetLastError()));
 	acceptor = accept(listener, NULL, NULL);
 	if (acceptor == INVALID_SOCKET)
-		quit(1, "Failed to accept in create_notifier: %s", WindowsErrorStr(WSAGetLastError()));
+		quit(1, "Failed to accept"IN_FMT_FFL": %s",
+		     __FILE__, __func__, __LINE__, WindowsErrorStr(WSAGetLastError()));
 	closesocket(listener);
 	pipefd[0] = connecter;
 	pipefd[1] = acceptor;
 #else
 	if (pipe(pipefd))
-		quit(1, "Failed to create pipe in create_notifier");
+		quithere(1, "Failed to create pipe");
 #endif
 }
 

+ 10 - 0
util.h

@@ -370,6 +370,16 @@ struct timeval *select_timeout(struct timeval *tvp_timeout, struct timeval *tvp_
 }
 
 
+#define _SNP2(fn, ...)  do{  \
+        int __n42 = fn(s, sz, __VA_ARGS__);  \
+        s += __n42;  \
+        sz = (sz <= __n42) ? 0 : (sz - __n42);  \
+        rv += __n42;  \
+}while(0)
+
+#define _SNP(...)  _SNP2(snprintf, __VA_ARGS__)
+
+
 #define RUNONCE(rv)  do {  \
 	static bool _runonce = false;  \
 	if (_runonce)  \