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
This commit is contained in:
Michael Schneider
2016-03-18 14:02:27 -07:00
parent c8cbd2ec4a
commit d1756baae7

View File

@@ -11,9 +11,14 @@
#import <deque>
static void runLoopSourceCallback(void *info) {
// No-op
}
@interface ASRunLoopQueue () {
CFRunLoopRef _runLoop;
CFRunLoopObserverRef _runLoopObserver;
CFRunLoopSourceRef _runLoopSource;
std::deque<id> _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);
}
}