From 5023c1cabeecfae4d3124f043b1543ecac7e4d4f Mon Sep 17 00:00:00 2001 From: dmaclach Date: Tue, 13 Nov 2018 11:14:18 -0800 Subject: Fixed up GTMSignalHandler and deprecated it. (#192) This gets GTMSignalHandler working with libdispatch, and also marks it as deprecated because it is probably easier just to write your own version to call a block instead of the method invocation here. This also makes the tests run again which hasn't been happening for a long time AFAICT. --- Foundation/GTMSignalHandler.m | 156 ++++++++---------------------------------- 1 file changed, 27 insertions(+), 129 deletions(-) (limited to 'Foundation/GTMSignalHandler.m') 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 // for kqueue() and kevent +#import #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 -- cgit v1.2.3