diff options
| author | 2021-06-20 02:45:09 +0200 | |
|---|---|---|
| committer | 2021-06-20 02:45:09 +0200 | |
| commit | 5718dd2ae149f615191552eef40f8f90e60a3455 (patch) | |
| tree | b6523e8d4a08b04445aa51eec864c255797e3a0c /src | |
| parent | cb50087482cf5a4239ad9c96b7157c45eac12876 (diff) | |
| download | libirecovery-5718dd2ae149f615191552eef40f8f90e60a3455.tar.gz libirecovery-5718dd2ae149f615191552eef40f8f90e60a3455.tar.bz2  | |
Make sure the device event handler thread has started before returning from irecv_device_event_subscribe()
This fixes a potential deadlock that might occur when irecv_device_event_unsubscribe()
is called before the device event handler thread has started, eventually
resulting in a deadlock.
Diffstat (limited to 'src')
| -rw-r--r-- | src/libirecovery.c | 40 | 
1 files changed, 37 insertions, 3 deletions
diff --git a/src/libirecovery.c b/src/libirecovery.c index 84f0b32..39f6f88 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c @@ -2127,11 +2127,22 @@ static int _irecv_usb_hotplug_cb(libusb_context *ctx, libusb_device *device, lib  #endif /* !HAVE_IOKIT */  #endif /* !WIN32 */ -static void *_irecv_event_handler(void* unused) +struct _irecv_event_handler_info { +	cond_t startup_cond; +	mutex_t startup_mutex; +}; + +static void *_irecv_event_handler(void* data)  { +	struct _irecv_event_handler_info* info = (struct _irecv_event_handler_info*)data;  #ifdef WIN32  	const GUID *guids[] = { &GUID_DEVINTERFACE_DFU, &GUID_DEVINTERFACE_IBOOT, NULL };  	int running = 1; + +	mutex_lock(&(info->startup_mutex)); +	cond_signal(&(info->startup_cond)); +	mutex_unlock(&(info->startup_mutex)); +  	do {  		SP_DEVICE_INTERFACE_DATA currentInterface;  		HDEVINFO usbDevices; @@ -2246,6 +2257,10 @@ static void *_irecv_event_handler(void* unused)  		i++;  	} +	mutex_lock(&(info->startup_mutex)); +	cond_signal(&(info->startup_cond)); +	mutex_unlock(&(info->startup_mutex)); +  	CFRunLoopRun();  #else /* !HAVE_IOKIT */ @@ -2253,6 +2268,11 @@ static void *_irecv_event_handler(void* unused)  	static libusb_hotplug_callback_handle usb_hotplug_cb_handle;  	libusb_hotplug_register_callback(irecv_hotplug_ctx, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, LIBUSB_HOTPLUG_ENUMERATE, APPLE_VENDOR_ID, LIBUSB_HOTPLUG_MATCH_ANY, 0, _irecv_usb_hotplug_cb, NULL, &usb_hotplug_cb_handle);  	int running = 1; + +	mutex_lock(&(info->startup_mutex)); +	cond_signal(&(info->startup_cond)); +	mutex_unlock(&(info->startup_mutex)); +  	do {  		struct timeval tv;  		tv.tv_sec = tv.tv_usec = 0; @@ -2272,6 +2292,10 @@ static void *_irecv_event_handler(void* unused)  	libusb_device **devs;  	int running = 1; +	mutex_lock(&(info->startup_mutex)); +	cond_signal(&(info->startup_cond)); +	mutex_unlock(&(info->startup_mutex)); +  	do {  		cnt = libusb_get_device_list(irecv_hotplug_ctx, &devs);  		if (cnt < 0) { @@ -2349,6 +2373,9 @@ IRECV_API irecv_error_t irecv_device_event_subscribe(irecv_device_event_context_  	mutex_unlock(&listener_mutex);  	if (th_event_handler == THREAD_T_NULL || !thread_alive(th_event_handler)) { +		struct _irecv_event_handler_info info; +		cond_init(&info.startup_cond); +		mutex_init(&info.startup_mutex);  #ifndef WIN32  #ifndef HAVE_IOKIT  		libusb_init(&irecv_hotplug_ctx); @@ -2356,7 +2383,13 @@ IRECV_API irecv_error_t irecv_device_event_subscribe(irecv_device_event_context_  #endif  		collection_init(&devices);  		mutex_init(&device_mutex); -		thread_new(&th_event_handler, _irecv_event_handler, NULL); +		mutex_lock(&info.startup_mutex); +		if (thread_new(&th_event_handler, _irecv_event_handler, &info) == 0) { +			cond_wait(&info.startup_cond, &info.startup_mutex); +		} +		mutex_unlock(&info.startup_mutex); +		cond_destroy(&info.startup_cond); +		mutex_destroy(&info.startup_mutex);  	}  	*context = _context; @@ -2378,10 +2411,11 @@ IRECV_API irecv_error_t irecv_device_event_unsubscribe(irecv_device_event_contex  	int num = collection_count(&listeners);  	mutex_unlock(&listener_mutex); -	if (num == 0) { +	if (num == 0 && th_event_handler != THREAD_T_NULL && thread_alive(th_event_handler)) {  #ifdef HAVE_IOKIT  		if (iokit_runloop) {  			CFRunLoopStop(iokit_runloop); +			iokit_runloop = NULL;  		}  #endif  		thread_join(th_event_handler);  | 
