Skip to content

Commit 3d545a2

Browse files
committed
darwin: fix race condition on device open
Similar to the previous commit with device capture counts, we also need to take account of multiple contexts calling open/close on a device and make sure the open_count is immune to data races.
1 parent 440cc1b commit 3d545a2

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

libusb/os/darwin_usb.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ static void darwin_deref_cached_device(struct darwin_cached_device *cached_dev)
459459
}
460460
IOObjectRelease (cached_dev->service);
461461
usbi_mutex_destroy (&cached_dev->capture_mutex);
462+
usbi_mutex_destroy (&cached_dev->open_mutex);
462463
free (cached_dev);
463464
}
464465
}
@@ -1363,6 +1364,7 @@ static enum libusb_error darwin_get_cached_device(struct libusb_context *ctx, io
13631364

13641365
/* initialize locks */
13651366
usbi_mutex_init (&new_device->capture_mutex);
1367+
usbi_mutex_init (&new_device->open_mutex);
13661368
} else {
13671369
/* release the ref to old device's service */
13681370
IOObjectRelease (new_device->service);
@@ -1524,7 +1526,8 @@ static enum libusb_error darwin_scan_devices(struct libusb_context *ctx) {
15241526
return LIBUSB_SUCCESS;
15251527
}
15261528

1527-
static int darwin_open (struct libusb_device_handle *dev_handle) {
1529+
/* call holding open_mutex lock */
1530+
static int _darwin_open_locked (struct libusb_device_handle *dev_handle) {
15281531
struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
15291532
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
15301533
IOReturn kresult;
@@ -1574,7 +1577,18 @@ static int darwin_open (struct libusb_device_handle *dev_handle) {
15741577
return 0;
15751578
}
15761579

1577-
static void darwin_close (struct libusb_device_handle *dev_handle) {
1580+
static int darwin_open (struct libusb_device_handle *dev_handle) {
1581+
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
1582+
enum libusb_error ret;
1583+
1584+
usbi_mutex_lock (&dpriv->open_mutex);
1585+
ret = _darwin_open_locked (dev_handle);
1586+
usbi_mutex_unlock (&dpriv->open_mutex);
1587+
return ret;
1588+
}
1589+
1590+
/* call holding open_mutex lock */
1591+
static void _darwin_close_locked (struct libusb_device_handle *dev_handle) {
15781592
struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
15791593
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
15801594
IOReturn kresult;
@@ -1618,6 +1632,14 @@ static void darwin_close (struct libusb_device_handle *dev_handle) {
16181632
}
16191633
}
16201634

1635+
static void darwin_close (struct libusb_device_handle *dev_handle) {
1636+
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
1637+
1638+
usbi_mutex_lock (&dpriv->open_mutex);
1639+
_darwin_close_locked (dev_handle);
1640+
usbi_mutex_unlock (&dpriv->open_mutex);
1641+
}
1642+
16211643
static int darwin_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config) {
16221644
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
16231645

@@ -2016,11 +2038,15 @@ static int darwin_restore_state (struct libusb_device_handle *dev_handle, uint8_
20162038
unsigned long claimed_interfaces) {
20172039
struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
20182040
struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
2019-
int open_count = dpriv->open_count;
2041+
int open_count;
20202042
int ret;
20212043

20222044
struct libusb_context *ctx = HANDLE_CTX (dev_handle);
20232045

2046+
usbi_mutex_lock (&dpriv->open_mutex);
2047+
2048+
open_count = dpriv->open_count;
2049+
20242050
/* clear claimed interfaces temporarily */
20252051
dev_handle->claimed_interfaces = 0;
20262052

@@ -2029,11 +2055,14 @@ static int darwin_restore_state (struct libusb_device_handle *dev_handle, uint8_
20292055
dpriv->open_count = 1;
20302056

20312057
/* clean up open interfaces */
2032-
(void) darwin_close (dev_handle);
2058+
(void) _darwin_close_locked (dev_handle);
20332059

20342060
/* re-open the device */
2035-
ret = darwin_open (dev_handle);
2061+
ret = _darwin_open_locked (dev_handle);
20362062
dpriv->open_count = open_count;
2063+
2064+
usbi_mutex_unlock (&dpriv->open_mutex);
2065+
20372066
if (LIBUSB_SUCCESS != ret) {
20382067
/* could not restore configuration */
20392068
return LIBUSB_ERROR_NOT_FOUND;

libusb/os/darwin_usb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ struct darwin_cached_device {
120120
bool in_reenumerate;
121121
int capture_count;
122122
usbi_mutex_t capture_mutex;
123+
usbi_mutex_t open_mutex;
123124
};
124125

125126
struct darwin_device_priv {

0 commit comments

Comments
 (0)