[project @ 2003-01-10 22:08:20 by wolfgang]
[ghc-hetmet.git] / ghc / rts / Signals.c
1 /* -----------------------------------------------------------------------------
2  * $Id: Signals.c,v 1.32 2003/01/10 22:08:20 wolfgang Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Signal processing / handling.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 /* This is non-Posix-compliant.
11    #include "PosixSource.h" 
12 */
13 #include "Rts.h"
14 #include "SchedAPI.h"
15 #include "Schedule.h"
16 #include "Signals.h"
17 #include "RtsUtils.h"
18 #include "RtsFlags.h"
19 #include "StablePriv.h"
20
21 #ifdef alpha_TARGET_ARCH
22 # include <machine/fpu.h>
23 #endif
24
25 #ifdef HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif
28
29 #ifdef HAVE_SIGNAL_H
30 # include <signal.h>
31 #endif
32
33 #include <stdlib.h>
34
35 #ifndef mingw32_TARGET_OS
36
37 #ifndef PAR
38
39 /* SUP: The type of handlers is a little bit, well, doubtful... */
40 static StgInt *handlers = NULL; /* Dynamically grown array of signal handlers */
41 static StgInt nHandlers = 0;    /* Size of handlers array */
42
43 static nat n_haskell_handlers = 0;
44
45 #define N_PENDING_HANDLERS 16
46
47 StgPtr pending_handler_buf[N_PENDING_HANDLERS];
48 StgPtr *next_pending_handler = pending_handler_buf;
49
50 StgInt nocldstop = 0;
51
52 /* -----------------------------------------------------------------------------
53  * Allocate/resize the table of signal handlers.
54  * -------------------------------------------------------------------------- */
55
56 static void
57 more_handlers(I_ sig)
58 {
59     StgInt i;
60
61     if (sig < nHandlers)
62         return;
63
64     if (handlers == NULL)
65         handlers = (StgInt *) malloc((sig + 1) * sizeof(StgInt));
66     else
67         handlers = (StgInt *) realloc(handlers, (sig + 1) * sizeof(StgInt));
68
69     if (handlers == NULL) {
70         // don't fflush(stdout); WORKAROUND bug in Linux glibc
71         barf("VM exhausted (in more_handlers)");
72     }
73     for(i = nHandlers; i <= sig; i++)
74         // Fill in the new slots with default actions
75         handlers[i] = STG_SIG_DFL;
76
77     nHandlers = sig + 1;
78 }
79
80 /* -----------------------------------------------------------------------------
81  * SIGCONT handler
82  *
83  * It seems that shells tend to put stdin back into blocking mode
84  * following a suspend/resume of the process.  Here we arrange to put
85  * it back into non-blocking mode.  We don't do anything to
86  * stdout/stderr because these handles don't get put into non-blocking
87  * mode at all - see the comments on stdout/stderr in PrelHandle.hsc.
88  * -------------------------------------------------------------------------- */
89
90 static void
91 cont_handler(int sig STG_UNUSED)
92 {
93     setNonBlockingFd(0);
94 }
95
96 /* -----------------------------------------------------------------------------
97  * Low-level signal handler
98  *
99  * Places the requested handler on a stack of pending handlers to be
100  * started up at the next context switch.
101  * -------------------------------------------------------------------------- */
102
103 static void
104 generic_handler(int sig)
105 {
106     sigset_t signals;
107
108     /* Can't call allocate from here.  Probably can't call malloc
109        either.  However, we have to schedule a new thread somehow.
110
111        It's probably ok to request a context switch and allow the
112        scheduler to  start the handler thread, but how do we
113        communicate this to the scheduler?
114
115        We need some kind of locking, but with low overhead (i.e. no
116        blocking signals every time around the scheduler).
117        
118        Signal Handlers are atomic (i.e. they can't be interrupted), and
119        we can make use of this.  We just need to make sure the
120        critical section of the scheduler can't be interrupted - the
121        only way to do this is to block signals.  However, we can lower
122        the overhead by only blocking signals when there are any
123        handlers to run, i.e. the set of pending handlers is
124        non-empty.
125     */
126        
127     /* We use a stack to store the pending signals.  We can't
128        dynamically grow this since we can't allocate any memory from
129        within a signal handler.
130
131        Hence unfortunately we have to bomb out if the buffer
132        overflows.  It might be acceptable to carry on in certain
133        circumstances, depending on the signal.  
134     */
135
136     *next_pending_handler++ = deRefStablePtr((StgStablePtr)handlers[sig]);
137
138     // stack full?
139     if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
140         prog_belch("too many pending signals");
141         stg_exit(EXIT_FAILURE);
142     }
143     
144     // re-establish the signal handler, and carry on
145     sigemptyset(&signals);
146     sigaddset(&signals, sig);
147     sigprocmask(SIG_UNBLOCK, &signals, NULL);
148
149     // *always* do the SIGCONT handler, even if the user overrides it.
150     if (sig == SIGCONT) {
151         cont_handler(sig);
152     }
153
154     context_switch = 1;
155 }
156
157 /* -----------------------------------------------------------------------------
158  * Blocking/Unblocking of the user signals
159  * -------------------------------------------------------------------------- */
160
161 static sigset_t userSignals;
162 static sigset_t savedSignals;
163
164 void
165 initUserSignals(void)
166 {
167     sigemptyset(&userSignals);
168 }
169
170 void
171 blockUserSignals(void)
172 {
173     sigprocmask(SIG_BLOCK, &userSignals, &savedSignals);
174 }
175
176 void
177 unblockUserSignals(void)
178 {
179     sigprocmask(SIG_SETMASK, &savedSignals, NULL);
180 }
181
182 rtsBool
183 anyUserHandlers(void)
184 {
185     return n_haskell_handlers != 0;
186 }
187
188 void
189 awaitUserSignals(void)
190 {
191     while (!signals_pending() && !interrupted) {
192         pause();
193     }
194 }
195
196 /* -----------------------------------------------------------------------------
197  * Install a Haskell signal handler.
198  * -------------------------------------------------------------------------- */
199
200 int
201 stg_sig_install(int sig, int spi, StgStablePtr *handler, void *mask)
202 {
203     sigset_t signals, osignals;
204     struct sigaction action;
205     StgInt previous_spi;
206
207     // Block the signal until we figure out what to do
208     // Count on this to fail if the signal number is invalid
209     if (sig < 0 || sigemptyset(&signals) ||
210         sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
211         return STG_SIG_ERR;
212     }
213     
214     more_handlers(sig);
215
216     previous_spi = handlers[sig];
217
218     switch(spi) {
219     case STG_SIG_IGN:
220         handlers[sig] = STG_SIG_IGN;
221         sigdelset(&userSignals, sig);
222         action.sa_handler = SIG_IGN;
223         break;
224         
225     case STG_SIG_DFL:
226         handlers[sig] = STG_SIG_DFL;
227         sigdelset(&userSignals, sig);
228         action.sa_handler = SIG_DFL;
229         break;
230
231     case STG_SIG_HAN:
232     case STG_SIG_RST:
233         handlers[sig] = (StgInt)*handler;
234         sigaddset(&userSignals, sig);
235         action.sa_handler = generic_handler;
236         if (spi == STG_SIG_RST) {
237             action.sa_flags = SA_RESETHAND;
238         }
239         n_haskell_handlers++;
240         break;
241
242     default:
243         barf("stg_sig_install: bad spi");
244     }
245
246     if (mask != NULL)
247         action.sa_mask = *(sigset_t *)mask;
248     else
249         sigemptyset(&action.sa_mask);
250
251     action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
252
253     if (sigaction(sig, &action, NULL) || 
254         sigprocmask(SIG_SETMASK, &osignals, NULL)) 
255     {
256         // need to return an error code, so avoid a stable pointer leak
257         // by freeing the previous handler if there was one.
258         if (previous_spi >= 0) {
259             freeStablePtr(stgCast(StgStablePtr,handlers[sig]));
260             n_haskell_handlers--;
261         }
262         return STG_SIG_ERR;
263     }
264     
265     if (previous_spi == STG_SIG_DFL || previous_spi == STG_SIG_IGN
266         || previous_spi == STG_SIG_ERR) {
267         return previous_spi;
268     } else {
269         *handler = (StgStablePtr)previous_spi;
270         return STG_SIG_HAN;
271     }
272 }
273
274 /* -----------------------------------------------------------------------------
275  * Creating new threads for the pending signal handlers.
276  * -------------------------------------------------------------------------- */
277 void
278 startSignalHandlers(void)
279 {
280   blockUserSignals();
281   
282   while (next_pending_handler != pending_handler_buf) {
283
284     next_pending_handler--;
285
286     scheduleThread(
287        createIOThread(RtsFlags.GcFlags.initialStkSize, 
288                       (StgClosure *) *next_pending_handler));
289   }
290
291   unblockUserSignals();
292 }
293
294 /* ----------------------------------------------------------------------------
295  * Mark signal handlers during GC.
296  *
297  * We do this rather than trying to start all the signal handlers
298  * prior to GC, because that requires extra heap for the new threads.
299  * Signals must be blocked (see blockUserSignals() above) during GC to
300  * avoid race conditions.
301  * -------------------------------------------------------------------------- */
302
303 void
304 markSignalHandlers (evac_fn evac)
305 {
306     StgPtr *p;
307
308     p = next_pending_handler;
309     while (p != pending_handler_buf) {
310         p--;
311         evac((StgClosure **)p);
312     }
313 }
314
315 #else // PAR
316 StgInt 
317 stg_sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
318 {
319     // don't fflush(stdout); WORKAROUND bug in Linux glibc
320     barf("no signal handling support in a parallel implementation");
321 }
322
323 void
324 startSignalHandlers(void)
325 {
326 }
327 #endif
328
329 /* -----------------------------------------------------------------------------
330  * SIGINT handler.
331  *
332  * We like to shutdown nicely after receiving a SIGINT, write out the
333  * stats, write profiling info, close open files and flush buffers etc.
334  * -------------------------------------------------------------------------- */
335 #ifdef SMP
336 pthread_t startup_guy;
337 #endif
338
339 static void
340 shutdown_handler(int sig STG_UNUSED)
341 {
342 #ifdef SMP
343     // if I'm a worker thread, send this signal to the guy who
344     // originally called startupHaskell().  Since we're handling
345     // the signal, it won't be a "send to all threads" type of signal
346     // (according to the POSIX threads spec).
347     if (pthread_self() != startup_guy) {
348         pthread_kill(startup_guy, sig);
349         return;
350     }
351 #endif
352
353     // If we're already trying to interrupt the RTS, terminate with
354     // extreme prejudice.  So the first ^C tries to exit the program
355     // cleanly, and the second one just kills it.
356     if (interrupted) {
357         exit(EXIT_INTERRUPTED);
358     } else {
359         interruptStgRts();
360     }
361 }
362
363 /* -----------------------------------------------------------------------------
364  * Install default signal handlers.
365  *
366  * The RTS installs a default signal handler for catching
367  * SIGINT, so that we can perform an orderly shutdown.
368  *
369  * Haskell code may install their own SIGINT handler, which is
370  * fine, provided they're so kind as to put back the old one
371  * when they de-install.
372  *
373  * In addition to handling SIGINT, the RTS also handles SIGFPE
374  * by ignoring it.  Apparently IEEE requires floating-point
375  * exceptions to be ignored by default, but alpha-dec-osf3
376  * doesn't seem to do so.
377  * -------------------------------------------------------------------------- */
378 void
379 initDefaultHandlers()
380 {
381     struct sigaction action,oact;
382
383 #ifdef SMP
384     startup_guy = pthread_self();
385 #endif
386
387     // install the SIGINT handler
388     action.sa_handler = shutdown_handler;
389     sigemptyset(&action.sa_mask);
390     action.sa_flags = 0;
391     if (sigaction(SIGINT, &action, &oact) != 0) {
392         prog_belch("warning: failed to install SIGINT handler");
393     }
394
395 #ifndef cygwin32_TARGET_OS
396     siginterrupt(SIGINT, 1);    // isn't this the default? --SDM
397 #endif
398
399     // install the SIGCONT handler
400     action.sa_handler = cont_handler;
401     sigemptyset(&action.sa_mask);
402     action.sa_flags = 0;
403     if (sigaction(SIGCONT, &action, &oact) != 0) {
404         prog_belch("warning: failed to install SIGCONT handler");
405     }
406
407     // install the SIGFPE handler
408
409     // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
410     // Apparently IEEE requires floating-point exceptions to be ignored by
411     // default, but alpha-dec-osf3 doesn't seem to do so.
412
413     // Commented out by SDM 2/7/2002: this causes an infinite loop on
414     // some architectures when an integer division by zero occurs: we
415     // don't recover from the floating point exception, and the
416     // program just generates another one immediately.
417 #if 0
418     action.sa_handler = SIG_IGN;
419     sigemptyset(&action.sa_mask);
420     action.sa_flags = 0;
421     if (sigaction(SIGFPE, &action, &oact) != 0) {
422         prog_belch("warning: failed to install SIGFPE handler");
423     }
424 #endif
425
426 #ifdef alpha_TARGET_ARCH
427     ieee_set_fp_control(0);
428 #endif
429 }
430
431 #endif /*! mingw32_TARGET_OS */