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