@@ -820,3 +820,130 @@ index 14a0cd36..e940356f 100644
820820- -
8218212.41.0
822822
823+ From e63455ac85ec8f7dda4b20dd639c270d69205344 Mon Sep 17 00:00:00 2001
824+ 825+ Date: Mon, 25 Aug 2025 12:04:57 -0700
826+ Subject: [PATCH] darwin: fix race condition on device open
827+
828+ Similar to the previous commit with device capture counts, we also need to
829+ take account of multiple contexts calling open/close on a device and make
830+ sure the open_count is immune to data races.
831+ ---
832+ libusb/os/darwin_usb.c | 39 ++++++++++++++++++++++++++++++++++-----
833+ libusb/os/darwin_usb.h | 1 +
834+ 2 files changed, 35 insertions(+), 5 deletions(-)
835+
836+ diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
837+ index e940356f..58414a31 100644
838+ --- a/libusb/os/darwin_usb.c
839+ +++ b/libusb/os/darwin_usb.c
840+ @@ -190,6 +190,7 @@ static void darwin_deref_cached_device(struct darwin_cached_device *cached_dev)
841+ }
842+ IOObjectRelease (cached_dev->service);
843+ usbi_mutex_destroy (&cached_dev->capture_mutex);
844+ + usbi_mutex_destroy (&cached_dev->open_mutex);
845+ free (cached_dev);
846+ }
847+ }
848+ @@ -1080,6 +1081,7 @@ static enum libusb_error darwin_get_cached_device(struct libusb_context *ctx, io
849+
850+ /* initialize locks */
851+ usbi_mutex_init (&new_device->capture_mutex);
852+ + usbi_mutex_init (&new_device->open_mutex);
853+ }
854+
855+ /* keep track of devices regardless of if we successfully enumerate them to
856+ @@ -1243,7 +1245,8 @@ static enum libusb_error darwin_scan_devices(struct libusb_context *ctx) {
857+ return LIBUSB_SUCCESS;
858+ }
859+
860+ - static int darwin_open (struct libusb_device_handle *dev_handle) {
861+ + /* call holding open_mutex lock */
862+ + static int _darwin_open_locked (struct libusb_device_handle *dev_handle) {
863+ struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
864+ struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
865+ IOReturn kresult;
866+ @@ -1292,7 +1295,18 @@ static int darwin_open (struct libusb_device_handle *dev_handle) {
867+ return 0;
868+ }
869+
870+ - static void darwin_close (struct libusb_device_handle *dev_handle) {
871+ + static int darwin_open (struct libusb_device_handle *dev_handle) {
872+ + struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
873+ + enum libusb_error ret;
874+ +
875+ + usbi_mutex_lock (&dpriv->open_mutex);
876+ + ret = _darwin_open_locked (dev_handle);
877+ + usbi_mutex_unlock (&dpriv->open_mutex);
878+ + return ret;
879+ + }
880+ +
881+ + /* call holding open_mutex lock */
882+ + static void _darwin_close_locked (struct libusb_device_handle *dev_handle) {
883+ struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
884+ struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
885+ IOReturn kresult;
886+ @@ -1336,6 +1350,14 @@ static void darwin_close (struct libusb_device_handle *dev_handle) {
887+ }
888+ }
889+
890+ + static void darwin_close (struct libusb_device_handle *dev_handle) {
891+ + struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
892+ +
893+ + usbi_mutex_lock (&dpriv->open_mutex);
894+ + _darwin_close_locked (dev_handle);
895+ + usbi_mutex_unlock (&dpriv->open_mutex);
896+ + }
897+ +
898+ static int darwin_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config) {
899+ struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
900+
901+ @@ -1710,11 +1732,15 @@ static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t
902+ unsigned long claimed_interfaces) {
903+ struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
904+ struct darwin_device_handle_priv *priv = usbi_get_device_handle_priv(dev_handle);
905+ - int open_count = dpriv->open_count;
906+ + int open_count;
907+ int ret;
908+
909+ struct libusb_context *ctx = HANDLE_CTX (dev_handle);
910+
911+ + usbi_mutex_lock (&dpriv->open_mutex);
912+ +
913+ + open_count = dpriv->open_count;
914+ +
915+ /* clear claimed interfaces temporarily */
916+ dev_handle->claimed_interfaces = 0;
917+
918+ @@ -1723,11 +1749,14 @@ static int darwin_restore_state (struct libusb_device_handle *dev_handle, int8_t
919+ dpriv->open_count = 1;
920+
921+ /* clean up open interfaces */
922+ - (void) darwin_close (dev_handle);
923+ + (void) _darwin_close_locked (dev_handle);
924+
925+ /* re-open the device */
926+ - ret = darwin_open (dev_handle);
927+ + ret = _darwin_open_locked (dev_handle);
928+ dpriv->open_count = open_count;
929+ +
930+ + usbi_mutex_unlock (&dpriv->open_mutex);
931+ +
932+ if (LIBUSB_SUCCESS != ret) {
933+ /* could not restore configuration */
934+ return LIBUSB_ERROR_NOT_FOUND;
935+ diff --git a/libusb/os/darwin_usb.h b/libusb/os/darwin_usb.h
936+ index cde286e7..22f151c1 100644
937+ --- a/libusb/os/darwin_usb.h
938+ +++ b/libusb/os/darwin_usb.h
939+ @@ -191,6 +191,7 @@ struct darwin_cached_device {
940+ bool in_reenumerate;
941+ int capture_count;
942+ usbi_mutex_t capture_mutex;
943+ + usbi_mutex_t open_mutex;
944+ };
945+
946+ struct darwin_device_priv {
947+ - -
948+ 2.41.0
949+
0 commit comments