开发者

GCD and RunLoops

开发者 https://www.devze.com 2023-01-07 16:03 出处:网络
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

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 开发者_如何学JAVAsource = 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);


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.


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.


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

0

精彩评论

暂无评论...
验证码 换一张
取 消