@@ -509,7 +509,7 @@ CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) {
509
509
static void __CFRunLoopSourceSchedule (CFRunLoopSourceRef rls , CFRunLoopRef rl , CFRunLoopModeRef rlm ) { /* DOES CALLOUT */
510
510
__CFRunLoopSourceLock (rls );
511
511
if (NULL == rls -> _runLoops ) {
512
- rls -> _runLoops = CFBagCreateMutable (CFGetAllocator ( rls ) , 0 , NULL );
512
+ rls -> _runLoops = CFBagCreateMutable (kCFAllocatorSystemDefault , 0 , NULL );
513
513
}
514
514
CFBagAddValue (rls -> _runLoops , rl );
515
515
__CFRunLoopSourceUnlock (rls ); // have to unlock before the callout -- cannot help clients with safety
@@ -793,6 +793,32 @@ static CFRunLoopTimerRef __CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rl
793
793
}
794
794
#endif
795
795
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
+
796
822
static void __CFRunLoopDeallocateSources (const void * value , void * context ) {
797
823
CFRunLoopModeRef rlm = (CFRunLoopModeRef )value ;
798
824
CFRunLoopRef rl = (CFRunLoopRef )context ;
@@ -865,6 +891,7 @@ static void __CFRunLoopDeallocate(CFTypeRef cf) {
865
891
three lines. */
866
892
__CFRunLoopSetDeallocating (rl );
867
893
if (NULL != rl -> _modes ) {
894
+ CFSetApplyFunction (rl -> _modes , (__CFRunLoopCleanseSources ), rl ); // remove references to rl
868
895
CFSetApplyFunction (rl -> _modes , (__CFRunLoopDeallocateSources ), rl );
869
896
CFSetApplyFunction (rl -> _modes , (__CFRunLoopDeallocateObservers ), rl );
870
897
CFSetApplyFunction (rl -> _modes , (__CFRunLoopDeallocateTimers ), rl );
@@ -941,7 +968,9 @@ static CFRunLoopRef __CFRunLoopCreate(void) {
941
968
return loop ;
942
969
}
943
970
944
- static CFMutableDictionaryRef runLoops = NULL ;
971
+ static void __CFRunLoopRemoveAllSources (CFRunLoopRef rl , CFStringRef modeName );
972
+
973
+ static CFMutableDictionaryRef __CFRunLoops = NULL ;
945
974
static char setMainLoop = 0 ;
946
975
static CFSpinLock_t loopsLock = CFSpinLockInit ;
947
976
@@ -952,62 +981,86 @@ static CFSpinLock_t loopsLock = CFSpinLockInit;
952
981
// fetch the main thread's pthread_t from the pthreads subsystem.
953
982
954
983
// 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 ;
957
986
__CFSpinLock (& loopsLock );
958
- if (!runLoops ) {
987
+ if (!__CFRunLoops ) {
959
988
__CFSpinUnlock (& loopsLock );
960
- CFMutableDictionaryRef dict = CFDictionaryCreateMutable (kCFAllocatorSystemDefault , 0 , NULL , NULL );
989
+ CFMutableDictionaryRef dict = CFDictionaryCreateMutable (kCFAllocatorSystemDefault , 0 , NULL , & kCFTypeDictionaryValueCallBacks );
961
990
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 )) {
964
993
CFRelease (dict );
965
- CFRelease (mainLoop );
966
994
}
995
+ CFRelease (mainLoop );
967
996
__CFSpinLock (& loopsLock );
968
997
}
969
998
if (pthread_main_np () && pthread_equal (t , pthread_self ())) {
970
999
t = kNilPthreadT ;
971
1000
}
972
- loop = (CFRunLoopRef )CFDictionaryGetValue (runLoops , pthreadPointer (t ));
1001
+ loop = (CFRunLoopRef )CFDictionaryGetValue (__CFRunLoops , pthreadPointer (t ));
973
1002
if (!loop ) {
974
1003
__CFSpinUnlock (& loopsLock );
975
1004
CFRunLoopRef newLoop = __CFRunLoopCreate ();
976
- __CFGetThreadSpecificData (); // just cause the thread finalizer to be called as a side effect
977
1005
__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 );
983
1009
loop = newLoop ;
984
1010
}
1011
+ CFRelease (newLoop );
985
1012
}
986
1013
if (!setMainLoop && pthread_main_np ()) {
987
1014
if (pthread_equal (t , kNilPthreadT )) {
988
- CFDictionarySetValue (runLoops , pthreadPointer (pthread_self ()), loop );
1015
+ CFDictionarySetValue (__CFRunLoops , pthreadPointer (pthread_self ()), loop );
989
1016
} 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 );
992
1019
}
993
1020
setMainLoop = 1 ;
994
1021
}
995
1022
__CFSpinUnlock (& loopsLock );
996
1023
return loop ;
997
1024
}
998
1025
999
- __private_extern__ void _CFRunLoop1 (void ) {
1026
+ // Called for each thread as it exits
1027
+ static void __CFFinalizeRunLoop (void * arg ) {
1028
+ CFRunLoopRef rl = NULL ;
1000
1029
__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 ()));
1008
1034
}
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 ()));
1009
1061
}
1010
1062
__CFSpinUnlock (& loopsLock );
1063
+ }
1011
1064
}
1012
1065
1013
1066
CFRunLoopRef CFRunLoopGetMain (void ) {
@@ -1020,27 +1073,6 @@ CFRunLoopRef CFRunLoopGetCurrent(void) {
1020
1073
return _CFRunLoop0 (pthread_self ());
1021
1074
}
1022
1075
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
-
1044
1076
CFStringRef CFRunLoopCopyCurrentMode (CFRunLoopRef rl ) {
1045
1077
CHECK_FOR_FORK ();
1046
1078
CFStringRef result = NULL ;
@@ -1610,7 +1642,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
1610
1642
if (seconds <= 0.0 ) {
1611
1643
poll = true;
1612
1644
}
1613
- if (rl == _CFRunLoop0 ( kNilPthreadT )) _LastMainWaitSet = CFPORT_NULL ;
1645
+ if (rl == CFRunLoopGetMain ( )) _LastMainWaitSet = CFPORT_NULL ;
1614
1646
for (;;) {
1615
1647
__CFPortSet waitSet = CFPORT_NULL ;
1616
1648
waitSet = CFPORT_NULL ;
@@ -1663,7 +1695,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
1663
1695
}
1664
1696
#endif
1665
1697
}
1666
- if (rl == _CFRunLoop0 ( kNilPthreadT )) _LastMainWaitSet = waitSet ;
1698
+ if (rl == CFRunLoopGetMain ( )) _LastMainWaitSet = waitSet ;
1667
1699
__CFRunLoopModeUnlock (rlm );
1668
1700
1669
1701
#if DEPLOYMENT_TARGET_MACOSX
@@ -1739,7 +1771,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
1739
1771
#endif
1740
1772
if (destroyWaitSet ) {
1741
1773
__CFPortSetFree (waitSet );
1742
- if (rl == _CFRunLoop0 ( kNilPthreadT )) _LastMainWaitSet = 0 ;
1774
+ if (rl == CFRunLoopGetMain ( )) _LastMainWaitSet = 0 ;
1743
1775
}
1744
1776
__CFRunLoopLock (rl );
1745
1777
__CFRunLoopModeLock (rlm );
@@ -2172,6 +2204,49 @@ void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef
2172
2204
}
2173
2205
}
2174
2206
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
+
2175
2250
Boolean CFRunLoopContainsObserver (CFRunLoopRef rl , CFRunLoopObserverRef rlo , CFStringRef modeName ) {
2176
2251
CHECK_FOR_FORK ();
2177
2252
CFRunLoopModeRef rlm ;
0 commit comments