|
|
@@ -157,7 +157,14 @@ static int input_thr_id;
|
|
|
#endif
|
|
|
int gpur_thr_id;
|
|
|
static int api_thr_id;
|
|
|
+#if defined(USE_MODMINER) || defined(USE_BITFORCE)
|
|
|
+static int hotplug_thr_id;
|
|
|
+#endif
|
|
|
static int total_control_threads;
|
|
|
+bool hotplug_mode;
|
|
|
+static int new_devices;
|
|
|
+static int new_threads;
|
|
|
+static int start_devices;
|
|
|
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
pthread_mutex_t cgusb_lock;
|
|
|
@@ -173,6 +180,7 @@ static pthread_mutex_t sshare_lock;
|
|
|
|
|
|
pthread_rwlock_t netacc_lock;
|
|
|
pthread_mutex_t mining_thr_lock;
|
|
|
+pthread_mutex_t devices_lock;
|
|
|
|
|
|
static pthread_mutex_t lp_lock;
|
|
|
static pthread_cond_t lp_cond;
|
|
|
@@ -742,18 +750,24 @@ static void load_temp_cutoffs()
|
|
|
if (val < 0 || val > 200)
|
|
|
quit(1, "Invalid value passed to set temp cutoff");
|
|
|
|
|
|
+ mutex_lock(&devices_lock);
|
|
|
devices[device]->cutofftemp = val;
|
|
|
+ mutex_unlock(&devices_lock);
|
|
|
}
|
|
|
} else {
|
|
|
+ mutex_lock(&devices_lock);
|
|
|
for (i = device; i < total_devices; ++i) {
|
|
|
if (!devices[i]->cutofftemp)
|
|
|
devices[i]->cutofftemp = opt_cutofftemp;
|
|
|
}
|
|
|
+ mutex_unlock(&devices_lock);
|
|
|
return;
|
|
|
}
|
|
|
if (device <= 1) {
|
|
|
+ mutex_lock(&devices_lock);
|
|
|
for (i = device; i < total_devices; ++i)
|
|
|
devices[i]->cutofftemp = val;
|
|
|
+ mutex_unlock(&devices_lock);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1990,9 +2004,12 @@ static void curses_print_devstatus(int thr_id)
|
|
|
char displayed_hashes[16], displayed_rolling[16];
|
|
|
uint64_t dh64, dr64;
|
|
|
|
|
|
+ if (opt_compact)
|
|
|
+ return;
|
|
|
+
|
|
|
cgpu = get_thr_cgpu(thr_id);
|
|
|
|
|
|
- if (devcursor + cgpu->cgminer_id > LINES - 2 || opt_compact)
|
|
|
+ if (cgpu->cgminer_id >= start_devices || devcursor + cgpu->cgminer_id > LINES - 2)
|
|
|
return;
|
|
|
|
|
|
cgpu->utility = cgpu->accepted / total_secs * 60;
|
|
|
@@ -2782,6 +2799,16 @@ static void __kill_work(void)
|
|
|
|
|
|
applog(LOG_INFO, "Received kill message");
|
|
|
|
|
|
+#if defined(USE_MODMINER) || defined(USE_BITFORCE)
|
|
|
+ /* 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");
|
|
|
+ thr = &control_thr[hotplug_thr_id];
|
|
|
+ thr_info_cancel(thr);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
applog(LOG_DEBUG, "Killing off watchpool thread");
|
|
|
/* Kill the watchpool thread */
|
|
|
thr = &control_thr[watchpool_thr_id];
|
|
|
@@ -4015,10 +4042,14 @@ void zero_stats(void)
|
|
|
|
|
|
zero_bestshare();
|
|
|
|
|
|
- mutex_lock(&hash_lock);
|
|
|
for (i = 0; i < total_devices; ++i) {
|
|
|
- struct cgpu_info *cgpu = devices[i];
|
|
|
+ struct cgpu_info *cgpu;
|
|
|
+
|
|
|
+ mutex_lock(&devices_lock);
|
|
|
+ cgpu = devices[i];
|
|
|
+ mutex_unlock(&devices_lock);
|
|
|
|
|
|
+ mutex_lock(&hash_lock);
|
|
|
cgpu->total_mhashes = 0;
|
|
|
cgpu->accepted = 0;
|
|
|
cgpu->rejected = 0;
|
|
|
@@ -4029,8 +4060,8 @@ void zero_stats(void)
|
|
|
cgpu->diff_accepted = 0;
|
|
|
cgpu->diff_rejected = 0;
|
|
|
cgpu->last_share_diff = 0;
|
|
|
+ mutex_unlock(&hash_lock);
|
|
|
}
|
|
|
- mutex_unlock(&hash_lock);
|
|
|
}
|
|
|
|
|
|
#ifdef HAVE_CURSES
|
|
|
@@ -5936,12 +5967,17 @@ static void *watchdog_thread(void __maybe_unused *userdata)
|
|
|
}
|
|
|
|
|
|
for (i = 0; i < total_devices; ++i) {
|
|
|
- struct cgpu_info *cgpu = devices[i];
|
|
|
- struct thr_info *thr = cgpu->thr[0];
|
|
|
+ struct cgpu_info *cgpu;
|
|
|
+ struct thr_info *thr;
|
|
|
enum dev_enable *denable;
|
|
|
char dev_str[8];
|
|
|
int gpu;
|
|
|
|
|
|
+ mutex_lock(&devices_lock);
|
|
|
+ cgpu = devices[i];
|
|
|
+ mutex_unlock(&devices_lock);
|
|
|
+ thr = cgpu->thr[0];
|
|
|
+
|
|
|
if (cgpu->drv->get_stats)
|
|
|
cgpu->drv->get_stats(cgpu);
|
|
|
|
|
|
@@ -6104,8 +6140,13 @@ void print_summary(void)
|
|
|
}
|
|
|
|
|
|
applog(LOG_WARNING, "Summary of per device statistics:\n");
|
|
|
- for (i = 0; i < total_devices; ++i)
|
|
|
- log_print_status(devices[i]);
|
|
|
+ for (i = 0; i < total_devices; ++i) {
|
|
|
+ struct cgpu_info *cgpu;
|
|
|
+ mutex_lock(&devices_lock);
|
|
|
+ cgpu = devices[i];
|
|
|
+ mutex_unlock(&devices_lock);
|
|
|
+ log_print_status(cgpu);
|
|
|
+ }
|
|
|
|
|
|
if (opt_shares)
|
|
|
applog(LOG_WARNING, "Mined %d accepted shares of %d requested\n", total_accepted, opt_shares);
|
|
|
@@ -6355,7 +6396,7 @@ void enable_curses(void) {
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-/* TODO: fix need a dummy CPU device_api even if no support for CPU mining */
|
|
|
+/* TODO: fix need a dummy CPU device_drv even if no support for CPU mining */
|
|
|
#ifndef WANT_CPUMINE
|
|
|
struct device_drv cpu_drv;
|
|
|
struct device_drv cpu_drv = {
|
|
|
@@ -6386,11 +6427,18 @@ static int cgminer_id_count = 0;
|
|
|
void enable_device(struct cgpu_info *cgpu)
|
|
|
{
|
|
|
cgpu->deven = DEV_ENABLED;
|
|
|
+ mutex_lock(&devices_lock);
|
|
|
devices[cgpu->cgminer_id = cgminer_id_count++] = cgpu;
|
|
|
- mining_threads += cgpu->threads;
|
|
|
+ mutex_unlock(&devices_lock);
|
|
|
+ if (hotplug_mode) {
|
|
|
+ new_threads += cgpu->threads;
|
|
|
+ adj_width(mining_threads + new_threads, &dev_width);
|
|
|
+ } else {
|
|
|
+ mining_threads += cgpu->threads;
|
|
|
#ifdef HAVE_CURSES
|
|
|
- adj_width(mining_threads, &dev_width);
|
|
|
+ adj_width(mining_threads, &dev_width);
|
|
|
#endif
|
|
|
+ }
|
|
|
#ifdef HAVE_OPENCL
|
|
|
if (cgpu->drv->drv_id == DRIVER_OPENCL) {
|
|
|
gpu_threads += cgpu->threads;
|
|
|
@@ -6418,8 +6466,13 @@ bool add_cgpu(struct cgpu_info*cgpu)
|
|
|
cgpu->device_id = d->lastid = 0;
|
|
|
HASH_ADD_STR(devids, name, d);
|
|
|
}
|
|
|
- devices = realloc(devices, sizeof(struct cgpu_info *) * (total_devices + 2));
|
|
|
- devices[total_devices++] = cgpu;
|
|
|
+ mutex_lock(&devices_lock);
|
|
|
+ devices = realloc(devices, sizeof(struct cgpu_info *) * (total_devices + new_devices + 2));
|
|
|
+ mutex_unlock(&devices_lock);
|
|
|
+ if (hotplug_mode)
|
|
|
+ devices[total_devices + new_devices++] = cgpu;
|
|
|
+ else
|
|
|
+ devices[total_devices++] = cgpu;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -6438,6 +6491,105 @@ struct device_drv *copy_drv(struct device_drv *drv)
|
|
|
return copy;
|
|
|
}
|
|
|
|
|
|
+#if defined(USE_MODMINER) || defined(USE_BITFORCE)
|
|
|
+static void hotplug_process()
|
|
|
+{
|
|
|
+ struct thr_info *thr;
|
|
|
+ int i, j;
|
|
|
+
|
|
|
+ for (i = 0; i < new_devices; i++) {
|
|
|
+ struct cgpu_info *cgpu = devices[total_devices + i];
|
|
|
+ enable_device(cgpu);
|
|
|
+ cgpu->cgminer_stats.getwork_wait_min.tv_sec = MIN_SEC_UNSET;
|
|
|
+ cgpu->rolling = cgpu->total_mhashes = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ mutex_lock(&mining_thr_lock);
|
|
|
+ mining_thr = realloc(mining_thr, sizeof(thr) * (mining_threads + new_threads + 1));
|
|
|
+ mutex_unlock(&mining_thr_lock);
|
|
|
+ if (!mining_thr)
|
|
|
+ quit(1, "Failed to hotplug realloc mining_thr");
|
|
|
+ for (i = 0; i < new_threads; i++) {
|
|
|
+ mining_thr[mining_threads + i] = calloc(1, sizeof(*thr));
|
|
|
+ if (!mining_thr[mining_threads + i])
|
|
|
+ quit(1, "Failed to hotplug calloc mining_thr[%d]", i);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Start threads
|
|
|
+ for (i = 0; i < new_devices; ++i) {
|
|
|
+ struct cgpu_info *cgpu = devices[total_devices];
|
|
|
+ cgpu->thr = malloc(sizeof(*cgpu->thr) * (cgpu->threads+1));
|
|
|
+ cgpu->thr[cgpu->threads] = NULL;
|
|
|
+ cgpu->status = LIFE_INIT;
|
|
|
+
|
|
|
+ for (j = 0; j < cgpu->threads; ++j) {
|
|
|
+ mutex_lock(&mining_thr_lock);
|
|
|
+ thr = mining_thr[mining_threads];
|
|
|
+ mutex_unlock(&mining_thr_lock);
|
|
|
+ thr->id = mining_threads;
|
|
|
+ thr->cgpu = cgpu;
|
|
|
+ thr->device_thread = j;
|
|
|
+
|
|
|
+ thr->q = tq_new();
|
|
|
+ if (!thr->q)
|
|
|
+ quit(1, "tq_new hotplug failed in starting %s%d mining thread (#%d)", cgpu->drv->name, cgpu->device_id, total_devices);
|
|
|
+
|
|
|
+ /* Enable threads for devices set not to mine but disable
|
|
|
+ * their queue in case we wish to enable them later */
|
|
|
+ if (cgpu->deven != DEV_DISABLED) {
|
|
|
+ applog(LOG_DEBUG, "Pushing hotplug ping to thread %d", thr->id);
|
|
|
+ tq_push(thr->q, &ping);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cgpu->drv->thread_prepare && !cgpu->drv->thread_prepare(thr))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ thread_reportout(thr);
|
|
|
+
|
|
|
+ if (unlikely(thr_info_create(thr, NULL, miner_thread, thr)))
|
|
|
+ quit(1, "hotplug thread %d create failed", thr->id);
|
|
|
+
|
|
|
+ cgpu->thr[j] = thr;
|
|
|
+
|
|
|
+ mining_threads++;
|
|
|
+ }
|
|
|
+ total_devices++;
|
|
|
+ applog(LOG_WARNING, "Hotplug: %s added %s %i", cgpu->drv->dname, cgpu->drv->name, cgpu->device_id);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void *hotplug_thread(void __maybe_unused *userdata)
|
|
|
+{
|
|
|
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
|
|
+
|
|
|
+ RenameThread("hotplug");
|
|
|
+
|
|
|
+ hotplug_mode = true;
|
|
|
+
|
|
|
+ while (0x2a) {
|
|
|
+ sleep(5);
|
|
|
+
|
|
|
+// Version 0.1 just add the devices on - worry about using nodev later
|
|
|
+
|
|
|
+ new_devices = 0;
|
|
|
+ new_threads = 0;
|
|
|
+
|
|
|
+#ifdef USE_BITFORCE
|
|
|
+ bitforce_drv.drv_detect();
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef USE_MODMINER
|
|
|
+ modminer_drv.drv_detect();
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (new_devices)
|
|
|
+ hotplug_process();
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
int main(int argc, char *argv[])
|
|
|
{
|
|
|
bool pools_active = false;
|
|
|
@@ -6479,6 +6631,7 @@ int main(int argc, char *argv[])
|
|
|
rwlock_init(&blk_lock);
|
|
|
rwlock_init(&netacc_lock);
|
|
|
mutex_init(&mining_thr_lock);
|
|
|
+ mutex_init(&devices_lock);
|
|
|
|
|
|
mutex_init(&lp_lock);
|
|
|
if (unlikely(pthread_cond_init(&lp_cond, NULL)))
|
|
|
@@ -6714,6 +6867,8 @@ int main(int argc, char *argv[])
|
|
|
if (!total_devices)
|
|
|
quit(1, "All devices disabled, cannot mine!");
|
|
|
|
|
|
+ start_devices = total_devices;
|
|
|
+
|
|
|
load_temp_cutoffs();
|
|
|
|
|
|
for (i = 0; i < total_devices; ++i)
|
|
|
@@ -6772,7 +6927,7 @@ int main(int argc, char *argv[])
|
|
|
quit(1, "Failed to calloc mining_thr[%d]", i);
|
|
|
}
|
|
|
|
|
|
- total_control_threads = 7;
|
|
|
+ total_control_threads = 8;
|
|
|
control_thr = calloc(total_control_threads, sizeof(*thr));
|
|
|
if (!control_thr)
|
|
|
quit(1, "Failed to calloc control_thr");
|
|
|
@@ -6947,11 +7102,21 @@ begin_bench:
|
|
|
if (thr_info_create(thr, NULL, api_thread, thr))
|
|
|
quit(1, "API thread create failed");
|
|
|
|
|
|
+#if defined(USE_MODMINER) || defined(USE_BITFORCE)
|
|
|
+ if (!opt_scrypt) {
|
|
|
+ hotplug_thr_id = 6;
|
|
|
+ thr = &control_thr[hotplug_thr_id];
|
|
|
+ if (thr_info_create(thr, NULL, hotplug_thread, thr))
|
|
|
+ quit(1, "hotplug thread create failed");
|
|
|
+ pthread_detach(thr->pth);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
#ifdef HAVE_CURSES
|
|
|
/* Create curses input thread for keyboard input. Create this last so
|
|
|
* that we know all threads are created since this can call kill_work
|
|
|
- * to try and shut down ll previous threads. */
|
|
|
- input_thr_id = 6;
|
|
|
+ * to try and shut down all previous threads. */
|
|
|
+ input_thr_id = 7;
|
|
|
thr = &control_thr[input_thr_id];
|
|
|
if (thr_info_create(thr, NULL, input_thread, thr))
|
|
|
quit(1, "input thread create failed");
|
|
|
@@ -6959,8 +7124,8 @@ begin_bench:
|
|
|
#endif
|
|
|
|
|
|
/* Just to be sure */
|
|
|
- if (total_control_threads != 7)
|
|
|
- quit(1, "incorrect total_control_threads (%d) should be 7", total_control_threads);
|
|
|
+ if (total_control_threads != 8)
|
|
|
+ quit(1, "incorrect total_control_threads (%d) should be 8", total_control_threads);
|
|
|
|
|
|
/* Once everything is set up, main() becomes the getwork scheduler */
|
|
|
while (42) {
|