]> git.saurik.com Git - apple/cf.git/commitdiff
CF-476.18.tar.gz mac-os-x-1057 v476.18
authorApple <opensource@apple.com>
Tue, 12 May 2009 22:31:02 +0000 (22:31 +0000)
committerApple <opensource@apple.com>
Tue, 12 May 2009 22:31:02 +0000 (22:31 +0000)
CFRunLoop.c

index 5eed26077d38751e4d427f80723ed0bced0dc5b6..824f077fe13feeaa64867e04003ad86f4897daad 100644 (file)
@@ -509,7 +509,7 @@ CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) {
 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
@@ -793,6 +793,32 @@ static CFRunLoopTimerRef __CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rl
 }
 #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;
@@ -865,6 +891,7 @@ static void __CFRunLoopDeallocate(CFTypeRef cf) {
        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);
@@ -941,7 +968,9 @@ static CFRunLoopRef __CFRunLoopCreate(void) {
     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;
 
@@ -952,43 +981,41 @@ 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;
     }
@@ -996,18 +1023,44 @@ __private_extern__ CFRunLoopRef _CFRunLoop0(pthread_t t) {
     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) {
@@ -1020,27 +1073,6 @@ CFRunLoopRef CFRunLoopGetCurrent(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;
@@ -1610,7 +1642,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
     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;
@@ -1663,7 +1695,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
            }
 #endif
        }
-       if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = waitSet;
+       if (rl == CFRunLoopGetMain()) _LastMainWaitSet = waitSet;
        __CFRunLoopModeUnlock(rlm);
 
 #if DEPLOYMENT_TARGET_MACOSX
@@ -1739,7 +1771,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter
 #endif
        if (destroyWaitSet) {
             __CFPortSetFree(waitSet);
-           if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = 0;
+           if (rl == CFRunLoopGetMain()) _LastMainWaitSet = 0;
        }
        __CFRunLoopLock(rl);
        __CFRunLoopModeLock(rlm);
@@ -2172,6 +2204,49 @@ void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef
     }
 }
 
+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;