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