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