void WorkQueue::registerMachPortEventHandler(mach_port_t machPort, MachPortEventType eventType, const Function<void()>& function) { ASSERT(machPort != MACH_PORT_NULL); dispatch_source_type_t sourceType = 0; switch (eventType) { case MachPortDataAvailable: sourceType = DISPATCH_SOURCE_TYPE_MACH_RECV; break; case MachPortDeadNameNotification: sourceType = DISPATCH_SOURCE_TYPE_MACH_SEND; break; } dispatch_source_t dispatchSource = dispatch_source_create(sourceType, machPort, 0, m_dispatchQueue); EventSource* eventSource = new EventSource(eventType, dispatchSource, function); dispatch_set_context(dispatchSource, eventSource); dispatch_source_set_event_handler_f(dispatchSource, &EventSource::eventHandler); dispatch_source_set_cancel_handler_f(dispatchSource, &EventSource::cancelHandler); dispatch_set_finalizer_f(dispatchSource, &EventSource::finalizeHandler); // Add the source to our set of sources. { MutexLocker locker(m_eventSourcesMutex); ASSERT(!m_eventSources.contains(machPort)); m_eventSources.set(machPort, eventSource); // And start it! dispatch_resume(dispatchSource); } }
void queue::finalizer( operation *op, const queue &q ) { dispatch_set_finalizer_f( d->native, _xdispatch_run_operation ); dispatch_set_context( d->native, op ); dispatch_set_target_queue( d->native, (dispatch_queue_t)q.native() ); }
int main(void) { dispatch_test_start("Dispatch Queue Finalizer"); #ifdef __LP64__ ctxt_magic = (void*)((uintptr_t)arc4random() << 32 | arc4random()); #else ctxt_magic = (void*)arc4random(); #endif // we need a non-NULL value for the tests to work properly if (ctxt_magic == NULL) { ctxt_magic = &ctxt_magic; } dispatch_queue_t q = dispatch_queue_create("com.apple.testing.finalizer", NULL); test_ptr_notnull("dispatch_queue_new", q); dispatch_set_finalizer_f(q, finalize); dispatch_queue_t q_null_context = dispatch_queue_create("com.apple.testing.finalizer.context_null", NULL); dispatch_set_context(q_null_context, NULL); dispatch_set_finalizer_f(q_null_context, never_call); dispatch_release(q_null_context); // Don't test k dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC), dispatch_get_main_queue(), ^{ // Usign async to set the context helps test that blocks are // run before the release as opposed to just thrown away. dispatch_async(q, ^{ dispatch_set_context(q, ctxt_magic); }); dispatch_release(q); });
int main(void) { test_start("Dispatch Queue Finalizer"); #ifdef __LP64__ ctxt_magic = (void*)((uintptr_t)arc4random() << 32 | arc4random()); #else ctxt_magic = (void*)arc4random(); #endif dispatch_queue_t q = dispatch_queue_create(NULL, NULL); test_ptr_notnull("dispatch_queue_new", q); dispatch_set_context(q, ctxt_magic); dispatch_set_finalizer_f(q, finalizer); dispatch_release(q); dispatch_main(); return 0; }
Boolean SCDynamicStoreSetDispatchQueue(SCDynamicStoreRef store, dispatch_queue_t queue) { dispatch_group_t drainGroup = NULL; dispatch_queue_t drainQueue = NULL; dispatch_group_t group = NULL; mach_port_t mp; Boolean ok = FALSE; dispatch_source_t source; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; if (store == NULL) { // sorry, you must provide a session _SCErrorSet(kSCStatusNoStoreSession); return FALSE; } if (queue == NULL) { if (storePrivate->dispatchQueue == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } ok = TRUE; goto cleanup; } if (storePrivate->server == MACH_PORT_NULL) { // sorry, you must have an open session to play _SCErrorSet(kSCStatusNoStoreServer); return FALSE; } if ((storePrivate->dispatchQueue != NULL) || (storePrivate->rls != NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } if (storePrivate->notifyStatus != NotifierNotRegistered) { // sorry, you can only have one notification registered at once... _SCErrorSet(kSCStatusNotifierActive); return FALSE; } /* * mark our using of the SCDynamicStore notifications, create and schedule * the notification port (storePrivate->rlsNotifyPort), and a bunch of other * "setup" */ storePrivate->notifyStatus = Using_NotifierInformViaDispatch; rlsSchedule((void*)store, NULL, NULL); if (storePrivate->rlsNotifyPort == NULL) { /* if we could not schedule the notification */ _SCErrorSet(kSCStatusFailed); goto cleanup; } // retain the dispatch queue storePrivate->dispatchQueue = queue; dispatch_retain(storePrivate->dispatchQueue); // // We've taken a reference to the callers dispatch_queue and we // want to hold on to that reference until we've processed any/all // notifications. To facilitate this we create a group, dispatch // any notification blocks to via that group, and when the caller // has told us to stop the notifications (unschedule) we wait for // the group to empty and use the group's finalizer to release // our reference to the SCDynamicStore. // group = dispatch_group_create(); storePrivate->dispatchGroup = group; CFRetain(store); dispatch_set_context(storePrivate->dispatchGroup, (void *)store); dispatch_set_finalizer_f(storePrivate->dispatchGroup, (dispatch_function_t)CFRelease); // create a dispatch source for the mach notifications mp = CFMachPortGetPort(storePrivate->rlsNotifyPort); source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, queue); if (source == NULL) { SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_source_create() failed")); _SCErrorSet(kSCStatusFailed); goto cleanup; } dispatch_source_set_event_handler(source, ^{ kern_return_t kr; mach_msg_id_t msgid; union { u_int8_t buf[sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE]; mach_msg_empty_rcv_t msg; mach_no_senders_notification_t no_senders; } notify_msg; kr = mach_msg(¬ify_msg.msg.header, // msg MACH_RCV_MSG, // options 0, // send_size sizeof(notify_msg), // rcv_size mp, // rcv_name MACH_MSG_TIMEOUT_NONE, // timeout MACH_PORT_NULL); // notify if (kr != KERN_SUCCESS) { SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore notification handler, kr=0x%x"), kr); return; } msgid = notify_msg.msg.header.msgh_id; CFRetain(store); dispatch_group_async(group, queue, ^{ if (msgid == MACH_NOTIFY_NO_SENDERS) { // re-establish notification and inform the client (void)__SCDynamicStoreReconnectNotifications(store); } rlsPerform(storePrivate); CFRelease(store); }); });