|
@@ -3218,8 +3218,6 @@ static void __kill_work(void)
|
|
|
/* Release USB resources in case it's a restart
|
|
/* Release USB resources in case it's a restart
|
|
|
* and not a QUIT */
|
|
* and not a QUIT */
|
|
|
if (!opt_scrypt) {
|
|
if (!opt_scrypt) {
|
|
|
- usb_polling = false;
|
|
|
|
|
-
|
|
|
|
|
applog(LOG_DEBUG, "Releasing all USB devices");
|
|
applog(LOG_DEBUG, "Releasing all USB devices");
|
|
|
usb_cleanup();
|
|
usb_cleanup();
|
|
|
|
|
|
|
@@ -4006,15 +4004,15 @@ static void set_blockdiff(const struct work *work)
|
|
|
static bool test_work_current(struct work *work)
|
|
static bool test_work_current(struct work *work)
|
|
|
{
|
|
{
|
|
|
bool ret = true;
|
|
bool ret = true;
|
|
|
- char *hexstr;
|
|
|
|
|
|
|
+ char hexstr[20];
|
|
|
|
|
|
|
|
if (work->mandatory)
|
|
if (work->mandatory)
|
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
|
|
/* Hack to work around dud work sneaking into test */
|
|
/* Hack to work around dud work sneaking into test */
|
|
|
- hexstr = bin2hex(work->data + 8, 18);
|
|
|
|
|
|
|
+ __bin2hex(hexstr, work->data + 8, 18);
|
|
|
if (!strncmp(hexstr, "000000000000000000000000000000000000", 36))
|
|
if (!strncmp(hexstr, "000000000000000000000000000000000000", 36))
|
|
|
- goto out_free;
|
|
|
|
|
|
|
+ return ret;
|
|
|
|
|
|
|
|
/* Search to see if this block exists yet and if not, consider it a
|
|
/* Search to see if this block exists yet and if not, consider it a
|
|
|
* new block and set the current block details to this one */
|
|
* new block and set the current block details to this one */
|
|
@@ -4049,7 +4047,7 @@ static bool test_work_current(struct work *work)
|
|
|
applog(LOG_DEBUG, "Deleted block %d from database", deleted_block);
|
|
applog(LOG_DEBUG, "Deleted block %d from database", deleted_block);
|
|
|
set_curblock(hexstr, work->data);
|
|
set_curblock(hexstr, work->data);
|
|
|
if (unlikely(new_blocks == 1))
|
|
if (unlikely(new_blocks == 1))
|
|
|
- goto out_free;
|
|
|
|
|
|
|
+ return ret;
|
|
|
|
|
|
|
|
work->work_block = ++work_block;
|
|
work->work_block = ++work_block;
|
|
|
|
|
|
|
@@ -4072,8 +4070,6 @@ static bool test_work_current(struct work *work)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
work->longpoll = false;
|
|
work->longpoll = false;
|
|
|
-out_free:
|
|
|
|
|
- free(hexstr);
|
|
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -5467,8 +5463,8 @@ static void *stratum_sthread(void *userdata)
|
|
|
quit(1, "Failed to create stratum_q in stratum_sthread");
|
|
quit(1, "Failed to create stratum_q in stratum_sthread");
|
|
|
|
|
|
|
|
while (42) {
|
|
while (42) {
|
|
|
|
|
+ char noncehex[12], nonce2hex[20];
|
|
|
struct stratum_share *sshare;
|
|
struct stratum_share *sshare;
|
|
|
- char *noncehex, *nonce2hex;
|
|
|
|
|
uint32_t *hash32, nonce;
|
|
uint32_t *hash32, nonce;
|
|
|
char s[1024], nonce2[8];
|
|
char s[1024], nonce2[8];
|
|
|
struct work *work;
|
|
struct work *work;
|
|
@@ -5497,7 +5493,7 @@ static void *stratum_sthread(void *userdata)
|
|
|
/* This work item is freed in parse_stratum_response */
|
|
/* This work item is freed in parse_stratum_response */
|
|
|
sshare->work = work;
|
|
sshare->work = work;
|
|
|
nonce = *((uint32_t *)(work->data + 76));
|
|
nonce = *((uint32_t *)(work->data + 76));
|
|
|
- noncehex = bin2hex((const unsigned char *)&nonce, 4);
|
|
|
|
|
|
|
+ __bin2hex(noncehex, (const unsigned char *)&nonce, 4);
|
|
|
memset(s, 0, 1024);
|
|
memset(s, 0, 1024);
|
|
|
|
|
|
|
|
mutex_lock(&sshare_lock);
|
|
mutex_lock(&sshare_lock);
|
|
@@ -5508,15 +5504,11 @@ static void *stratum_sthread(void *userdata)
|
|
|
memset(nonce2, 0, 8);
|
|
memset(nonce2, 0, 8);
|
|
|
/* We only use uint32_t sized nonce2 increments internally */
|
|
/* We only use uint32_t sized nonce2 increments internally */
|
|
|
memcpy(nonce2, &work->nonce2, sizeof(uint32_t));
|
|
memcpy(nonce2, &work->nonce2, sizeof(uint32_t));
|
|
|
- nonce2hex = bin2hex((const unsigned char *)nonce2, work->nonce2_len);
|
|
|
|
|
- if (unlikely(!nonce2hex))
|
|
|
|
|
- quit(1, "Failed to bin2hex nonce2 in stratum_thread");
|
|
|
|
|
|
|
+ __bin2hex(nonce2hex, (const unsigned char *)nonce2, work->nonce2_len);
|
|
|
|
|
|
|
|
snprintf(s, sizeof(s),
|
|
snprintf(s, sizeof(s),
|
|
|
"{\"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\": %d, \"method\": \"mining.submit\"}",
|
|
"{\"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\": %d, \"method\": \"mining.submit\"}",
|
|
|
pool->rpc_user, work->job_id, nonce2hex, work->ntime, noncehex, sshare->id);
|
|
pool->rpc_user, work->job_id, nonce2hex, work->ntime, noncehex, sshare->id);
|
|
|
- free(noncehex);
|
|
|
|
|
- free(nonce2hex);
|
|
|
|
|
|
|
|
|
|
applog(LOG_INFO, "Submitting share %08lx to pool %d",
|
|
applog(LOG_INFO, "Submitting share %08lx to pool %d",
|
|
|
(long unsigned int)htole32(hash32[6]), pool->pool_no);
|
|
(long unsigned int)htole32(hash32[6]), pool->pool_no);
|
|
@@ -5974,7 +5966,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
|
|
|
cgtime(&work->tv_staged);
|
|
cgtime(&work->tv_staged);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static struct work *get_work(struct thr_info *thr, const int thr_id)
|
|
|
|
|
|
|
+struct work *get_work(struct thr_info *thr, const int thr_id)
|
|
|
{
|
|
{
|
|
|
struct work *work = NULL;
|
|
struct work *work = NULL;
|
|
|
|
|
|
|
@@ -6532,6 +6524,53 @@ void hash_queued_work(struct thr_info *mythr)
|
|
|
cgpu->deven = DEV_DISABLED;
|
|
cgpu->deven = DEV_DISABLED;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/* This version of hash_work is for devices drivers that want to do their own
|
|
|
|
|
+ * work management entirely, usually by using get_work(). Note that get_work
|
|
|
|
|
+ * is a blocking function and will wait indefinitely if no work is available
|
|
|
|
|
+ * so this must be taken into consideration in the driver. */
|
|
|
|
|
+void hash_driver_work(struct thr_info *mythr)
|
|
|
|
|
+{
|
|
|
|
|
+ struct timeval tv_start = {0, 0}, tv_end;
|
|
|
|
|
+ struct cgpu_info *cgpu = mythr->cgpu;
|
|
|
|
|
+ struct device_drv *drv = cgpu->drv;
|
|
|
|
|
+ const int thr_id = mythr->id;
|
|
|
|
|
+ int64_t hashes_done = 0;
|
|
|
|
|
+
|
|
|
|
|
+ while (likely(!cgpu->shutdown)) {
|
|
|
|
|
+ struct timeval diff;
|
|
|
|
|
+ int64_t hashes;
|
|
|
|
|
+
|
|
|
|
|
+ mythr->work_restart = false;
|
|
|
|
|
+
|
|
|
|
|
+ hashes = drv->scanwork(mythr);
|
|
|
|
|
+
|
|
|
|
|
+ if (unlikely(hashes == -1 )) {
|
|
|
|
|
+ applog(LOG_ERR, "%s %d failure, disabling!", drv->name, cgpu->device_id);
|
|
|
|
|
+ cgpu->deven = DEV_DISABLED;
|
|
|
|
|
+ dev_error(cgpu, REASON_THREAD_ZERO_HASH);
|
|
|
|
|
+ mt_disable(mythr, thr_id, drv);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ hashes_done += hashes;
|
|
|
|
|
+ cgtime(&tv_end);
|
|
|
|
|
+ timersub(&tv_end, &tv_start, &diff);
|
|
|
|
|
+ /* Update the hashmeter at most 5 times per second */
|
|
|
|
|
+ if ((hashes_done && (diff.tv_sec > 0 || diff.tv_usec > 200000)) ||
|
|
|
|
|
+ diff.tv_sec >= opt_log_interval) {
|
|
|
|
|
+ hashmeter(thr_id, &diff, hashes_done);
|
|
|
|
|
+ hashes_done = 0;
|
|
|
|
|
+ copy_time(&tv_start, &tv_end);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (unlikely(mythr->pause || cgpu->deven != DEV_ENABLED))
|
|
|
|
|
+ mt_disable(mythr, thr_id, drv);
|
|
|
|
|
+
|
|
|
|
|
+ if (unlikely(mythr->work_restart))
|
|
|
|
|
+ drv->flush_work(cgpu);
|
|
|
|
|
+ }
|
|
|
|
|
+ cgpu->deven = DEV_DISABLED;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void *miner_thread(void *userdata)
|
|
void *miner_thread(void *userdata)
|
|
|
{
|
|
{
|
|
|
struct thr_info *mythr = userdata;
|
|
struct thr_info *mythr = userdata;
|
|
@@ -7180,6 +7219,8 @@ static void clean_up(void)
|
|
|
clear_adl(nDevs);
|
|
clear_adl(nDevs);
|
|
|
#endif
|
|
#endif
|
|
|
#ifdef USE_USBUTILS
|
|
#ifdef USE_USBUTILS
|
|
|
|
|
+ usb_polling = false;
|
|
|
|
|
+ pthread_join(usb_poll_thread, NULL);
|
|
|
libusb_exit(NULL);
|
|
libusb_exit(NULL);
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
@@ -7751,11 +7792,12 @@ static void probe_pools(void)
|
|
|
#ifdef USE_USBUTILS
|
|
#ifdef USE_USBUTILS
|
|
|
static void *libusb_poll_thread(void __maybe_unused *arg)
|
|
static void *libusb_poll_thread(void __maybe_unused *arg)
|
|
|
{
|
|
{
|
|
|
|
|
+ struct timeval tv_end = {0, 200000};
|
|
|
|
|
+
|
|
|
RenameThread("usbpoll");
|
|
RenameThread("usbpoll");
|
|
|
|
|
|
|
|
- pthread_detach(pthread_self());
|
|
|
|
|
while (usb_polling)
|
|
while (usb_polling)
|
|
|
- libusb_handle_events(NULL);
|
|
|
|
|
|
|
+ libusb_handle_events_timeout_completed(NULL, &tv_end, NULL);
|
|
|
|
|
|
|
|
return NULL;
|
|
return NULL;
|
|
|
}
|
|
}
|