aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Foundation/GTMSignalHandler.h18
-rw-r--r--Foundation/GTMSignalHandler.m72
-rw-r--r--Foundation/GTMSignalHandlerTest.m38
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