Use a linked list for all usb transfers instead of just cancellable ones.
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
diff --git a/cgminer.c b/cgminer.c
index cb4fa45..44b51c5 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -7831,7 +7831,6 @@ static void probe_pools(void)
static void *libusb_poll_thread(void __maybe_unused *arg)
{
struct timeval tv_end = {1, 0};
- bool inprogress = false;
RenameThread("usbpoll");
@@ -7843,14 +7842,9 @@ static void *libusb_poll_thread(void __maybe_unused *arg)
/* Keep event handling going until there are no async transfers in
* flight. */
- do {
+ while (async_usb_transfers())
libusb_handle_events_timeout_completed(NULL, &tv_end, NULL);
- cg_rlock(&cgusb_fd_lock);
- inprogress = !!cgusb_transfers;
- cg_runlock(&cgusb_fd_lock);
- } while (inprogress);
-
return NULL;
}
diff --git a/usbutils.c b/usbutils.c
index 5f41fd0..201bd89 100644
--- a/usbutils.c
+++ b/usbutils.c
@@ -93,12 +93,10 @@
.epinfos = _epinfosy \
}
-/* Keep a global counter of how many async transfers are in place to avoid
- * shutting down the usb polling thread while they exist. */
-int cgusb_transfers;
-
-/* Linked list of all cancellable transfers. */
-static struct list_head ct_list;
+/* Linked list of all async transfers in progress. Protected by cgusb_fd_lock.
+ * This allows us to not stop the usb polling thread till all are complete, and
+ * to find cancellable transfers. */
+static struct list_head ut_list;
#ifdef USE_BFLSC
// N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1
@@ -2219,6 +2217,17 @@ struct usb_transfer {
struct list_head list;
};
+bool async_usb_transfers(void)
+{
+ bool ret;
+
+ cg_rlock(&cgusb_fd_lock);
+ ret = !list_empty(&ut_list);
+ cg_runlock(&cgusb_fd_lock);
+
+ return ret;
+}
+
/* Cancellable transfers should only be labelled as such if it is safe for them
* to effectively mimic timing out early. This flag is usually used to signify
* a read is waiting on a non-critical response that takes a long time and the
@@ -2228,12 +2237,15 @@ void cancel_usb_transfers(void)
struct usb_transfer *ut;
int cancellations = 0;
- cg_rlock(&cgusb_fd_lock);
- list_for_each_entry(ut, &ct_list, list) {
- libusb_cancel_transfer(ut->transfer);
- cancellations++;
+ cg_wlock(&cgusb_fd_lock);
+ list_for_each_entry(ut, &ut_list, list) {
+ if (ut->cancellable) {
+ ut->cancellable = false;
+ libusb_cancel_transfer(ut->transfer);
+ cancellations++;
+ }
}
- cg_runlock(&cgusb_fd_lock);
+ cg_wunlock(&cgusb_fd_lock);
if (cancellations)
applog(LOG_DEBUG, "Cancelled %d USB transfers", cancellations);
@@ -2250,20 +2262,19 @@ static void init_usb_transfer(struct usb_transfer *ut)
static void complete_usb_transfer(struct usb_transfer *ut)
{
- cgsem_destroy(&ut->cgsem);
- libusb_free_transfer(ut->transfer);
-
cg_wlock(&cgusb_fd_lock);
- cgusb_transfers--;
- if (ut->cancellable)
- list_del(&ut->list);
+ list_del(&ut->list);
cg_wunlock(&cgusb_fd_lock);
+
+ cgsem_destroy(&ut->cgsem);
+ libusb_free_transfer(ut->transfer);
}
static void LIBUSB_CALL transfer_callback(struct libusb_transfer *transfer)
{
struct usb_transfer *ut = transfer->user_data;
+ ut->cancellable = false;
cgsem_post(&ut->cgsem);
}
@@ -2323,15 +2334,12 @@ static int usb_submit_transfer(struct usb_transfer *ut, struct libusb_transfer *
{
int err;
+ INIT_LIST_HEAD(&ut->list);
+ ut->cancellable = cancellable;
+
cg_wlock(&cgusb_fd_lock);
err = libusb_submit_transfer(transfer);
- cgusb_transfers++;
- if (cancellable) {
- ut->cancellable = true;
- INIT_LIST_HEAD(&ut->list);
- list_add(&ut->list, &ct_list);
- } else
- ut->cancellable = false;
+ list_add(&ut->list, &ut_list);
cg_wunlock(&cgusb_fd_lock);
return err;
@@ -3327,7 +3335,7 @@ void usb_initialise(void)
int bus, dev, lim, i;
bool found;
- INIT_LIST_HEAD(&ct_list);
+ INIT_LIST_HEAD(&ut_list);
for (i = 0; i < DRIVER_MAX; i++) {
drv_count[i].count = 0;
diff --git a/usbutils.h b/usbutils.h
index 52441be..2c9e5ad 100644
--- a/usbutils.h
+++ b/usbutils.h
@@ -117,8 +117,6 @@
#define DEFAULT_EP_IN 0
#define DEFAULT_EP_OUT 1
-int cgusb_transfers;
-
struct usb_epinfo {
uint8_t att;
uint16_t size;
@@ -356,6 +354,7 @@ enum usb_cmds {
struct device_drv;
struct cgpu_info;
+bool async_usb_transfers(void);
void cancel_usb_transfers(void);
void usb_all(int level);
const char *usb_cmdname(enum usb_cmds cmd);