From d1756baae7e4f9de2d8a90d4988b6970901e1acf Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Fri, 18 Mar 2016 14:02:27 -0700 Subject: [PATCH 1/2] Add custom run loop source to signal if new jobs are enqueued in ASRunLoopQueue It is not guaranteed that the runloop will turn if it has no scheduled work, and this causes processing of the queue to stop. Attaching a custom loop source to the run loop and signal it if new work needs to be done --- AsyncDisplayKit/ASRunLoopQueue.mm | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/AsyncDisplayKit/ASRunLoopQueue.mm b/AsyncDisplayKit/ASRunLoopQueue.mm index 2eb3420e18..b27a745279 100644 --- a/AsyncDisplayKit/ASRunLoopQueue.mm +++ b/AsyncDisplayKit/ASRunLoopQueue.mm @@ -11,9 +11,14 @@ #import +static void runLoopSourceCallback(void *info) { + // No-op +} + @interface ASRunLoopQueue () { CFRunLoopRef _runLoop; CFRunLoopObserverRef _runLoopObserver; + CFRunLoopSourceRef _runLoopSource; std::deque _internalQueue; ASDN::RecursiveMutex _internalQueueLock; } @@ -36,12 +41,24 @@ }; _runLoopObserver = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, true, 0, handlerBlock); CFRunLoopAddObserver(_runLoop, _runLoopObserver, kCFRunLoopCommonModes); + + // It is not guaranteed that the runloop will turn if it has no scheduled work, and this causes processing of + // the queue to stop. Attaching a custom loop source to the run loop and signal it if new work needs to be done + CFRunLoopSourceContext runLoopSourceContext = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &runLoopSourceCallback}; + _runLoopSource = CFRunLoopSourceCreate(NULL, 0, &runLoopSourceContext); + CFRunLoopAddSource(runloop, _runLoopSource, kCFRunLoopCommonModes); } return self; } - (void)dealloc { + if (CFRunLoopContainsSource(_runLoop, _runLoopSource, kCFRunLoopCommonModes)) { + CFRunLoopRemoveSource(_runLoop, _runLoopSource, kCFRunLoopCommonModes); + } + CFRelease(_runLoopSource); + _runLoopSource = nil; + if (CFRunLoopObserverIsValid(_runLoopObserver)) { CFRunLoopObserverInvalidate(_runLoopObserver); } @@ -103,6 +120,9 @@ if (!foundObject) { _internalQueue.push_back(object); + + CFRunLoopSourceSignal(_runLoopSource); + CFRunLoopWakeUp(_runLoop); } } From 14b9df30a31592af29e16b60e425d9fb09912d15 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Fri, 18 Mar 2016 14:32:45 -0700 Subject: [PATCH 2/2] Create CFRunLoopSourceContext via calloc --- AsyncDisplayKit/ASRunLoopQueue.mm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASRunLoopQueue.mm b/AsyncDisplayKit/ASRunLoopQueue.mm index b27a745279..8519a61f13 100644 --- a/AsyncDisplayKit/ASRunLoopQueue.mm +++ b/AsyncDisplayKit/ASRunLoopQueue.mm @@ -9,6 +9,7 @@ #import "ASRunLoopQueue.h" #import "ASThread.h" +#import #import static void runLoopSourceCallback(void *info) { @@ -44,9 +45,11 @@ static void runLoopSourceCallback(void *info) { // It is not guaranteed that the runloop will turn if it has no scheduled work, and this causes processing of // the queue to stop. Attaching a custom loop source to the run loop and signal it if new work needs to be done - CFRunLoopSourceContext runLoopSourceContext = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &runLoopSourceCallback}; - _runLoopSource = CFRunLoopSourceCreate(NULL, 0, &runLoopSourceContext); + CFRunLoopSourceContext *runLoopSourceContext = (CFRunLoopSourceContext *)calloc(1, sizeof(CFRunLoopSourceContext)); + runLoopSourceContext->perform = runLoopSourceCallback; + _runLoopSource = CFRunLoopSourceCreate(NULL, 0, runLoopSourceContext); CFRunLoopAddSource(runloop, _runLoopSource, kCFRunLoopCommonModes); + free(runLoopSourceContext); } return self; }