user187676
user187676

Reputation:

GCD and RunLoops

In my app I add an CFMachPortRef (via CFMachPortCreateRunLoopSource) to a threads CFRunLoop

Now i was asking myself, can this be done using GCD? Let's say instead of spawning my own NSThread and add the created CFRunLoopSourceRef to its run loop via CFRunLoopAddSource, add the event port to a dispatch's runloop?

I think this will most likely not work due to the inner workings of GCD, but I really don't know.

Update


I got this so far, however neither the callback function for the event tap nor the dispatch_source_event_handler block is called. Any ideas?

CFMachPortRef port = CGEventTapCreate(kCGSessionEventTap,
                                      kCGHeadInsertEventTap,
                                      opts,
                                      desc_.eventMask,
                                      _CGEventCallback,
                                      self);

// create dispatch source
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
                                                  CFMachPortGetPort(port),
                                                  0,
                                                  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));

// set event handler
dispatch_source_set_event_handler(source, ^{
    printf("handle me!\n");
});

dispatch_resume(source);

Upvotes: 2

Views: 2924

Answers (3)

popipo
popipo

Reputation: 1

Invoke dispatch_resume method must be in the same thread that invoke mach_msg method about port. you can try it.

Upvotes: 0

James
James

Reputation: 1371

To schedule the callbacks from a notification port on a GCD queue you can use IONotificationPortSetDispatchQueue instead of using CFRunLoopAddSource with a Runloop.

Example:

IOServiceOpen(driver, mach_task_self(), 0, &connection);

notifyPort = IONotificationPortCreate(kIOMasterPortDefault);

IOServiceAddInterestNotification(
  notifyPort,
  driver,
  kIOGeneralInterest,
  myCallback,
  NULL, //refcon
  &notificationObject
);

// Instead of this:
// CFRunLoopAddSource(CFRunLoopGetCurrent(),
//                    IONotificationPortGetRunLoopSource(notifyPort),
//                    kCFRunLoopDefaultMode);
// do this:
IONotificationPortSetDispatchQueue(notifyPort, myQueue);

This will cause the myCallback() handler to be called on the GCD queue myQueue.

Upvotes: 0

Brian Webster
Brian Webster

Reputation: 12045

You can actually use GCD to monitor a Mach port, using the dispatch_source_create() function. The code would look something like this:

mach_port_t myPort; //assume you have this already
dispatch_source_t portSource;

portSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, myPort, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT));
dispatch_source_set_event_handler(portSource, ^(void) { //code for handling incoming message here });

dispatch_resume(portSource);

Whenever a message comes into the port, the block you pass in as the event handler should get called, and you can handle the message there. This example just uses the global queue provided by GCD to handle the message, but you can create a custom queue if you'd like.

Upvotes: 2

Related Questions