From 2f68e47167925993947ac07e360e9fa251c50979 Mon Sep 17 00:00:00 2001 From: Ken Thomases Date: Wed, 30 Oct 2013 05:52:58 -0500 Subject: [PATCH] winemac: Don't use the main dispatch queue to implement OnMainThread() for a thread with no event queue. The main dispatch queue is a serial queue and is a shared resource. If we submit a long-running task to it, then no other tasks, including those submitted by the system frameworks, can run until it completes. --- dlls/winemac.drv/cocoa_event.m | 49 +++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/dlls/winemac.drv/cocoa_event.m b/dlls/winemac.drv/cocoa_event.m index 3b35576600b..13f96953fdb 100644 --- a/dlls/winemac.drv/cocoa_event.m +++ b/dlls/winemac.drv/cocoa_event.m @@ -460,42 +460,55 @@ void OnMainThread(dispatch_block_t block) NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary]; WineEventQueue* queue = [threadDict objectForKey:WineEventQueueThreadDictionaryKey]; + dispatch_semaphore_t semaphore; __block BOOL finished; if (!queue) { - /* Fall back to synchronous dispatch without handling query events. */ - dispatch_sync(dispatch_get_main_queue(), block); - [pool release]; - return; + semaphore = dispatch_semaphore_create(0); + dispatch_retain(semaphore); } finished = FALSE; OnMainThreadAsync(^{ block(); finished = TRUE; - [queue signalEventAvailable]; + if (queue) + [queue signalEventAvailable]; + else + { + dispatch_semaphore_signal(semaphore); + dispatch_release(semaphore); + } }); - while (!finished) + if (queue) { - MacDrvEvent* macDrvEvent; - struct kevent kev; - - while (!finished && - (macDrvEvent = [queue getEventMatchingMask:event_mask_for_type(QUERY_EVENT)])) + while (!finished) { - queue->event_handler(macDrvEvent->event); - } + MacDrvEvent* macDrvEvent; + struct kevent kev; - if (!finished) - { - [pool release]; - pool = [[NSAutoreleasePool alloc] init]; + while (!finished && + (macDrvEvent = [queue getEventMatchingMask:event_mask_for_type(QUERY_EVENT)])) + { + queue->event_handler(macDrvEvent->event); + } - kevent(queue->kq, NULL, 0, &kev, 1, NULL); + if (!finished) + { + [pool release]; + pool = [[NSAutoreleasePool alloc] init]; + + kevent(queue->kq, NULL, 0, &kev, 1, NULL); + } } } + else + { + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + dispatch_release(semaphore); + } [pool release]; }