From b3e98e9f5fc3a99ee674d54b1920317b5f42a3d6 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Mon, 21 Mar 2016 16:58:39 -0700 Subject: [PATCH 1/2] If the queue is not fully drained yet force another run loop to process next batch of items --- AsyncDisplayKit/ASRunLoopQueue.mm | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/AsyncDisplayKit/ASRunLoopQueue.mm b/AsyncDisplayKit/ASRunLoopQueue.mm index 8519a61f13..a18f7a8a70 100644 --- a/AsyncDisplayKit/ASRunLoopQueue.mm +++ b/AsyncDisplayKit/ASRunLoopQueue.mm @@ -12,8 +12,13 @@ #import #import +#define ASRunLoopQueueLoggingEnabled 0 + static void runLoopSourceCallback(void *info) { // No-op +#if ASRunLoopQueueLoggingEnabled + NSLog(@"<%@> - Called runLoopSourceCallback", info); +#endif } @interface ASRunLoopQueue () { @@ -22,6 +27,10 @@ static void runLoopSourceCallback(void *info) { CFRunLoopSourceRef _runLoopSource; std::deque _internalQueue; ASDN::RecursiveMutex _internalQueueLock; + +#if ASRunLoopQueueLoggingEnabled + NSTimer *_runloopQueueLoggingTimer; +#endif } @property (nonatomic, copy) void (^queueConsumer)(id dequeuedItem, BOOL isQueueDrained); @@ -47,9 +56,17 @@ static void runLoopSourceCallback(void *info) { // 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 = (CFRunLoopSourceContext *)calloc(1, sizeof(CFRunLoopSourceContext)); runLoopSourceContext->perform = runLoopSourceCallback; +#if ASRunLoopQueueLoggingEnabled + runLoopSourceContext->info = (__bridge void *)self; +#endif _runLoopSource = CFRunLoopSourceCreate(NULL, 0, runLoopSourceContext); CFRunLoopAddSource(runloop, _runLoopSource, kCFRunLoopCommonModes); free(runLoopSourceContext); + +#if ASRunLoopQueueLoggingEnabled + _runloopQueueLoggingTimer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(checkRunLoop) userInfo:nil repeats:YES]; + [[NSRunLoop mainRunLoop] addTimer:_runloopQueueLoggingTimer forMode:NSRunLoopCommonModes]; +#endif } return self; } @@ -69,6 +86,13 @@ static void runLoopSourceCallback(void *info) { _runLoopObserver = nil; } +#if ASRunLoopQueueLoggingEnabled +- (void)checkRunLoop +{ + NSLog(@"<%@> - Jobs: %ld", self, _internalQueue.size()); +} +#endif + - (void)processQueue { std::deque itemsToProcess = std::deque(); @@ -102,6 +126,12 @@ static void runLoopSourceCallback(void *info) { self.queueConsumer(itemsToProcess[i], isQueueDrained); } } + + // If the queue is not fully drained yet force another run loop to process next batch of items + if (!isQueueDrained) { + CFRunLoopSourceSignal(_runLoopSource); + CFRunLoopWakeUp(_runLoop); + } } - (void)enqueue:(id)object From a937184a0be7feb066b0a5d21d7b11dd00c26ce4 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Mon, 21 Mar 2016 17:10:29 -0700 Subject: [PATCH 2/2] Remove CFRunLoopWakeUp in CFRunLoop observer callback We don't nee CFRunLoopWakeUp as at this time are currently running in an observer callback, and after running all of the BeforeWaiting observers it must surely check for more sources / etc to run before determining if it will sleep --- AsyncDisplayKit/ASRunLoopQueue.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/AsyncDisplayKit/ASRunLoopQueue.mm b/AsyncDisplayKit/ASRunLoopQueue.mm index a18f7a8a70..e879bfe762 100644 --- a/AsyncDisplayKit/ASRunLoopQueue.mm +++ b/AsyncDisplayKit/ASRunLoopQueue.mm @@ -130,7 +130,6 @@ static void runLoopSourceCallback(void *info) { // If the queue is not fully drained yet force another run loop to process next batch of items if (!isQueueDrained) { CFRunLoopSourceSignal(_runLoopSource); - CFRunLoopWakeUp(_runLoop); } }