Mark ASRunLoopQueue as drained if it contains only NULLs (#558)

* Mark ASRunLoopQueue as drained if it contains only NULLs

* Update CHANGELOG.md

* Cover ASRunLoopQueue with tests

* Include PR link in CHANGELOG.md

* Replace license header of ASRunLoopQueueTests.m with correct one

* Insert a nil in _internalQueue to ensure compaction, instead of maintaining a state for _isQueueDrained
This commit is contained in:
César Estébanez Tascón
2017-09-11 22:32:25 +02:00
committed by Garrett Moon
parent 7c7a4acf0e
commit 002c2d6978
5 changed files with 184 additions and 3 deletions

View File

@@ -348,12 +348,12 @@ typedef enum {
{
ASDN::MutexLocker l(_internalQueueLock);
// Early-exit if the queue is empty.
NSInteger internalQueueCount = _internalQueue.count;
// Early-exit if the queue is empty.
if (internalQueueCount == 0) {
return;
}
ASSignpostStart(ASSignpostRunLoopQueueBatch);
// Snatch the next batch of items.
@@ -382,6 +382,14 @@ typedef enum {
}
}
if (foundItemCount == 0) {
// If _internalQueue holds weak references, and all of them just become NULL, then the array
// is never marked as needsCompletion, and compact will return early, not removing the NULL's.
// Inserting a NULL here ensures the compaction will take place.
// See http://www.openradar.me/15396578 and https://stackoverflow.com/a/40274426/1136669
[_internalQueue addPointer:NULL];
}
[_internalQueue compact];
if (_internalQueue.count == 0) {
isQueueDrained = YES;
@@ -434,10 +442,16 @@ typedef enum {
if (!foundObject) {
[_internalQueue addPointer:(__bridge void *)object];
CFRunLoopSourceSignal(_runLoopSource);
CFRunLoopWakeUp(_runLoop);
}
}
- (BOOL)isEmpty
{
ASDN::MutexLocker l(_internalQueueLock);
return _internalQueue.count == 0;
}
@end