]> err.no Git - sope/blob - sope-appserver/NGObjWeb/UnixSignalHandler.m
Improved WORepetition's implementation to be more convenient in regards to the 'list...
[sope] / sope-appserver / NGObjWeb / UnixSignalHandler.m
1 /*
2    UnixSignalHandler.m
3
4    Copyright (C) 1995, 1996, 1997 Ovidiu Predescu and Mircea Oancea.
5    
6
7    Author: Ovidiu Predescu <ovidiu@net-community.com>
8    Date: November 1997
9
10    Based on a similar class written by Mircea Oancea in July 1995.
11
12    This file is part of libFoundation.
13
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
18    documentation.
19
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.
26 */
27
28 #if !LIB_FOUNDATION_LIBRARY
29
30 //#include <config.h>
31 #define HAVE_SIGSETMASK 1
32 #define RETSIGTYPE      void
33
34 #include <signal.h>
35
36 //#include "NSObjectMacros.h"
37 #include "common.h"
38 #import <Foundation/NSValue.h>
39 #import <Foundation/NSNotification.h>
40 #import <Foundation/NSNotificationQueue.h>
41 #include "UnixSignalHandler.h"
42
43 static NSString* UnixSignalPendingNotification
44     = @"UnixSignalPendingNotification";
45
46 #if HAVE_SIGSETMASK
47 #  define BSD_SIGNALS 1
48 #elif HAVE_SIGHOLD
49 #  define SYSV_SIGNALS 1
50 #elif defined(__MINGW32__)
51 #  warning "Don't know how to handle signals on Mingw32 !"
52 #else
53 #  error "Don't know how to handle signals!"
54 #endif
55
56 #if !defined(sigmask)
57 # define sigmask(m)     (1 << ((m)-1))
58 #endif
59
60 static RETSIGTYPE signalHandlerFunction (int signum);
61
62 typedef RETSIGTYPE (*PTSignalFunction)(int);
63
64 @interface UnixSignalHandlerListItem : NSObject
65 {
66 @public
67   id observer;
68   SEL selector;
69   BOOL immediatelyNotifyOnSignal;
70   UnixSignalHandlerListItem* nextItem;
71 }
72 - (id)initWithObserver:observer
73   selector:(SEL)selector
74   immediatelyNotifyOnSignal:(BOOL)flag;
75 - (id)removeObserver:observer;
76 - (void)invokeForSignal:(int)signum;
77 @end
78
79
80 @implementation UnixSignalHandlerListItem
81
82 - (id)initWithObserver:anObserver
83   selector:(SEL)aSelector
84   immediatelyNotifyOnSignal:(BOOL)flag
85 {
86   self->observer = anObserver;
87   self->selector = aSelector;
88   self->immediatelyNotifyOnSignal = flag;
89   return self;
90 }
91
92 - (id)removeObserver:anObserver
93 {
94   if (observer == anObserver) {
95     (void)AUTORELEASE(self);
96     return nextItem;
97   }
98   else {
99     nextItem = [nextItem removeObserver:anObserver];
100     return self;
101   }
102 }
103
104 - (void)invokeForSignal:(int)signum
105 {
106   [observer performSelector:selector
107             withObject:[NSNumber numberWithLong:signum]];
108 }
109
110 @end
111
112
113 @interface UnixSignalHandlerList : NSObject
114 {
115 @public
116   UnixSignalHandlerListItem* firstItem;
117   PTSignalFunction oldSignalHandler;
118   BOOL signalsPending;
119 }
120
121 - (void)addObserver:observer
122   selector:(SEL)selector
123   immediatelyNotifyOnSignal:(BOOL)flag;
124 - (void)removeObserver:observer;
125 - (void)invokeIfCalledImmediatelyIs:(BOOL)flag signal:(int)signum;
126
127 @end
128
129
130 @implementation UnixSignalHandlerList
131
132 - (void)addObserver:anObserver
133   selector:(SEL)aSelector
134   immediatelyNotifyOnSignal:(BOOL)flag
135 {
136   UnixSignalHandlerListItem* newItem = [UnixSignalHandlerListItem new];
137
138   newItem->nextItem = firstItem;
139   [newItem initWithObserver:anObserver
140            selector:aSelector
141            immediatelyNotifyOnSignal:flag];
142   firstItem = newItem;
143 }
144
145 - (void)removeObserver:observer
146 {
147   firstItem = [firstItem removeObserver:observer];
148 }
149
150 - (void)invokeIfCalledImmediatelyIs:(BOOL)flag signal:(int)signum
151 {
152   UnixSignalHandlerListItem* item = firstItem;
153
154   if (signalsPending) {
155     while (item) {
156       if (item->immediatelyNotifyOnSignal == flag)
157         [item invokeForSignal:signum];
158       item = item->nextItem;
159     }
160     signalsPending = NO;
161   }
162 }
163
164 @end /* UnixSignalHandlerList */
165
166
167
168 @interface UnixSignalHandler (private)
169 - (void)_pendingSignal:(int)signum;
170 @end
171
172 @implementation UnixSignalHandler
173
174 static NSNotification* notification = nil;
175 static UnixSignalHandler* sharedHandler = nil;
176
177 static RETSIGTYPE signalHandlerFunction (int signum)
178 {
179   /* Temporary disable the signals */
180   [sharedHandler blockAllSignals];
181
182   ((UnixSignalHandlerList*)(sharedHandler->signalHandlers[signum]))
183       ->signalsPending = YES;
184   sharedHandler->signalsPending = YES;
185
186   [[NSNotificationQueue defaultQueue]
187           enqueueNotification:notification
188           postingStyle:NSPostASAP];
189   [sharedHandler _pendingSignal:signum];
190
191   [sharedHandler enableAllSignals];
192 }
193
194 + (void)initialize
195 {
196   static BOOL initialized = NO;
197
198   if (!initialized) {
199     initialized = YES;
200     sharedHandler = [self new];
201     notification = RETAIN([NSNotification
202                             notificationWithName:UnixSignalPendingNotification
203                             object:sharedHandler]);
204     [[NSNotificationCenter defaultCenter]
205           addObserver:self
206           selector:@selector(_dispatch:)
207           name:UnixSignalPendingNotification
208           object:nil];
209   }
210 }
211
212 + (id)sharedHandler
213 {
214     return sharedHandler;
215 }
216
217 - (id)init
218 {
219   int i;
220
221   for (i = 0; i < NSIG; i++)
222     signalHandlers[i] = [UnixSignalHandlerList new];
223
224 #if BSD_SIGNALS
225   currentSigmask = sigblock (0);
226 #endif
227
228   return self;
229 }
230
231 - (void)_pendingSignal:(int)signum
232 {
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];
239 }
240
241 + (void)_dispatch:(NSNotification *)notification
242 {
243   int i;
244
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
247      signal occurred. */
248   
249   if (sharedHandler->signalsPending) {
250     for (i = 0; i < NSIG; i++)
251       [sharedHandler->signalHandlers[i] 
252                     invokeIfCalledImmediatelyIs:NO signal:i];
253     sharedHandler->signalsPending = NO;
254   }
255 }
256
257 - (BOOL)signalsPending
258 {
259     return signalsPending;
260 }
261
262 - (void)addObserver:(id)observer
263   selector:(SEL)selector
264   forSignal:(int)signum
265   immediatelyNotifyOnSignal:(BOOL)flag
266 {
267   BOOL shouldInstall = (signalHandlers[signum]->firstItem == NULL);
268
269   [self blockSignal:signum];
270   [signalHandlers[signum] addObserver:observer
271                           selector:selector
272                           immediatelyNotifyOnSignal:flag];
273   if (shouldInstall)
274 #if HAVE_SIGSET
275     signalHandlers[signum]->oldSignalHandler
276         = (PTSignalFunction)sigset (signum, signalHandlerFunction);
277 #elif HAVE_SIGACTION && !defined(__alpha__)
278     {
279         struct sigaction act, oldact;
280
281         act.sa_handler = (PTSignalFunction)signalHandlerFunction;
282         sigemptyset (&act.sa_mask);
283         act.sa_flags = 0;
284         sigaction (signum, &act, &oldact);
285         signalHandlers[signum]->oldSignalHandler = oldact.sa_handler;
286     }
287 #else
288     signalHandlers[signum]->oldSignalHandler
289         = (PTSignalFunction)signal (signum, signalHandlerFunction);
290 #endif
291   [self enableSignal:signum];
292 }
293
294 - (void)removeObserver:(id)observer
295 {
296   int i;
297
298   for (i = 0; i < NSIG; i++)
299     [self removeObserver:observer forSignal:i];
300 }
301
302 - (void)removeObserver:(id)observer
303   forSignal:(int)signum
304 {
305   [self blockSignal:signum];
306   [signalHandlers[signum] removeObserver:observer];
307   if (signalHandlers[signum]->firstItem == NULL)
308 #if HAVE_SIGSET
309     sigset (signum, signalHandlers[signum]->oldSignalHandler);
310 #else
311     signal (signum, signalHandlers[signum]->oldSignalHandler);
312 #endif
313   [self enableSignal:signum];
314 }
315
316 - (void)blockAllSignals
317 {
318 #if BSD_SIGNALS
319   sigsetmask ((unsigned)-1);
320 #elif SYSV_SIGNALS
321   int i;
322
323   for (i = 0; i < NSIG; i++)
324     sighold (i);
325 #endif
326 }
327
328 - (void)enableAllSignals
329 {
330 #if BSD_SIGNALS
331   sigsetmask (currentSigmask);
332 #elif SYSV_SIGNALS
333   int i;
334
335   for (i = 0; i < NSIG; i++)
336       if ((currentSigmask & sigmask(i)))
337           sigrelse (i);
338 #endif
339 }
340
341 - (void)blockSignal:(int)signum
342 {
343   currentSigmask |= sigmask (signum);
344 #if BSD_SIGNALS
345   sigsetmask (currentSigmask);
346 #elif SYSV_SIGNALS
347   sighold (signum);
348 #endif
349 }
350
351 - (void)enableSignal:(int)signum
352 {
353   currentSigmask &= ~(sigmask (signum));
354 #if BSD_SIGNALS
355   sigsetmask (currentSigmask);
356 #elif SYSV_SIGNALS
357   sigrelse (signum);
358 #endif
359 }
360
361 - (void)waitForSignal:(int)signum
362 {
363 #if BSD_SIGNALS
364   sigpause (sigmask (signum));
365 #elif SYSV_SIGNALS
366   sigpause (signum);
367 #endif
368 }
369
370 @end
371
372 #endif /* !LIB_FOUNDATION_LIBRARY */