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