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