aboutsummaryrefslogtreecommitdiff
path: root/Foundation/GTMSignalHandler.m
diff options
context:
space:
mode:
Diffstat (limited to 'Foundation/GTMSignalHandler.m')
-rw-r--r--Foundation/GTMSignalHandler.m156
1 files changed, 27 insertions, 129 deletions
diff --git a/Foundation/GTMSignalHandler.m b/Foundation/GTMSignalHandler.m
index 05ee826..4d4f3e2 100644
--- a/Foundation/GTMSignalHandler.m
+++ b/Foundation/GTMSignalHandler.m
@@ -18,9 +18,8 @@
#import "GTMSignalHandler.h"
#import "GTMDefines.h"
-#import "GTMTypeCasting.h"
-#import <sys/event.h> // for kqueue() and kevent
+#import <dispatch/dispatch.h>
#import "GTMDebugSelectorValidation.h"
// Simplifying assumption: No more than one handler for a particular signal is
@@ -31,22 +30,6 @@
// handlers interested in a particular signal, but not really worth it for apps
// that register the handlers at startup and don't change them.
-
-// File descriptor for the kqueue that will hold all of our signal events.
-static int gSignalKQueueFileDescriptor = 0;
-
-// A wrapper around the kqueue file descriptor so we can put it into a
-// runloop.
-static CFSocketRef gRunLoopSocket = NULL;
-
-
-@interface GTMSignalHandler (PrivateMethods)
-- (void)notify;
-- (void)addFileDescriptorMonitor:(int)fd;
-- (void)registerWithKQueue;
-@end
-
-
@implementation GTMSignalHandler
-(id)init {
@@ -67,20 +50,34 @@ static CFSocketRef gRunLoopSocket = NULL;
return nil;
}
- signo_ = signo;
- target_ = target; // Don't retain since target will most likely retain us.
- action_ = action;
- GTMAssertSelectorNilOrImplementedWithArguments(target_,
- action_,
+ GTMAssertSelectorNilOrImplementedWithArguments(target,
+ action,
@encode(int),
NULL);
- // We're handling this signal via kqueue, so turn off the usual signal
+ // We're handling this signal via libdispatch, so turn off the usual signal
// handling.
- signal(signo_, SIG_IGN);
+ if (signal(signo, SIG_IGN) == SIG_ERR) {
+ _GTMDevLog(@"could not ignore signal %d. Errno %d", signo, errno); // COV_NF_LINE
+ }
if (action != NULL) {
- [self registerWithKQueue];
+ signalSource_ = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL,
+ signo,
+ 0,
+ dispatch_get_main_queue());
+ dispatch_source_set_event_handler(signalSource_, ^(void) {
+ NSMethodSignature *methodSig
+ = [target methodSignatureForSelector:action];
+ _GTMDevAssert(methodSig != nil, @"failed to get the signature?");
+ NSInvocation *invocation
+ = [NSInvocation invocationWithMethodSignature:methodSig];
+ [invocation setTarget:target];
+ [invocation setSelector:action];
+ [invocation setArgument:(void*)&signo atIndex:2];
+ [invocation invoke];
+ });
+ dispatch_resume(signalSource_);
}
}
return self;
@@ -91,112 +88,13 @@ static CFSocketRef gRunLoopSocket = NULL;
[super dealloc];
}
-// Cribbed from Advanced Mac OS X Programming.
-static void SocketCallBack(CFSocketRef socketref, CFSocketCallBackType type,
- CFDataRef address, const void *data, void *info) {
- // We're using CFRunLoop calls here. Even when used on the main thread, they
- // don't trigger the draining of the main application's autorelease pool that
- // NSRunLoop provides. If we're used in a UI-less app, this means that
- // autoreleased objects would never go away, so we provide our own pool here.
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- struct kevent event;
-
- if (kevent(gSignalKQueueFileDescriptor, NULL, 0, &event, 1, NULL) == -1) {
- _GTMDevLog(@"could not pick up kqueue event. Errno %d", errno); // COV_NF_LINE
- } else {
- GTMSignalHandler *handler = GTM_STATIC_CAST(GTMSignalHandler, event.udata);
- [handler notify];
- }
-
- [pool drain];
-}
-
-// Cribbed from Advanced Mac OS X Programming
-- (void)addFileDescriptorMonitor:(int)fd {
- CFSocketContext context = { 0, NULL, NULL, NULL, NULL };
-
- gRunLoopSocket = CFSocketCreateWithNative(kCFAllocatorDefault,
- fd,
- kCFSocketReadCallBack,
- SocketCallBack,
- &context);
- if (gRunLoopSocket == NULL) {
- _GTMDevLog(@"could not CFSocketCreateWithNative"); // COV_NF_LINE
- goto bailout; // COV_NF_LINE
- }
-
- CFRunLoopSourceRef rls;
- rls = CFSocketCreateRunLoopSource(NULL, gRunLoopSocket, 0);
- if (rls == NULL) {
- _GTMDevLog(@"could not create a run loop source"); // COV_NF_LINE
- goto bailout; // COV_NF_LINE
- }
-
- CFRunLoopAddSource(CFRunLoopGetCurrent(), rls,
- kCFRunLoopDefaultMode);
- CFRelease(rls);
-
- bailout:
- return;
-
-}
-
-- (void)registerWithKQueue {
-
- // Make sure we have our kqueue.
- if (gSignalKQueueFileDescriptor == 0) {
- gSignalKQueueFileDescriptor = kqueue();
-
- if (gSignalKQueueFileDescriptor == -1) {
- _GTMDevLog(@"could not make signal kqueue. Errno %d", errno); // COV_NF_LINE
- return; // COV_NF_LINE
- }
-
- // Add the kqueue file descriptor to the runloop.
- [self addFileDescriptorMonitor:gSignalKQueueFileDescriptor];
- }
-
- // Add a new event for the signal.
- struct kevent filter;
- EV_SET(&filter, signo_, EVFILT_SIGNAL, EV_ADD | EV_ENABLE | EV_CLEAR,
- 0, 0, self);
-
- const struct timespec noWait = { 0, 0 };
- if (kevent(gSignalKQueueFileDescriptor, &filter, 1, NULL, 0, &noWait) != 0) {
- _GTMDevLog(@"could not add event for signal %d. Errno %d", signo_, errno); // COV_NF_LINE
- }
-
-}
- (void)invalidate {
- // Short-circuit cases where we didn't actually register a kqueue event.
- if (signo_ == 0) return;
- if (action_ == nil) return;
-
- struct kevent filter;
- EV_SET(&filter, signo_, EVFILT_SIGNAL, EV_DELETE, 0, 0, self);
-
- const struct timespec noWait = { 0, 0 };
- if (kevent(gSignalKQueueFileDescriptor, &filter, 1, NULL, 0, &noWait) != 0) {
- _GTMDevLog(@"could not remove event for signal %d. Errno %d", signo_, errno); // COV_NF_LINE
+ if (signalSource_) {
+ dispatch_source_cancel(signalSource_);
+ dispatch_release(signalSource_);
+ signalSource_ = NULL;
}
-
- // Set action_ to nil so that if invalidate is called on us twice,
- // nothing happens.
- action_ = nil;
-}
-
-- (void)notify {
- // Now, fire the selector
- NSMethodSignature *methodSig = [target_ methodSignatureForSelector:action_];
- _GTMDevAssert(methodSig != nil, @"failed to get the signature?");
- NSInvocation *invocation
- = [NSInvocation invocationWithMethodSignature:methodSig];
- [invocation setTarget:target_];
- [invocation setSelector:action_];
- [invocation setArgument:&signo_ atIndex:2];
- [invocation invoke];
}
@end