static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */
__CFRunLoopSourceLock(rls);
if (NULL == rls->_runLoops) {
- rls->_runLoops = CFBagCreateMutable(CFGetAllocator(rls), 0, NULL);
+ rls->_runLoops = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
}
CFBagAddValue(rls->_runLoops, rl);
__CFRunLoopSourceUnlock(rls); // have to unlock before the callout -- cannot help clients with safety
}
#endif
+// Remove backreferences the mode's sources have to the rl (context);
+// the primary purpose of rls->_runLoops is so that Invalidation can remove
+// the source from the run loops it is in, but during deallocation of a
+// run loop, we already know that the sources are going to be punted
+// from it, so invalidation of sources does not need to remove from a
+// deallocating run loop.
+static void __CFRunLoopCleanseSources(const void *value, void *context) {
+ CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
+ CFRunLoopRef rl = (CFRunLoopRef)context;
+ CFIndex idx, cnt;
+ const void **list, *buffer[256];
+ if (NULL == rlm->_sources) return;
+ cnt = CFSetGetCount(rlm->_sources);
+ list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
+ CFSetGetValues(rlm->_sources, list);
+ for (idx = 0; idx < cnt; idx++) {
+ CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx];
+ __CFRunLoopSourceLock(rls);
+ if (NULL != rls->_runLoops) {
+ CFBagRemoveValue(rls->_runLoops, rl);
+ }
+ __CFRunLoopSourceUnlock(rls);
+ }
+ if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
+}
+
static void __CFRunLoopDeallocateSources(const void *value, void *context) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
CFRunLoopRef rl = (CFRunLoopRef)context;
three lines. */
__CFRunLoopSetDeallocating(rl);
if (NULL != rl->_modes) {
+ CFSetApplyFunction(rl->_modes, (__CFRunLoopCleanseSources), rl); // remove references to rl
CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateSources), rl);
CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateObservers), rl);
CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateTimers), rl);
return loop;
}
-static CFMutableDictionaryRef runLoops = NULL;
+static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName);
+
+static CFMutableDictionaryRef __CFRunLoops = NULL;
static char setMainLoop = 0;
static CFSpinLock_t loopsLock = CFSpinLockInit;
// fetch the main thread's pthread_t from the pthreads subsystem.
// t==0 is a synonym for "main thread" that always works
-__private_extern__ CFRunLoopRef _CFRunLoop0(pthread_t t) {
- CFRunLoopRef loop = NULL;
+static CFRunLoopRef _CFRunLoop0(pthread_t t) {
+ CFRunLoopRef loop;
__CFSpinLock(&loopsLock);
- if (!runLoops) {
+ if (!__CFRunLoops) {
__CFSpinUnlock(&loopsLock);
- CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
+ CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
CFRunLoopRef mainLoop = __CFRunLoopCreate();
- CFDictionarySetValue(dict, 0, mainLoop);
- if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&runLoops)) {
+ CFDictionarySetValue(dict, pthreadPointer(kNilPthreadT), mainLoop);
+ if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
CFRelease(dict);
- CFRelease(mainLoop);
}
+ CFRelease(mainLoop);
__CFSpinLock(&loopsLock);
}
if (pthread_main_np() && pthread_equal(t, pthread_self())) {
t = kNilPthreadT;
}
- loop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t));
+ loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop) {
__CFSpinUnlock(&loopsLock);
CFRunLoopRef newLoop = __CFRunLoopCreate();
- __CFGetThreadSpecificData(); // just cause the thread finalizer to be called as a side effect
__CFSpinLock(&loopsLock);
- loop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t));
- if (loop) {
- CFRelease(newLoop);
- } else {
- CFDictionarySetValue(runLoops, pthreadPointer(t), newLoop);
+ loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
+ if (!loop) {
+ CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
loop = newLoop;
}
+ CFRelease(newLoop);
}
if (!setMainLoop && pthread_main_np()) {
if (pthread_equal(t, kNilPthreadT)) {
- CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), loop);
+ CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), loop);
} else {
- CFRunLoopRef mainLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(kNilPthreadT));
- CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), mainLoop);
+ CFRunLoopRef mainLoop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(kNilPthreadT));
+ CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), mainLoop);
}
setMainLoop = 1;
}
return loop;
}
-__private_extern__ void _CFRunLoop1(void) {
+// Called for each thread as it exits
+static void __CFFinalizeRunLoop(void *arg) {
+ CFRunLoopRef rl = NULL;
__CFSpinLock(&loopsLock);
- if (runLoops) {
- pthread_t t = pthread_self();
- CFRunLoopRef currentLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t));
- CFRunLoopRef mainLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(kNilPthreadT));
- if (currentLoop && mainLoop != currentLoop) {
- CFDictionaryRemoveValue(runLoops, pthreadPointer(t));
- CFRelease(currentLoop);
+ if (__CFRunLoops) {
+ rl = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(pthread_self()));
+ if (rl) CFRetain(rl);
+ CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
}
+ __CFSpinUnlock(&loopsLock);
+ if (rl && CFRunLoopGetMain() != rl) {
+ // purge all sources before deallocation
+ CFArrayRef array = CFRunLoopCopyAllModes(rl);
+ for (CFIndex idx = CFArrayGetCount(array); idx--;) {
+ CFStringRef modeName = CFArrayGetValueAtIndex(array, idx);
+ __CFRunLoopRemoveAllSources(rl, modeName);
+ }
+ __CFRunLoopRemoveAllSources(rl, kCFRunLoopCommonModes);
+ CFRelease(array);
+ }
+ if (rl) {
+ CFRelease(rl);
+ }
+}
+
+__private_extern__ void _CFRunLoop1(void) { __CFFinalizeRunLoop(0); }
+
+void _CFRunLoopSetCurrent(CFRunLoopRef rl) {
+ CFRunLoopRef currentLoop = CFRunLoopGetCurrent();
+ if (rl != currentLoop) {
+ __CFSpinLock(&loopsLock);
+ if (rl) {
+ CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), rl);
+ } else {
+ CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
}
__CFSpinUnlock(&loopsLock);
+ }
}
CFRunLoopRef CFRunLoopGetMain(void) {
return _CFRunLoop0(pthread_self());
}
-void _CFRunLoopSetCurrent(CFRunLoopRef rl) {
- __CFSpinLock(&loopsLock);
- CFRunLoopRef currentLoop = runLoops ? (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(pthread_self())) : NULL;
- if (rl != currentLoop) {
- // intentionally leak currentLoop so we don't kill any ports in the child
- // if (currentLoop) CFRelease(currentLoop);
- if (rl) {
- if (!runLoops) {
- runLoops = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
- CFRunLoopRef mainLoop = __CFRunLoopCreate();
- CFDictionarySetValue(runLoops, pthreadPointer(kNilPthreadT), mainLoop);
- }
- CFRetain(rl);
- CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), rl);
- } else {
- CFDictionaryRemoveValue(runLoops, pthreadPointer(pthread_self()));
- }
- }
- __CFSpinUnlock(&loopsLock);
-}
-
CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) {
CHECK_FOR_FORK();
CFStringRef result = NULL;
if (seconds <= 0.0) {
poll = true;
}
- if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = CFPORT_NULL;
+ if (rl == CFRunLoopGetMain()) _LastMainWaitSet = CFPORT_NULL;
for (;;) {
__CFPortSet waitSet = CFPORT_NULL;
waitSet = CFPORT_NULL;
}
#endif
}
- if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = waitSet;
+ if (rl == CFRunLoopGetMain()) _LastMainWaitSet = waitSet;
__CFRunLoopModeUnlock(rlm);
#if DEPLOYMENT_TARGET_MACOSX
#endif
if (destroyWaitSet) {
__CFPortSetFree(waitSet);
- if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = 0;
+ if (rl == CFRunLoopGetMain()) _LastMainWaitSet = 0;
}
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
}
}
+static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value, void *ctx) {
+ CFStringRef modeName = (CFStringRef)value;
+ CFRunLoopRef rl = (CFRunLoopRef)ctx;
+ __CFRunLoopRemoveAllSources(rl, modeName);
+}
+
+static void __CFRunLoopRemoveSourceFromMode(const void *value, void *ctx) {
+ CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
+ CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
+ CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]);
+ CFRunLoopRemoveSource(rl, rls, modeName);
+}
+
+static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName) {
+ CHECK_FOR_FORK();
+ CFRunLoopModeRef rlm;
+ __CFRunLoopLock(rl);
+ if (modeName == kCFRunLoopCommonModes) {
+ if (NULL != rl->_commonModeItems) {
+ CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
+ __CFRunLoopUnlock(rl);
+ if (NULL != set) {
+ CFSetApplyFunction(set, (__CFRunLoopRemoveSourcesFromCommonMode), (void *)rl);
+ CFRelease(set);
+ }
+ } else {
+ __CFRunLoopUnlock(rl);
+ }
+ } else {
+ rlm = __CFRunLoopFindMode(rl, modeName, false);
+ __CFRunLoopUnlock(rl);
+ if (NULL != rlm && NULL != rlm->_sources) {
+ CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources);
+ __CFRunLoopModeUnlock(rlm);
+ CFTypeRef context[2] = {rl, modeName};
+ CFSetApplyFunction(set, (__CFRunLoopRemoveSourceFromMode), (void *)context);
+ CFRelease(set);
+ } else if (NULL != rlm) {
+ __CFRunLoopModeUnlock(rlm);
+ }
+ }
+}
+
Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;