Commit ad30d41f795cfade08cc512a9594ed68ee09f504

Kano 2013-06-14T23:48:03

usb lock out transfers during open/close

diff --git a/cgminer.c b/cgminer.c
index 7ee5e5c..fa9ca5b 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -185,6 +185,7 @@ int hotplug_time = 5;
 #ifdef USE_USBUTILS
 pthread_mutex_t cgusb_lock;
 pthread_mutex_t cgusbres_lock;
+pthread_rwlock_t cgusb_fd_lock;
 #endif
 
 pthread_mutex_t hash_lock;
@@ -7339,6 +7340,7 @@ int main(int argc, char *argv[])
 #ifdef USE_USBUTILS
 	mutex_init(&cgusb_lock);
 	mutex_init(&cgusbres_lock);
+	rwlock_init(&cgusb_fd_lock);
 #endif
 #endif
 
diff --git a/miner.h b/miner.h
index ff32c28..89a535a 100644
--- a/miner.h
+++ b/miner.h
@@ -897,6 +897,7 @@ extern int opt_expiry;
 #ifdef USE_USBUTILS
 extern pthread_mutex_t cgusb_lock;
 extern pthread_mutex_t cgusbres_lock;
+extern pthread_rwlock_t cgusb_fd_lock;
 #endif
 
 extern cglock_t control_lock;
diff --git a/usbutils.c b/usbutils.c
index 393e733..7a3dcb4 100644
--- a/usbutils.c
+++ b/usbutils.c
@@ -1338,8 +1338,11 @@ void usb_uninit(struct cgpu_info *cgpu)
 	//  if release_cgpu() was called due to a USB NODEV(err)
 	if (!cgpu->usbdev)
 		return;
-	if (!libusb_release_interface(cgpu->usbdev->handle, cgpu->usbdev->found->interface))
+	if (!libusb_release_interface(cgpu->usbdev->handle, cgpu->usbdev->found->interface)) {
+		wr_lock(&cgusb_fd_lock);
 		libusb_close(cgpu->usbdev->handle);
+		wr_unlock(&cgusb_fd_lock);
+	}
 	cgpu->usbdev = free_cgusb(cgpu->usbdev);
 }
 
@@ -1517,7 +1520,9 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u
 		goto dame;
 	}
 
+	wr_lock(&cgusb_fd_lock);
 	err = libusb_open(dev, &(cgusb->handle));
+	wr_unlock(&cgusb_fd_lock);
 	if (err) {
 		switch (err) {
 			case LIBUSB_ERROR_ACCESS:
@@ -1727,7 +1732,9 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u
 
 cldame:
 
+	wr_lock(&cgusb_fd_lock);
 	libusb_close(cgusb->handle);
+	wr_unlock(&cgusb_fd_lock);
 
 dame:
 
@@ -2177,8 +2184,11 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle,
 {
 	int err, tries = 0;
 
+	rd_lock(&cgusb_fd_lock);
 	err = libusb_bulk_transfer(dev_handle, endpoint, data, length,
 				   transferred, timeout);
+	rd_unlock(&cgusb_fd_lock);
+
 	if (unlikely(err == LIBUSB_ERROR_PIPE)) {
 		applog(LOG_WARNING, "%s: libusb pipe error, trying to clear",
 		       cgpu->drv->name);
@@ -2187,8 +2197,11 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle,
 			if (unlikely(err == LIBUSB_ERROR_NOT_FOUND ||
 				     err == LIBUSB_ERROR_NO_DEVICE))
 					break;
+
+			rd_lock(&cgusb_fd_lock);
 			err = libusb_bulk_transfer(dev_handle, endpoint, data,
 						   length, transferred, timeout);
+			rd_unlock(&cgusb_fd_lock);
 		} while (err == LIBUSB_ERROR_PIPE && tries++ < USB_RETRY_MAX);
 		applog(LOG_DEBUG, "%s: libusb pipe error%scleared",
 		       cgpu->drv->name, err ? " not " : " ");
@@ -2565,9 +2578,11 @@ int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest
 	USBDEBUG("USB debug: @_usb_transfer() buf=%s", bin2hex((unsigned char *)buf, (size_t)siz));
 
 	STATS_TIMEVAL(&tv_start);
+	rd_lock(&cgusb_fd_lock);
 	err = libusb_control_transfer(usbdev->handle, request_type,
 		bRequest, wValue, wIndex, (unsigned char *)buf, (uint16_t)siz,
 		timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout);
+	rd_unlock(&cgusb_fd_lock);
 	STATS_TIMEVAL(&tv_finish);
 	USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_CTRL_WRITE, cmd, SEQ0);
 
@@ -2610,10 +2625,12 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe
 	*amount = 0;
 
 	STATS_TIMEVAL(&tv_start);
+	rd_lock(&cgusb_fd_lock);
 	err = libusb_control_transfer(usbdev->handle, request_type,
 		bRequest, wValue, wIndex,
 		(unsigned char *)buf, (uint16_t)bufsiz,
 		timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout);
+	rd_unlock(&cgusb_fd_lock);
 	STATS_TIMEVAL(&tv_finish);
 	USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_CTRL_READ, cmd, SEQ0);