Skip to content

Commit 4361bba

Browse files
Apple Open Sourceopensource-apple
authored andcommitted
1 parent 1ccf037 commit 4361bba

File tree

1 file changed

+126
-51
lines changed

1 file changed

+126
-51
lines changed

CFRunLoop.c

Lines changed: 126 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) {
509509
static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */
510510
__CFRunLoopSourceLock(rls);
511511
if (NULL == rls->_runLoops) {
512-
rls->_runLoops = CFBagCreateMutable(CFGetAllocator(rls), 0, NULL);
512+
rls->_runLoops = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
513513
}
514514
CFBagAddValue(rls->_runLoops, rl);
515515
__CFRunLoopSourceUnlock(rls); // have to unlock before the callout -- cannot help clients with safety
@@ -793,6 +793,32 @@ static CFRunLoopTimerRef __CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rl
793793
}
794794
#endif
795795

796+
// Remove backreferences the mode's sources have to the rl (context);
797+
// the primary purpose of rls->_runLoops is so that Invalidation can remove
798+
// the source from the run loops it is in, but during deallocation of a
799+
// run loop, we already know that the sources are going to be punted
800+
// from it, so invalidation of sources does not need to remove from a
801+
// deallocating run loop.
802+
static void __CFRunLoopCleanseSources(const void *value, void *context) {
803+
CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
804+
CFRunLoopRef rl = (CFRunLoopRef)context;
805+
CFIndex idx, cnt;
806+
const void **list, *buffer[256];
807+
if (NULL == rlm->_sources) return;
808+
cnt = CFSetGetCount(rlm->_sources);
809+
list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
810+
CFSetGetValues(rlm->_sources, list);
811+
for (idx = 0; idx < cnt; idx++) {
812+
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx];
813+
__CFRunLoopSourceLock(rls);
814+
if (NULL != rls->_runLoops) {
815+
CFBagRemoveValue(rls->_runLoops, rl);
816+
}
817+
__CFRunLoopSourceUnlock(rls);
818+
}
819+
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
820+
}
821+
796822
static void __CFRunLoopDeallocateSources(const void *value, void *context) {
797823
CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
798824
CFRunLoopRef rl = (CFRunLoopRef)context;
@@ -865,6 +891,7 @@ static void __CFRunLoopDeallocate(CFTypeRef cf) {
865891
three lines. */
866892
__CFRunLoopSetDeallocating(rl);
867893
if (NULL != rl->_modes) {
894+
CFSetApplyFunction(rl->_modes, (__CFRunLoopCleanseSources), rl); // remove references to rl
868895
CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateSources), rl);
869896
CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateObservers), rl);
870897
CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateTimers), rl);
@@ -941,7 +968,9 @@ static CFRunLoopRef __CFRunLoopCreate(void) {
941968
return loop;
942969
}
943970

944-
static CFMutableDictionaryRef runLoops = NULL;
971+
static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName);
972+
973+
static CFMutableDictionaryRef __CFRunLoops = NULL;
945974
static char setMainLoop = 0;
946975
static CFSpinLock_t loopsLock = CFSpinLockInit;
947976

@@ -952,62 +981,86 @@ static CFSpinLock_t loopsLock = CFSpinLockInit;
952981
// fetch the main thread's pthread_t from the pthreads subsystem.
953982

954983
// t==0 is a synonym for "main thread" that always works
955-
__private_extern__ CFRunLoopRef _CFRunLoop0(pthread_t t) {
956-
CFRunLoopRef loop = NULL;
984+
static CFRunLoopRef _CFRunLoop0(pthread_t t) {
985+
CFRunLoopRef loop;
957986
__CFSpinLock(&loopsLock);
958-
if (!runLoops) {
987+
if (!__CFRunLoops) {
959988
__CFSpinUnlock(&loopsLock);
960-
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
989+
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
961990
CFRunLoopRef mainLoop = __CFRunLoopCreate();
962-
CFDictionarySetValue(dict, 0, mainLoop);
963-
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&runLoops)) {
991+
CFDictionarySetValue(dict, pthreadPointer(kNilPthreadT), mainLoop);
992+
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
964993
CFRelease(dict);
965-
CFRelease(mainLoop);
966994
}
995+
CFRelease(mainLoop);
967996
__CFSpinLock(&loopsLock);
968997
}
969998
if (pthread_main_np() && pthread_equal(t, pthread_self())) {
970999
t = kNilPthreadT;
9711000
}
972-
loop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t));
1001+
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
9731002
if (!loop) {
9741003
__CFSpinUnlock(&loopsLock);
9751004
CFRunLoopRef newLoop = __CFRunLoopCreate();
976-
__CFGetThreadSpecificData(); // just cause the thread finalizer to be called as a side effect
9771005
__CFSpinLock(&loopsLock);
978-
loop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t));
979-
if (loop) {
980-
CFRelease(newLoop);
981-
} else {
982-
CFDictionarySetValue(runLoops, pthreadPointer(t), newLoop);
1006+
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
1007+
if (!loop) {
1008+
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
9831009
loop = newLoop;
9841010
}
1011+
CFRelease(newLoop);
9851012
}
9861013
if (!setMainLoop && pthread_main_np()) {
9871014
if (pthread_equal(t, kNilPthreadT)) {
988-
CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), loop);
1015+
CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), loop);
9891016
} else {
990-
CFRunLoopRef mainLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(kNilPthreadT));
991-
CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), mainLoop);
1017+
CFRunLoopRef mainLoop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(kNilPthreadT));
1018+
CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), mainLoop);
9921019
}
9931020
setMainLoop = 1;
9941021
}
9951022
__CFSpinUnlock(&loopsLock);
9961023
return loop;
9971024
}
9981025

999-
__private_extern__ void _CFRunLoop1(void) {
1026+
// Called for each thread as it exits
1027+
static void __CFFinalizeRunLoop(void *arg) {
1028+
CFRunLoopRef rl = NULL;
10001029
__CFSpinLock(&loopsLock);
1001-
if (runLoops) {
1002-
pthread_t t = pthread_self();
1003-
CFRunLoopRef currentLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t));
1004-
CFRunLoopRef mainLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(kNilPthreadT));
1005-
if (currentLoop && mainLoop != currentLoop) {
1006-
CFDictionaryRemoveValue(runLoops, pthreadPointer(t));
1007-
CFRelease(currentLoop);
1030+
if (__CFRunLoops) {
1031+
rl = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(pthread_self()));
1032+
if (rl) CFRetain(rl);
1033+
CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
10081034
}
1035+
__CFSpinUnlock(&loopsLock);
1036+
if (rl && CFRunLoopGetMain() != rl) {
1037+
// purge all sources before deallocation
1038+
CFArrayRef array = CFRunLoopCopyAllModes(rl);
1039+
for (CFIndex idx = CFArrayGetCount(array); idx--;) {
1040+
CFStringRef modeName = CFArrayGetValueAtIndex(array, idx);
1041+
__CFRunLoopRemoveAllSources(rl, modeName);
1042+
}
1043+
__CFRunLoopRemoveAllSources(rl, kCFRunLoopCommonModes);
1044+
CFRelease(array);
1045+
}
1046+
if (rl) {
1047+
CFRelease(rl);
1048+
}
1049+
}
1050+
1051+
__private_extern__ void _CFRunLoop1(void) { __CFFinalizeRunLoop(0); }
1052+
1053+
void _CFRunLoopSetCurrent(CFRunLoopRef rl) {
1054+
CFRunLoopRef currentLoop = CFRunLoopGetCurrent();
1055+
if (rl != currentLoop) {
1056+
__CFSpinLock(&loopsLock);
1057+
if (rl) {
1058+
CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), rl);
1059+
} else {
1060+
CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
10091061
}
10101062
__CFSpinUnlock(&loopsLock);
1063+
}
10111064
}
10121065

10131066
CFRunLoopRef CFRunLoopGetMain(void) {
@@ -1020,27 +1073,6 @@ CFRunLoopRef CFRunLoopGetCurrent(void) {
10201073
return _CFRunLoop0(pthread_self());
10211074
}
10221075

1023-
void _CFRunLoopSetCurrent(CFRunLoopRef rl) {
1024-
__CFSpinLock(&loopsLock);
1025-
CFRunLoopRef currentLoop = runLoops ? (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(pthread_self())) : NULL;
1026-
if (rl != currentLoop) {
1027-
// intentionally leak currentLoop so we don't kill any ports in the child
1028-
// if (currentLoop) CFRelease(currentLoop);
1029-
if (rl) {
1030-
if (!runLoops) {
1031-
runLoops = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
1032-
CFRunLoopRef mainLoop = __CFRunLoopCreate();
1033-
CFDictionarySetValue(runLoops, pthreadPointer(kNilPthreadT), mainLoop);
1034-
}
1035-
CFRetain(rl);
1036-
CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), rl);
1037-
} else {
1038-
CFDictionaryRemoveValue(runLoops, pthreadPointer(pthread_self()));
1039-
}
1040-
}
1041-
__CFSpinUnlock(&loopsLock);
1042-
}
1043-
10441076
CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) {
10451077
CHECK_FOR_FORK();
10461078
CFStringRef result = NULL;
@@ -1610,7 +1642,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
16101642
if (seconds <= 0.0) {
16111643
poll = true;
16121644
}
1613-
if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = CFPORT_NULL;
1645+
if (rl == CFRunLoopGetMain()) _LastMainWaitSet = CFPORT_NULL;
16141646
for (;;) {
16151647
__CFPortSet waitSet = CFPORT_NULL;
16161648
waitSet = CFPORT_NULL;
@@ -1663,7 +1695,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
16631695
}
16641696
#endif
16651697
}
1666-
if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = waitSet;
1698+
if (rl == CFRunLoopGetMain()) _LastMainWaitSet = waitSet;
16671699
__CFRunLoopModeUnlock(rlm);
16681700

16691701
#if DEPLOYMENT_TARGET_MACOSX
@@ -1739,7 +1771,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
17391771
#endif
17401772
if (destroyWaitSet) {
17411773
__CFPortSetFree(waitSet);
1742-
if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = 0;
1774+
if (rl == CFRunLoopGetMain()) _LastMainWaitSet = 0;
17431775
}
17441776
__CFRunLoopLock(rl);
17451777
__CFRunLoopModeLock(rlm);
@@ -2172,6 +2204,49 @@ void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef
21722204
}
21732205
}
21742206

2207+
static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value, void *ctx) {
2208+
CFStringRef modeName = (CFStringRef)value;
2209+
CFRunLoopRef rl = (CFRunLoopRef)ctx;
2210+
__CFRunLoopRemoveAllSources(rl, modeName);
2211+
}
2212+
2213+
static void __CFRunLoopRemoveSourceFromMode(const void *value, void *ctx) {
2214+
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
2215+
CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
2216+
CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]);
2217+
CFRunLoopRemoveSource(rl, rls, modeName);
2218+
}
2219+
2220+
static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName) {
2221+
CHECK_FOR_FORK();
2222+
CFRunLoopModeRef rlm;
2223+
__CFRunLoopLock(rl);
2224+
if (modeName == kCFRunLoopCommonModes) {
2225+
if (NULL != rl->_commonModeItems) {
2226+
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2227+
__CFRunLoopUnlock(rl);
2228+
if (NULL != set) {
2229+
CFSetApplyFunction(set, (__CFRunLoopRemoveSourcesFromCommonMode), (void *)rl);
2230+
CFRelease(set);
2231+
}
2232+
} else {
2233+
__CFRunLoopUnlock(rl);
2234+
}
2235+
} else {
2236+
rlm = __CFRunLoopFindMode(rl, modeName, false);
2237+
__CFRunLoopUnlock(rl);
2238+
if (NULL != rlm && NULL != rlm->_sources) {
2239+
CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources);
2240+
__CFRunLoopModeUnlock(rlm);
2241+
CFTypeRef context[2] = {rl, modeName};
2242+
CFSetApplyFunction(set, (__CFRunLoopRemoveSourceFromMode), (void *)context);
2243+
CFRelease(set);
2244+
} else if (NULL != rlm) {
2245+
__CFRunLoopModeUnlock(rlm);
2246+
}
2247+
}
2248+
}
2249+
21752250
Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
21762251
CHECK_FOR_FORK();
21772252
CFRunLoopModeRef rlm;

0 commit comments

Comments
 (0)