diff options
-rw-r--r-- | Foundation/GTMSignalHandler.h | 18 | ||||
-rw-r--r-- | Foundation/GTMSignalHandler.m | 72 | ||||
-rw-r--r-- | Foundation/GTMSignalHandlerTest.m | 38 |
3 files changed, 59 insertions, 69 deletions
diff --git a/Foundation/GTMSignalHandler.h b/Foundation/GTMSignalHandler.h index da3a3ea..b1c7c2f 100644 --- a/Foundation/GTMSignalHandler.h +++ b/Foundation/GTMSignalHandler.h @@ -23,28 +23,26 @@ // This is a very simple, easy-to-use class for registering handlers that get // called when a specific signal is delivered. Also handy for ignoring // inconvenient signals. Ignoring SIGKILL is not support for what should be -// obvious reasons. +// obvious reasons. You can pass nil for target & action to ignore the signal. // // Example of how to catch SIGABRT and SIGTERM while ignring SIGWINCH: // GTMSignalHandler *abrt, *term, *winch; // abrt = [[GTMSignalHandler alloc] // initWithSignal:SIGABRT // target:self -// handler:@selector(handleAbort:)]; +// action:@selector(handleAbort:)]; // // term = [[GTMSignalHandler alloc] // initWithSignal:SIGTERM // target:self -// handler:@selector(handleTerm:)]; +// action:@selector(handleTerm:)]; // // winch = [[GTMSignalHandler alloc] initWithSignal:SIGWINCH // initWithSignal:SIGWINCH // target:nil -// handler:NULL +// action:NULL // -// And then the signal handler has the triggered signal number boxed in an -// NSNumber: -// -(void)handleTerm:(NSNumber *)signo { +// -(void)handleTerm:(int)signo { // .. do stuff .. // } // @@ -63,13 +61,13 @@ @private int signo_; __weak id target_; - SEL handler_; + SEL action_; } // Returns a retained signal handler object that will invoke |handler| on the // |target| whenever a signal of number |signo| is delivered to the process. -(id)initWithSignal:(int)signo target:(id)target - handler:(SEL)handler; + action:(SEL)action; -@end // GTMSignalHandler +@end diff --git a/Foundation/GTMSignalHandler.m b/Foundation/GTMSignalHandler.m index f88adf6..edfff7d 100644 --- a/Foundation/GTMSignalHandler.m +++ b/Foundation/GTMSignalHandler.m @@ -32,43 +32,33 @@ // File descriptor for the kqueue that will hold all of our signal events. -static int gSignalKQueueFileDescriptor; +static int gSignalKQueueFileDescriptor = 0; // A wrapper around the kqueue file descriptor so we can put it into a // runloop. -static CFSocketRef gRunLoopSocket; +static CFSocketRef gRunLoopSocket = NULL; @interface GTMSignalHandler (PrivateMethods) - -// Invoke |handler_| on the |target_|, passing a boxed |signo_|. - (void)notify; - -// Wrap the file descriptor in a CFSocket and add it to the runloop so that a -// callback function will be called when there's activity on the descriptor. In -// this case, we're interested in new stuff from the kqueue. - (void)addFileDescriptorMonitor:(int)fd; - -// Add ourselves to our global kqueue. - (void)registerWithKQueue; - -// Remove ourseves from our global kqueue. - (void)unregisterWithKQueue; - -@end // PrivateMethods +@end @implementation GTMSignalHandler -(id)init { // Folks shouldn't call init directly, so they get what they deserve. - return [self initWithSignal:0 target:nil handler:NULL]; -} // init - + _GTMDevLog(@"Don't call init, use " + @"initWithSignal:target:action:"); + return [self initWithSignal:0 target:nil action:NULL]; +} - (id)initWithSignal:(int)signo target:(id)target - handler:(SEL)handler { + action:(SEL)action { if ((self = [super init])) { @@ -79,37 +69,36 @@ static CFSocketRef gRunLoopSocket; signo_ = signo; target_ = target; // Don't retain since target will most likely retain us. - handler_ = handler; + action_ = action; GTMAssertSelectorNilOrImplementedWithArguments(target_, - handler_, - @encode(NSNumber *), + action_, + @encode(int), NULL); // We're handling this signal via kqueue, so turn off the usual signal // handling. signal(signo_, SIG_IGN); - if (handler != NULL) { + if (action != NULL) { [self registerWithKQueue]; } } return self; -} // initWithSignal +} - (void)finalize { [self unregisterWithKQueue]; [super finalize]; -} // finalize +} - (void)dealloc { [self unregisterWithKQueue]; [super dealloc]; -} // dealloc - +} // Cribbed from Advanced Mac OS X Programming. static void SocketCallBack(CFSocketRef socketref, CFSocketCallBackType type, @@ -123,8 +112,7 @@ static void SocketCallBack(CFSocketRef socketref, CFSocketCallBackType type, [handler notify]; } -} // SocketCallBack - +} // Cribbed from Advanced Mac OS X Programming - (void)addFileDescriptorMonitor:(int)fd { @@ -154,8 +142,7 @@ static void SocketCallBack(CFSocketRef socketref, CFSocketCallBackType type, bailout: return; -} // addFileDescriptorMonitor - +} - (void)registerWithKQueue { @@ -182,13 +169,12 @@ static void SocketCallBack(CFSocketRef socketref, CFSocketCallBackType type, _GTMDevLog(@"could not add event for signal %d. Errno %d", signo_, errno); // COV_NF_LINE } -} // registerWithKQueue - +} - (void)unregisterWithKQueue { // Short-circuit cases where we didn't actually register a kqueue event. if (signo_ == 0) return; - if (handler_ == 0) return; + if (action_ == nil) return; struct kevent filter; EV_SET(&filter, signo_, EVFILT_SIGNAL, EV_DELETE, 0, 0, self); @@ -198,12 +184,18 @@ static void SocketCallBack(CFSocketRef socketref, CFSocketCallBackType type, _GTMDevLog(@"could not remove event for signal %d. Errno %d", signo_, errno); // COV_NF_LINE } -} // unregisterWithKQueue - +} - (void)notify { - [target_ performSelector:handler_ - withObject:[NSNumber numberWithInt:signo_]]; -} // notify - -@end // GTMSignalHandler + // 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 diff --git a/Foundation/GTMSignalHandlerTest.m b/Foundation/GTMSignalHandlerTest.m index 9dcabf4..a0019f3 100644 --- a/Foundation/GTMSignalHandlerTest.m +++ b/Foundation/GTMSignalHandlerTest.m @@ -16,11 +16,12 @@ // the License. // -#import "GTMSignalHandler.h" #import "GTMSenTestCase.h" +#import "GTMSignalHandler.h" +#import "GTMUnitTestDevLog.h" @interface GTMSignalHandlerTest : GTMTestCase -@end // GTMSignalHandlerTest +@end @interface SignalCounter : NSObject { @public @@ -29,7 +30,7 @@ } - (int)count; - (int)lastSeen; -- (void)countSignal:(NSNumber *)signo; +- (void)countSignal:(int)signo; + (id)signalCounter; @end // SignalCounter @@ -44,11 +45,11 @@ return lastSeenSignal_; } // Count the number of times this signal handler has fired. -- (void)countSignal:(NSNumber *)signo { +- (void)countSignal:(int)signo { signalCount_++; - lastSeenSignal_ = [signo intValue]; -} // countSignal -@end // SignalCounter + lastSeenSignal_ = signo; +} +@end @implementation GTMSignalHandlerTest @@ -56,13 +57,14 @@ - (void)giveSomeLove { NSDate *endTime = [NSDate dateWithTimeIntervalSinceNow:0.5]; [[NSRunLoop currentRunLoop] runUntilDate:endTime]; -} // giveSomeLove - +} - (void)testNillage { GTMSignalHandler *handler; // Just an init should return nil. + [GTMUnitTestDevLog expectString:@"Don't call init, use " + @"initWithSignal:target:action:"]; handler = [[[GTMSignalHandler alloc] init] autorelease]; STAssertNil(handler, nil); @@ -70,11 +72,10 @@ handler = [[[GTMSignalHandler alloc] initWithSignal:0 target:self - handler:@selector(nomnomnom:)] autorelease]; + action:@selector(nomnomnom:)] autorelease]; STAssertNil(handler, nil); -} // testNillage - +} - (void)testSingleHandler { SignalCounter *counter = [SignalCounter signalCounter]; @@ -83,7 +84,7 @@ GTMSignalHandler *handler = [[GTMSignalHandler alloc] initWithSignal:SIGWINCH target:counter - handler:@selector(countSignal:)]; + action:@selector(countSignal:)]; STAssertNotNil(handler, nil); raise(SIGWINCH); [self giveSomeLove]; @@ -102,7 +103,7 @@ STAssertNotNil(counter2, nil); [[[GTMSignalHandler alloc] initWithSignal:SIGUSR1 target:counter2 - handler:@selector(countSignal:)] autorelease]; + action:@selector(countSignal:)] autorelease]; raise(SIGUSR1); [self giveSomeLove]; @@ -123,8 +124,7 @@ STAssertEquals([counter2 count], 1, nil); STAssertEquals([counter2 lastSeen], SIGUSR1, nil); -} // testSingleHandler - +} - (void)testIgnore { SignalCounter *counter = [SignalCounter signalCounter]; @@ -132,12 +132,12 @@ [[[GTMSignalHandler alloc] initWithSignal:SIGUSR1 target:counter - handler:NULL] autorelease]; + action:NULL] autorelease]; raise(SIGUSR1); [self giveSomeLove]; STAssertEquals([counter count], 0, nil); -} // testIgnore +} -@end // GTMSignalHandlerTest +@end |