Ejemplo n.º 1
0
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);
    }
}
Ejemplo n.º 2
0
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);
	});
Ejemplo n.º 4
0
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(&notify_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);
		});
	});