CF_EXPORT CFStringRef rwsched_tasklet_CFRunLoopCopyCurrentMode(rwsched_tasklet_ptr_t sched_tasklet, rwsched_CFRunLoopRef rl) { CFStringRef mode; // Validate input paraemters RW_CF_TYPE_VALIDATE(sched_tasklet, rwsched_tasklet_ptr_t); rwsched_instance_ptr_t instance = sched_tasklet->instance; RW_CF_TYPE_VALIDATE(instance, rwsched_instance_ptr_t); // RW_CF_TYPE_VALIDATE(rl, rwsched_CFRunLoopRef); // Call the native CFRunLoop function mode = CFRunLoopCopyCurrentMode(rl); // Return the native CFRunLoop mode return mode; }
int Tcl_WaitForEvent( Tcl_Time *timePtr) /* Maximum block time, or NULL. */ { FileHandler *filePtr; FileHandlerEvent *fileEvPtr; int mask; int waitForFiles; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) { return tclStubs.tcl_WaitForEvent(timePtr); } /* * Start notifier thread if necessary. */ LOCK_NOTIFIER_INIT; if (!notifierCount) { Tcl_Panic("Tcl_WaitForEvent: notifier not initialized"); } if (!notifierThread) { int result; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_attr_setstacksize(&attr, 60 * 1024); result = pthread_create(¬ifierThread, &attr, (void * (*)(void *))NotifierThreadProc, NULL); pthread_attr_destroy(&attr); if (result || !notifierThread) { Tcl_Panic("Tcl_WaitForEvent: unable to start notifier thread"); } } UNLOCK_NOTIFIER_INIT; /* * Place this thread on the list of interested threads, signal the * notifier thread, and wait for a response or a timeout. */ LOCK_NOTIFIER; if (!tsdPtr->runLoop) { Tcl_Panic("Tcl_WaitForEvent: CFRunLoop not initialized"); } waitForFiles = (tsdPtr->numFdBits > 0); if (timePtr != NULL && timePtr->sec == 0 && timePtr->usec == 0) { /* * Cannot emulate a polling select with a polling condition variable. * Instead, pretend to wait for files and tell the notifier thread * what we are doing. The notifier thread makes sure it goes through * select with its select mask in the same state as ours currently is. * We block until that happens. */ waitForFiles = 1; tsdPtr->pollState = POLL_WANT; timePtr = NULL; } else { tsdPtr->pollState = 0; } if (waitForFiles) { /* * Add the ThreadSpecificData structure of this thread to the list of * ThreadSpecificData structures of all threads that are waiting on * file events. */ tsdPtr->nextPtr = waitingListPtr; if (waitingListPtr) { waitingListPtr->prevPtr = tsdPtr; } tsdPtr->prevPtr = 0; waitingListPtr = tsdPtr; tsdPtr->onList = 1; write(triggerPipe, "", 1); } FD_ZERO(&(tsdPtr->readyMasks.readable)); FD_ZERO(&(tsdPtr->readyMasks.writable)); FD_ZERO(&(tsdPtr->readyMasks.exceptional)); if (!tsdPtr->eventReady) { CFTimeInterval waitTime; CFStringRef runLoopMode; if (timePtr == NULL) { waitTime = 1.0e10; /* Wait forever, as per CFRunLoop.c */ } else { waitTime = timePtr->sec + 1.0e-6 * timePtr->usec; } /* * If the run loop is already running (e.g. if Tcl_WaitForEvent was * called recursively), re-run it in a custom run loop mode containing * only the source for the notifier thread, otherwise wakeups from other * sources added to the common run loop modes might get lost. */ if ((runLoopMode = CFRunLoopCopyCurrentMode(tsdPtr->runLoop))) { CFRelease(runLoopMode); runLoopMode = tclEventsOnlyRunLoopMode; } else { runLoopMode = kCFRunLoopDefaultMode; } UNLOCK_NOTIFIER; CFRunLoopRunInMode(runLoopMode, waitTime, TRUE); LOCK_NOTIFIER; } tsdPtr->eventReady = 0; if (waitForFiles && tsdPtr->onList) { /* * Remove the ThreadSpecificData structure of this thread from the * waiting list. Alert the notifier thread to recompute its select * masks - skipping this caused a hang when trying to close a pipe * which the notifier thread was still doing a select on. */ if (tsdPtr->prevPtr) { tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; } else { waitingListPtr = tsdPtr->nextPtr; } if (tsdPtr->nextPtr) { tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; } tsdPtr->nextPtr = tsdPtr->prevPtr = NULL; tsdPtr->onList = 0; write(triggerPipe, "", 1); } /* * Queue all detected file events before returning. */ for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL); filePtr = filePtr->nextPtr) { mask = 0; if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) { mask |= TCL_READABLE; } if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) { mask |= TCL_WRITABLE; } if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) { mask |= TCL_EXCEPTION; } if (!mask) { continue; } /* * Don't bother to queue an event if the mask was previously non-zero * since an event must still be on the queue. */ if (filePtr->readyMask == 0) { fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent)); fileEvPtr->header.proc = FileHandlerEventProc; fileEvPtr->fd = filePtr->fd; Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); } filePtr->readyMask = mask; } UNLOCK_NOTIFIER; return 0; }
/* CF_EXPORT */ void CFNetServiceBrowserStopSearch(CFNetServiceBrowserRef b, CFStreamError* error) { __CFNetServiceBrowser* browser = (__CFNetServiceBrowser*)b; // By default, the error is marked as a cancel CFStreamError extra = {kCFStreamErrorDomainNetServices , kCFNetServicesErrorCancel}; // Make sure error has a value. if (!error) error = &extra; // Lock down the browser __CFSpinLock(&(browser->_lock)); // Make sure there is something to cancel. if (browser->_trigger) { CFRunLoopSourceContext ctxt = { 0, // version browser, // info NULL, // retain NULL, // release NULL, // copyDescription NULL, // equal NULL, // hash NULL, // schedule NULL, // cancel (void(*)(void*))(&_BrowserCancel) // perform }; // Remove the trigger from run loops and modes _CFTypeUnscheduleFromMultipleRunLoops(browser->_trigger, browser->_schedules); // Go ahead and invalidate the trigger _CFTypeInvalidate(browser->_trigger); // Release the trigger now. CFRelease(browser->_trigger); // Need to clean up the service discovery stuff if there is if (browser->_browse) { // Release the underlying service discovery reference DNSServiceRefDeallocate(browser->_browse); browser->_browse = NULL; // Dump all the lists of items. CFDictionaryRemoveAllValues(browser->_found); CFArrayRemoveAllValues(browser->_adds); CFArrayRemoveAllValues(browser->_removes); } // Copy the error into place memmove(&(browser->_error), error, sizeof(error[0])); // Create the cancel source browser->_trigger = CFRunLoopSourceCreate(CFGetAllocator(browser), 0, &ctxt); // If the cancel was created, need to schedule and signal it. if (browser->_trigger) { CFArrayRef schedules = browser->_schedules; CFIndex i, count = CFArrayGetCount(schedules); // Schedule the new trigger _CFTypeScheduleOnMultipleRunLoops(browser->_trigger, schedules); // Signal the cancel for immediate attention. CFRunLoopSourceSignal((CFRunLoopSourceRef)(browser->_trigger)); // Make sure the signal can make it through for (i = 0; i < count; i += 2) { // Grab the run loop for checking CFRunLoopRef runloop = (CFRunLoopRef)CFArrayGetValueAtIndex(schedules, i); // If it's sleeping, need to further check it. if (CFRunLoopIsWaiting(runloop)) { // Grab the mode for further check CFStringRef mode = CFRunLoopCopyCurrentMode(runloop); if (mode) { // If the trigger is in the right mode, need to wake up the run loop. if (CFRunLoopContainsSource(runloop, (CFRunLoopSourceRef)(browser->_trigger), mode)) { CFRunLoopWakeUp(runloop); } // Don't need this anymore. CFRelease(mode); } } } } } // Unlock the browser __CFSpinUnlock(&(browser->_lock)); }