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