4 Copyright (C) 1995, 1996, 1997 Ovidiu Predescu and Mircea Oancea.
7 Author: Ovidiu Predescu <ovidiu@net-community.com>
10 Based on a similar class written by Mircea Oancea in July 1995.
12 This file is part of libFoundation.
14 Permission to use, copy, modify, and distribute this software and its
15 documentation for any purpose and without fee is hereby granted, provided
16 that the above copyright notice appear in all copies and that both that
17 copyright notice and this permission notice appear in supporting
20 We disclaim all warranties with regard to this software, including all
21 implied warranties of merchantability and fitness, in no event shall
22 we be liable for any special, indirect or consequential damages or any
23 damages whatsoever resulting from loss of use, data or profits, whether in
24 an action of contract, negligence or other tortious action, arising out of
25 or in connection with the use or performance of this software.
28 #if !LIB_FOUNDATION_LIBRARY
31 #define HAVE_SIGSETMASK 1
32 #define RETSIGTYPE void
36 //#include "NSObjectMacros.h"
38 #import <Foundation/NSValue.h>
39 #import <Foundation/NSNotification.h>
40 #import <Foundation/NSNotificationQueue.h>
41 #include "UnixSignalHandler.h"
43 static NSString* UnixSignalPendingNotification
44 = @"UnixSignalPendingNotification";
47 # define BSD_SIGNALS 1
49 # define SYSV_SIGNALS 1
50 #elif defined(__MINGW32__)
51 # warning "Don't know how to handle signals on Mingw32 !"
53 # error "Don't know how to handle signals!"
57 # define sigmask(m) (1 << ((m)-1))
60 static RETSIGTYPE signalHandlerFunction (int signum);
62 typedef RETSIGTYPE (*PTSignalFunction)(int);
64 @interface UnixSignalHandlerListItem : NSObject
69 BOOL immediatelyNotifyOnSignal;
70 UnixSignalHandlerListItem* nextItem;
72 - (id)initWithObserver:observer
73 selector:(SEL)selector
74 immediatelyNotifyOnSignal:(BOOL)flag;
75 - (id)removeObserver:observer;
76 - (void)invokeForSignal:(int)signum;
80 @implementation UnixSignalHandlerListItem
82 - (id)initWithObserver:anObserver
83 selector:(SEL)aSelector
84 immediatelyNotifyOnSignal:(BOOL)flag
86 self->observer = anObserver;
87 self->selector = aSelector;
88 self->immediatelyNotifyOnSignal = flag;
92 - (id)removeObserver:anObserver
94 if (observer == anObserver) {
95 (void)AUTORELEASE(self);
99 nextItem = [nextItem removeObserver:anObserver];
104 - (void)invokeForSignal:(int)signum
106 [observer performSelector:selector
107 withObject:[NSNumber numberWithLong:signum]];
113 @interface UnixSignalHandlerList : NSObject
116 UnixSignalHandlerListItem* firstItem;
117 PTSignalFunction oldSignalHandler;
121 - (void)addObserver:observer
122 selector:(SEL)selector
123 immediatelyNotifyOnSignal:(BOOL)flag;
124 - (void)removeObserver:observer;
125 - (void)invokeIfCalledImmediatelyIs:(BOOL)flag signal:(int)signum;
130 @implementation UnixSignalHandlerList
132 - (void)addObserver:anObserver
133 selector:(SEL)aSelector
134 immediatelyNotifyOnSignal:(BOOL)flag
136 UnixSignalHandlerListItem* newItem = [UnixSignalHandlerListItem new];
138 newItem->nextItem = firstItem;
139 [newItem initWithObserver:anObserver
141 immediatelyNotifyOnSignal:flag];
145 - (void)removeObserver:observer
147 firstItem = [firstItem removeObserver:observer];
150 - (void)invokeIfCalledImmediatelyIs:(BOOL)flag signal:(int)signum
152 UnixSignalHandlerListItem* item = firstItem;
154 if (signalsPending) {
156 if (item->immediatelyNotifyOnSignal == flag)
157 [item invokeForSignal:signum];
158 item = item->nextItem;
164 @end /* UnixSignalHandlerList */
168 @interface UnixSignalHandler (private)
169 - (void)_pendingSignal:(int)signum;
172 @implementation UnixSignalHandler
174 static NSNotification* notification = nil;
175 static UnixSignalHandler* sharedHandler = nil;
177 static RETSIGTYPE signalHandlerFunction (int signum)
179 /* Temporary disable the signals */
180 [sharedHandler blockAllSignals];
182 ((UnixSignalHandlerList*)(sharedHandler->signalHandlers[signum]))
183 ->signalsPending = YES;
184 sharedHandler->signalsPending = YES;
186 [[NSNotificationQueue defaultQueue]
187 enqueueNotification:notification
188 postingStyle:NSPostASAP];
189 [sharedHandler _pendingSignal:signum];
191 [sharedHandler enableAllSignals];
196 static BOOL initialized = NO;
200 sharedHandler = [self new];
201 notification = RETAIN([NSNotification
202 notificationWithName:UnixSignalPendingNotification
203 object:sharedHandler]);
204 [[NSNotificationCenter defaultCenter]
206 selector:@selector(_dispatch:)
207 name:UnixSignalPendingNotification
214 return sharedHandler;
221 for (i = 0; i < NSIG; i++)
222 signalHandlers[i] = [UnixSignalHandlerList new];
225 currentSigmask = sigblock (0);
231 - (void)_pendingSignal:(int)signum
233 /* Notify all the handlers that listen for the signal signum immediately.
234 Only those handlers that have requested an immediate notification on
235 signal are invoked here. Those that want to be called after the signal
236 occured are invoked at a later time, when the current NSRunLoop finishes
237 the current cycle. */
238 [signalHandlers[signum] invokeIfCalledImmediatelyIs:YES signal:signum];
241 + (void)_dispatch:(NSNotification *)notification
245 /* Notify all the handlers that have requested to be called after the current
246 NSRunLoop cycle has finished. The others were already called when the
249 if (sharedHandler->signalsPending) {
250 for (i = 0; i < NSIG; i++)
251 [sharedHandler->signalHandlers[i]
252 invokeIfCalledImmediatelyIs:NO signal:i];
253 sharedHandler->signalsPending = NO;
257 - (BOOL)signalsPending
259 return signalsPending;
262 - (void)addObserver:(id)observer
263 selector:(SEL)selector
264 forSignal:(int)signum
265 immediatelyNotifyOnSignal:(BOOL)flag
267 BOOL shouldInstall = (signalHandlers[signum]->firstItem == NULL);
269 [self blockSignal:signum];
270 [signalHandlers[signum] addObserver:observer
272 immediatelyNotifyOnSignal:flag];
275 signalHandlers[signum]->oldSignalHandler
276 = (PTSignalFunction)sigset (signum, signalHandlerFunction);
277 #elif HAVE_SIGACTION && !defined(__alpha__)
279 struct sigaction act, oldact;
281 act.sa_handler = (PTSignalFunction)signalHandlerFunction;
282 sigemptyset (&act.sa_mask);
284 sigaction (signum, &act, &oldact);
285 signalHandlers[signum]->oldSignalHandler = oldact.sa_handler;
288 signalHandlers[signum]->oldSignalHandler
289 = (PTSignalFunction)signal (signum, signalHandlerFunction);
291 [self enableSignal:signum];
294 - (void)removeObserver:(id)observer
298 for (i = 0; i < NSIG; i++)
299 [self removeObserver:observer forSignal:i];
302 - (void)removeObserver:(id)observer
303 forSignal:(int)signum
305 [self blockSignal:signum];
306 [signalHandlers[signum] removeObserver:observer];
307 if (signalHandlers[signum]->firstItem == NULL)
309 sigset (signum, signalHandlers[signum]->oldSignalHandler);
311 signal (signum, signalHandlers[signum]->oldSignalHandler);
313 [self enableSignal:signum];
316 - (void)blockAllSignals
319 sigsetmask ((unsigned)-1);
323 for (i = 0; i < NSIG; i++)
328 - (void)enableAllSignals
331 sigsetmask (currentSigmask);
335 for (i = 0; i < NSIG; i++)
336 if ((currentSigmask & sigmask(i)))
341 - (void)blockSignal:(int)signum
343 currentSigmask |= sigmask (signum);
345 sigsetmask (currentSigmask);
351 - (void)enableSignal:(int)signum
353 currentSigmask &= ~(sigmask (signum));
355 sigsetmask (currentSigmask);
361 - (void)waitForSignal:(int)signum
364 sigpause (sigmask (signum));
372 #endif /* !LIB_FOUNDATION_LIBRARY */