Commit 31e8ebaffaec734c48dd61ff2425674e906de2b4

Con Kolivas 2013-10-19T16:08:17

Merge branch 'master' into hashfast

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
diff --git a/NEWS b/NEWS
index d430852..f4d8f5b 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,28 @@
+Version 3.6.4 - 18th October 2013
+
+- Fixing the memory leak for remaining semaphores means we can go back to using
+async transfers on other OSes with our own timeout management again.
+- Use the forcelog function on shutdown to cope with indeterminate console lock
+states due to killing of threads.
+- Add a forcelog variant of applog which invalidates any console lock to force
+output.
+- Send pthread_cancel to failed completion_timeout that has timed out.
+- Simplify queued hashtable by storing unqueued work separately in a single
+pointer.
+- bflsc use getinfo chip parallelization if it is present
+- bflsc - fix brackets so [Chips] isn't always null
+- Remove unused variables.
+- Use cgcompletion timeouts for the unreliable shutdown functions on kill_work.
+- Fix cgcompletion return code and free on successful completion.
+- Provide a cg_completion_timeout helper function for unreliable functions that
+takes arbitrary functions and parameters and reliably returns.
+- Perform sync transfers on shutdown to allow final transfers to complete.
+- Destroy cgsems used after transfers to not leave open files on osx.
+- klondike rewrite work control
+- allow __work_complete() access
+- miner.h allow devices to tv_stamp work
+
+
 Version 3.6.3 - 17th October 2013
 
 - API add 'MHS %ds' to 'summary'
diff --git a/cgminer.c b/cgminer.c
index 6679448..a4007f6 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -427,7 +427,7 @@ static void applog_and_exit(const char *fmt, ...)
 	va_start(ap, fmt);
 	vsnprintf(exit_buf, sizeof(exit_buf), fmt, ap);
 	va_end(ap);
-	_applog(LOG_ERR, exit_buf);
+	_applog(LOG_ERR, exit_buf, true);
 	exit(1);
 }
 
@@ -3166,7 +3166,7 @@ static void kill_mining(void)
 	struct thr_info *thr;
 	int i;
 
-	applog(LOG_DEBUG, "Killing off mining threads");
+	forcelog(LOG_DEBUG, "Killing off mining threads");
 	/* Kill the mining threads*/
 	for (i = 0; i < mining_threads; i++) {
 		pthread_t *pth = NULL;
@@ -3193,29 +3193,29 @@ static void __kill_work(void)
 	if (!successful_connect)
 		return;
 
-	applog(LOG_INFO, "Received kill message");
+	forcelog(LOG_INFO, "Received kill message");
 
 #ifdef USE_USBUTILS
 	/* Best to get rid of it first so it doesn't
 	 * try to create any new devices */
 	if (!opt_scrypt) {
-		applog(LOG_DEBUG, "Killing off HotPlug thread");
+		forcelog(LOG_DEBUG, "Killing off HotPlug thread");
 		thr = &control_thr[hotplug_thr_id];
 		kill_timeout(thr);
 	}
 #endif
 
-	applog(LOG_DEBUG, "Killing off watchpool thread");
+	forcelog(LOG_DEBUG, "Killing off watchpool thread");
 	/* Kill the watchpool thread */
 	thr = &control_thr[watchpool_thr_id];
 	kill_timeout(thr);
 
-	applog(LOG_DEBUG, "Killing off watchdog thread");
+	forcelog(LOG_DEBUG, "Killing off watchdog thread");
 	/* Kill the watchdog thread */
 	thr = &control_thr[watchdog_thr_id];
 	kill_timeout(thr);
 
-	applog(LOG_DEBUG, "Shutting down mining threads");
+	forcelog(LOG_DEBUG, "Shutting down mining threads");
 	for (i = 0; i < mining_threads; i++) {
 		struct cgpu_info *cgpu;
 
@@ -3233,12 +3233,12 @@ static void __kill_work(void)
 
 	cg_completion_timeout(&kill_mining, NULL, 3000);
 
-	applog(LOG_DEBUG, "Killing off stage thread");
+	forcelog(LOG_DEBUG, "Killing off stage thread");
 	/* Stop the others */
 	thr = &control_thr[stage_thr_id];
 	kill_timeout(thr);
 
-	applog(LOG_DEBUG, "Killing off API thread");
+	forcelog(LOG_DEBUG, "Killing off API thread");
 	thr = &control_thr[api_thr_id];
 	kill_timeout(thr);
 
@@ -3246,10 +3246,10 @@ static void __kill_work(void)
 	/* Release USB resources in case it's a restart
 	 * and not a QUIT */
 	if (!opt_scrypt) {
-		applog(LOG_DEBUG, "Releasing all USB devices");
+		forcelog(LOG_DEBUG, "Releasing all USB devices");
 		cg_completion_timeout(&usb_cleanup, NULL, 1000);
 
-		applog(LOG_DEBUG, "Killing off usbres thread");
+		forcelog(LOG_DEBUG, "Killing off usbres thread");
 		thr = &control_thr[usbres_thr_id];
 		kill_timeout(thr);
 	}
diff --git a/configure.ac b/configure.ac
index 39b74cc..27c68ba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [3])
 m4_define([v_min], [6])
-m4_define([v_mic], [3])
+m4_define([v_mic], [4])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([lt_rev], m4_eval(v_maj + v_min))
diff --git a/logging.c b/logging.c
index d00600f..52eb9ef 100644
--- a/logging.c
+++ b/logging.c
@@ -21,11 +21,17 @@ bool opt_log_output = false;
 /* per default priorities higher than LOG_NOTICE are logged */
 int opt_log_level = LOG_NOTICE;
 
-static void my_log_curses(int prio, const char *datetime, const char *str)
+static void my_log_curses(int prio, const char *datetime, const char *str, bool force)
 {
 	if (opt_quiet && prio != LOG_ERR)
 		return;
 
+	/* Mutex could be locked by dead thread on shutdown so forcelog will
+	 * invalidate any console lock status. */
+	if (force) {
+		mutex_trylock(&console_lock);
+		mutex_unlock(&console_lock);
+	}
 #ifdef HAVE_CURSES
 	extern bool use_curses;
 	if (use_curses && log_curses_only(prio, datetime, str))
@@ -44,7 +50,7 @@ static void my_log_curses(int prio, const char *datetime, const char *str)
 /*
  * log function
  */
-void _applog(int prio, const char *str)
+void _applog(int prio, const char *str, bool force)
 {
 #ifdef HAVE_SYSLOG_H
 	if (use_syslog) {
@@ -77,6 +83,6 @@ void _applog(int prio, const char *str)
 			fflush(stderr);
 		}
 
-		my_log_curses(prio, datetime, str);
+		my_log_curses(prio, datetime, str, force);
 	}
 }
diff --git a/logging.h b/logging.h
index 2956452..4d8a250 100644
--- a/logging.h
+++ b/logging.h
@@ -28,7 +28,7 @@ extern int opt_log_level;
 
 #define LOGBUFSIZ 256
 
-extern void _applog(int prio, const char *str);
+extern void _applog(int prio, const char *str, bool force);
 
 #define IN_FMT_FFL " in %s %s():%d"
 
@@ -37,7 +37,7 @@ extern void _applog(int prio, const char *str);
 		if (use_syslog || opt_log_output || prio <= opt_log_level) { \
 			char tmp42[LOGBUFSIZ]; \
 			snprintf(tmp42, sizeof(tmp42), fmt, ##__VA_ARGS__); \
-			_applog(prio, tmp42); \
+			_applog(prio, tmp42, false); \
 		} \
 	} \
 } while (0)
@@ -47,7 +47,17 @@ extern void _applog(int prio, const char *str);
 		if (use_syslog || opt_log_output || prio <= opt_log_level) { \
 			char tmp42[_SIZ]; \
 			snprintf(tmp42, sizeof(tmp42), fmt, ##__VA_ARGS__); \
-			_applog(prio, tmp42); \
+			_applog(prio, tmp42, false); \
+		} \
+	} \
+} while (0)
+
+#define forcelog(prio, fmt, ...) do { \
+	if (opt_debug || prio != LOG_DEBUG) { \
+		if (use_syslog || opt_log_output || prio <= opt_log_level) { \
+			char tmp42[LOGBUFSIZ]; \
+			snprintf(tmp42, sizeof(tmp42), fmt, ##__VA_ARGS__); \
+			_applog(prio, tmp42, true); \
 		} \
 	} \
 } while (0)
@@ -56,7 +66,7 @@ extern void _applog(int prio, const char *str);
 	if (fmt) { \
 		char tmp42[LOGBUFSIZ]; \
 		snprintf(tmp42, sizeof(tmp42), fmt, ##__VA_ARGS__); \
-		_applog(LOG_ERR, tmp42); \
+		_applog(LOG_ERR, tmp42, true); \
 	} \
 	_quit(status); \
 } while (0)
@@ -66,7 +76,7 @@ extern void _applog(int prio, const char *str);
 		char tmp42[LOGBUFSIZ]; \
 		snprintf(tmp42, sizeof(tmp42), fmt IN_FMT_FFL, \
 				##__VA_ARGS__, __FILE__, __func__, __LINE__); \
-		_applog(LOG_ERR, tmp42); \
+		_applog(LOG_ERR, tmp42, true); \
 	} \
 	_quit(status); \
 } while (0)
@@ -76,7 +86,7 @@ extern void _applog(int prio, const char *str);
 		char tmp42[LOGBUFSIZ]; \
 		snprintf(tmp42, sizeof(tmp42), fmt IN_FMT_FFL, \
 				##__VA_ARGS__, _file, _func, _line); \
-		_applog(LOG_ERR, tmp42); \
+		_applog(LOG_ERR, tmp42, true); \
 	} \
 	_quit(status); \
 } while (0)
diff --git a/usbutils.c b/usbutils.c
index d66d722..6ad2245 100644
--- a/usbutils.c
+++ b/usbutils.c
@@ -968,7 +968,7 @@ void usb_all(int level)
 		for (i = 0; i < count; i++)
 			usb_full(&j, list[i], &buf, &off, &len, level);
 
-		_applog(LOG_WARNING, buf);
+		_applog(LOG_WARNING, buf, false);
 
 		free(buf);
 
@@ -2267,6 +2267,33 @@ static void LIBUSB_CALL transfer_callback(struct libusb_transfer *transfer)
 	cgsem_post(&ut->cgsem);
 }
 
+static int usb_transfer_toerr(int ret)
+{
+	switch (ret) {
+		default:
+		case LIBUSB_TRANSFER_COMPLETED:
+			ret = LIBUSB_SUCCESS;
+			break;
+		case LIBUSB_TRANSFER_ERROR:
+			ret = LIBUSB_ERROR_IO;
+			break;
+		case LIBUSB_TRANSFER_TIMED_OUT:
+		case LIBUSB_TRANSFER_CANCELLED:
+			ret = LIBUSB_ERROR_TIMEOUT;
+			break;
+		case LIBUSB_TRANSFER_STALL:
+			ret = LIBUSB_ERROR_PIPE;
+			break;
+		case LIBUSB_TRANSFER_NO_DEVICE:
+			ret = LIBUSB_ERROR_NO_DEVICE;
+			break;
+		case LIBUSB_TRANSFER_OVERFLOW:
+			ret = LIBUSB_ERROR_OVERFLOW;
+			break;
+	}
+	return ret;
+}
+
 /* Wait for callback function to tell us it has finished the USB transfer, but
  * use our own timer to cancel the request if we go beyond the timeout. */
 static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int timeout)
@@ -2283,8 +2310,7 @@ static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int
 		cgsem_wait(&ut->cgsem);
 	}
 	ret = transfer->status;
-	if (ret == LIBUSB_TRANSFER_CANCELLED || ret == LIBUSB_TRANSFER_TIMED_OUT)
-		ret = LIBUSB_ERROR_TIMEOUT;
+	ret = usb_transfer_toerr(ret);
 
 	/* No need to sort out mutexes here since they won't be reused */
 	*transferred = transfer->actual_length;
@@ -2331,15 +2357,9 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
 	USBDEBUG("USB debug: @usb_bulk_transfer(%s (nodev=%s),intinfo=%d,epinfo=%d,data=%p,length=%d,timeout=%u,mode=%d,cmd=%s,seq=%d) endpoint=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), intinfo, epinfo, data, length, timeout, mode, usb_cmdname(cmd), seq, (int)endpoint);
 
 	init_usb_transfer(&ut);
-#ifdef LINUX
 	/* We give the transfer no timeout since we manage timeouts ourself */
 	libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length,
 				  transfer_callback, &ut, 0);
-#else
-	/* All other OSes not so lucky */
-	libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length,
-				  transfer_callback, &ut, timeout);
-#endif
 	STATS_TIMEVAL(&tv_start);
 	cg_rlock(&cgusb_fd_lock);
 	err = libusb_submit_transfer(ut.transfer);
@@ -2357,7 +2377,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
 				cgpu->drv->name, cgpu->device_id,
 				usb_cmdname(cmd), *transferred, err, errn);
 
-	if (err == LIBUSB_ERROR_PIPE || err == LIBUSB_TRANSFER_STALL) {
+	if (err == LIBUSB_ERROR_PIPE) {
 		int retries = 0;
 
 		do {
@@ -2775,25 +2795,19 @@ static int usb_control_transfer(struct cgpu_info *cgpu, libusb_device_handle *de
 				  wIndex, wLength);
 	if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT)
 		memcpy(buf + LIBUSB_CONTROL_SETUP_SIZE, buffer, wLength);
-#ifdef LINUX
 	libusb_fill_control_transfer(ut.transfer, dev_handle, buf, transfer_callback,
 				     &ut, 0);
-#else
-	libusb_fill_control_transfer(ut.transfer, dev_handle, buf, transfer_callback,
-				     &ut, timeout);
-#endif
 	err = libusb_submit_transfer(ut.transfer);
 	if (!err)
 		err = callback_wait(&ut, &transferred, timeout);
-	if (err == LIBUSB_TRANSFER_COMPLETED && transferred) {
+	if (err == LIBUSB_SUCCESS && transferred) {
 		if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
 			memcpy(buffer, libusb_control_transfer_get_data(ut.transfer),
 			       transferred);
 		err = transferred;
 		goto out;
 	}
-	if ((err) == LIBUSB_TRANSFER_CANCELLED)
-		err = LIBUSB_ERROR_TIMEOUT;
+	err = usb_transfer_toerr(err);
 out:
 	complete_usb_transfer(&ut);
 	return err;
diff --git a/util.c b/util.c
index 48c9225..36bced2 100644
--- a/util.c
+++ b/util.c
@@ -2410,7 +2410,7 @@ void _cgsem_wait(cgsem_t *cgsem, const char *file, const char *func, const int l
 		applog(LOG_WARNING, "Failed to read errno=%d" IN_FMT_FFL, errno, file, func, line);
 }
 
-void _cgsem_destroy(cgsem_t *cgsem)
+void cgsem_destroy(cgsem_t *cgsem)
 {
 	close(cgsem->pipefd[1]);
 	close(cgsem->pipefd[0]);
@@ -2480,7 +2480,7 @@ int _cgsem_mswait(cgsem_t *cgsem, int ms, const char *file, const char *func, co
 	return 0;
 }
 
-void _cgsem_destroy(cgsem_t *cgsem)
+void cgsem_destroy(cgsem_t *cgsem)
 {
 	sem_destroy(cgsem);
 }
@@ -2499,7 +2499,7 @@ void *completion_thread(void *arg)
 {
 	struct cg_completion *cgc = (struct cg_completion *)arg;
 
-	pthread_detach(pthread_self());
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 	cgc->fn(cgc->fnarg);
 	cgsem_post(&cgc->cgsem);
 
@@ -2522,7 +2522,10 @@ bool cg_completion_timeout(void *fn, void *fnarg, int timeout)
 	pthread_create(&pthread, NULL, completion_thread, (void *)cgc);
 
 	ret = cgsem_mswait(&cgc->cgsem, timeout);
-	if (!ret)
+	if (!ret) {
+		pthread_join(pthread, NULL);
 		free(cgc);
+	} else
+		pthread_cancel(pthread);
 	return !ret;
 }
diff --git a/util.h b/util.h
index fa4e7ed..ae4a345 100644
--- a/util.h
+++ b/util.h
@@ -134,14 +134,13 @@ void _cgsem_init(cgsem_t *cgsem, const char *file, const char *func, const int l
 void _cgsem_post(cgsem_t *cgsem, const char *file, const char *func, const int line);
 void _cgsem_wait(cgsem_t *cgsem, const char *file, const char *func, const int line);
 int _cgsem_mswait(cgsem_t *cgsem, int ms, const char *file, const char *func, const int line);
-void _cgsem_destroy(cgsem_t *cgsem);
+void cgsem_destroy(cgsem_t *cgsem);
 bool cg_completion_timeout(void *fn, void *fnarg, int timeout);
 
 #define cgsem_init(_sem) _cgsem_init(_sem, __FILE__, __func__, __LINE__)
 #define cgsem_post(_sem) _cgsem_post(_sem, __FILE__, __func__, __LINE__)
 #define cgsem_wait(_sem) _cgsem_wait(_sem, __FILE__, __func__, __LINE__)
 #define cgsem_mswait(_sem, _timeout) _cgsem_mswait(_sem, _timeout, __FILE__, __func__, __LINE__)
-#define cgsem_destroy(_sem) _cgsem_destroy(_sem)
 
 /* Align a size_t to 4 byte boundaries for fussy arches */
 static inline void align_len(size_t *len)