[project @ 2002-12-05 14:20:55 by stolz]
[ghc-hetmet.git] / ghc / rts / Signals.c
1 /* -----------------------------------------------------------------------------
2  * $Id: Signals.c,v 1.30 2002/12/05 14:20:55 stolz Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Signal processing / handling.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 /* This is non-Posix-compliant.
11    #include "PosixSource.h" 
12 */
13 #include "Rts.h"
14 #include "SchedAPI.h"
15 #include "Schedule.h"
16 #include "Signals.h"
17 #include "RtsUtils.h"
18 #include "RtsFlags.h"
19 #include "StablePriv.h"
20
21 #ifdef alpha_TARGET_ARCH
22 # include <machine/fpu.h>
23 #endif
24
25 #ifdef HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif
28
29 #ifdef HAVE_SIGNAL_H
30 # include <signal.h>
31 #endif
32
33 #include <stdlib.h>
34
35 #ifndef mingw32_TARGET_OS
36
37 #ifndef PAR
38
39 /* SUP: The type of handlers is a little bit, well, doubtful... */
40 static StgInt *handlers = NULL; /* Dynamically grown array of signal handlers */
41 static StgInt nHandlers = 0;    /* Size of handlers array */
42
43 static nat n_haskell_handlers = 0;
44
45 #define N_PENDING_HANDLERS 16
46
47 StgPtr pending_handler_buf[N_PENDING_HANDLERS];
48 StgPtr *next_pending_handler = pending_handler_buf;
49
50 StgInt nocldstop = 0;
51
52 /* -----------------------------------------------------------------------------
53  * Allocate/resize the table of signal handlers.
54  * -------------------------------------------------------------------------- */
55
56 static void
57 more_handlers(I_ sig)
58 {
59     StgInt i;
60
61     if (sig < nHandlers)
62         return;
63
64     if (handlers == NULL)
65         handlers = (StgInt *) malloc((sig + 1) * sizeof(StgInt));
66     else
67         handlers = (StgInt *) realloc(handlers, (sig + 1) * sizeof(StgInt));
68
69     if (handlers == NULL) {
70         // don't fflush(stdout); WORKAROUND bug in Linux glibc
71         barf("VM exhausted (in more_handlers)");
72     }
73     for(i = nHandlers; i <= sig; i++)
74         // Fill in the new slots with default actions
75         handlers[i] = STG_SIG_DFL;
76
77     nHandlers = sig + 1;
78 }
79
80 /* -----------------------------------------------------------------------------
81  * SIGCONT handler
82  *
83  * It seems that shells tend to put stdin back into blocking mode
84  * following a suspend/resume of the process.  Here we arrange to put
85  * it back into non-blocking mode.  We don't do anything to
86  * stdout/stderr because these handles don't get put into non-blocking
87  * mode at all - see the comments on stdout/stderr in PrelHandle.hsc.
88  * -------------------------------------------------------------------------- */
89
90 static void
91 cont_handler(int sig STG_UNUSED)
92 {
93     setNonBlockingFd(0);
94 }
95
96 /* -----------------------------------------------------------------------------
97  * Low-level signal handler
98  *
99  * Places the requested handler on a stack of pending handlers to be
100  * started up at the next context switch.
101  * -------------------------------------------------------------------------- */
102
103 static void
104 generic_handler(int sig)
105 {
106     sigset_t signals;
107
108     /* Can't call allocate from here.  Probably can't call malloc
109        either.  However, we have to schedule a new thread somehow.
110
111        It's probably ok to request a context switch and allow the
112        scheduler to  start the handler thread, but how do we
113        communicate this to the scheduler?
114
115        We need some kind of locking, but with low overhead (i.e. no
116        blocking signals every time around the scheduler).
117        
118        Signal Handlers are atomic (i.e. they can't be interrupted), and
119        we can make use of this.  We just need to make sure the
120        critical section of the scheduler can't be interrupted - the
121        only way to do this is to block signals.  However, we can lower
122        the overhead by only blocking signals when there are any
123        handlers to run, i.e. the set of pending handlers is
124        non-empty.
125     */
126        
127     /* We use a stack to store the pending signals.  We can't
128        dynamically grow this since we can't allocate any memory from
129        within a signal handler.
130
131        Hence unfortunately we have to bomb out if the buffer
132        overflows.  It might be acceptable to carry on in certain
133        circumstances, depending on the signal.  
134     */
135
136     *next_pending_handler++ = deRefStablePtr((StgStablePtr)handlers[sig]);
137
138     // stack full?
139     if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
140         barf("too many pending signals");
141     }
142     
143     // re-establish the signal handler, and carry on
144     sigemptyset(&signals);
145     sigaddset(&signals, sig);
146     sigprocmask(SIG_UNBLOCK, &signals, NULL);
147
148     // *always* do the SIGCONT handler, even if the user overrides it.
149     if (sig == SIGCONT) {
150         cont_handler(sig);
151     }
152
153     context_switch = 1;
154 }
155
156 /* -----------------------------------------------------------------------------
157  * Blocking/Unblocking of the user signals
158  * -------------------------------------------------------------------------- */
159
160 static sigset_t userSignals;
161 static sigset_t savedSignals;
162
163 void
164 initUserSignals(void)
165 {
166     sigemptyset(&userSignals);
167 }
168
169 void
170 blockUserSignals(void)
171 {
172     sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
173 }
174
175 void
176 unblockUserSignals(void)
177 {
178     sigprocmask(SIG_SETMASK, &savedSignals, NULL);
179 }
180
181 rtsBool
182 anyUserHandlers(void)
183 {
184     return n_haskell_handlers != 0;
185 }
186
187 void
188 awaitUserSignals(void)
189 {
190     while (!signals_pending() && !interrupted) {
191         pause();
192     }
193 }
194
195 /* -----------------------------------------------------------------------------
196  * Install a Haskell signal handler.
197  * -------------------------------------------------------------------------- */
198
199 int
200 stg_sig_install(int sig, int spi, StgStablePtr *handler, void *mask)
201 {
202     sigset_t signals, osignals;
203     struct sigaction action;
204     StgInt previous_spi;
205
206     // Block the signal until we figure out what to do
207     // Count on this to fail if the signal number is invalid
208     if (sig < 0 || sigemptyset(&signals) ||
209         sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
210         return STG_SIG_ERR;
211     }
212     
213     more_handlers(sig);
214
215     previous_spi = handlers[sig];
216
217     switch(spi) {
218     case STG_SIG_IGN:
219         handlers[sig] = STG_SIG_IGN;
220         sigdelset(&userSignals, sig);
221         action.sa_handler = SIG_IGN;
222         break;
223         
224     case STG_SIG_DFL:
225         handlers[sig] = STG_SIG_DFL;
226         sigdelset(&userSignals, sig);
227         action.sa_handler = SIG_DFL;
228         break;
229
230     case STG_SIG_HAN:
231     case STG_SIG_RST:
232         handlers[sig] = (StgInt)*handler;
233         sigaddset(&userSignals, sig);
234         action.sa_handler = generic_handler;
235         if (spi == STG_SIG_RST) {
236             action.sa_flags = SA_RESETHAND;
237         }
238         n_haskell_handlers++;
239         break;
240
241     default:
242         barf("stg_sig_install: bad spi");
243     }
244
245     if (mask != NULL)
246         action.sa_mask = *(sigset_t *)mask;
247     else
248         sigemptyset(&action.sa_mask);
249
250     action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
251
252     if (sigaction(sig, &action, NULL) || 
253         sigprocmask(SIG_SETMASK, &osignals, NULL)) 
254     {
255         // need to return an error code, so avoid a stable pointer leak
256         // by freeing the previous handler if there was one.
257         if (previous_spi >= 0) {
258             freeStablePtr(stgCast(StgStablePtr,handlers[sig]));
259             n_haskell_handlers--;
260         }
261         return STG_SIG_ERR;
262     }
263     
264     if (previous_spi == STG_SIG_DFL || previous_spi == STG_SIG_IGN
265         || previous_spi == STG_SIG_ERR) {
266         return previous_spi;
267     } else {
268         *handler = (StgStablePtr)previous_spi;
269         return STG_SIG_HAN;
270     }
271 }
272
273 /* -----------------------------------------------------------------------------
274  * Creating new threads for the pending signal handlers.
275  * -------------------------------------------------------------------------- */
276 void
277 startSignalHandlers(void)
278 {
279   blockUserSignals();
280   
281   while (next_pending_handler != pending_handler_buf) {
282
283     next_pending_handler--;
284
285     scheduleThread(
286        createIOThread(RtsFlags.GcFlags.initialStkSize, 
287                       (StgClosure *) *next_pending_handler));
288   }
289
290   unblockUserSignals();
291 }
292
293 /* ----------------------------------------------------------------------------
294  * Mark signal handlers during GC.
295  *
296  * We do this rather than trying to start all the signal handlers
297  * prior to GC, because that requires extra heap for the new threads.
298  * Signals must be blocked (see blockUserSignals() above) during GC to
299  * avoid race conditions.
300  * -------------------------------------------------------------------------- */
301
302 void
303 markSignalHandlers (evac_fn evac)
304 {
305     StgPtr *p;
306
307     p = next_pending_handler;
308     while (p != pending_handler_buf) {
309         p--;
310         evac((StgClosure **)p);
311     }
312 }
313
314 #else // PAR
315 StgInt 
316 stg_sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
317 {
318     // don't fflush(stdout); WORKAROUND bug in Linux glibc
319     barf("no signal handling support in a parallel implementation");
320 }
321
322 void
323 startSignalHandlers(void)
324 {
325 }
326 #endif
327
328 /* -----------------------------------------------------------------------------
329  * SIGINT handler.
330  *
331  * We like to shutdown nicely after receiving a SIGINT, write out the
332  * stats, write profiling info, close open files and flush buffers etc.
333  * -------------------------------------------------------------------------- */
334 #ifdef SMP
335 pthread_t startup_guy;
336 #endif
337
338 static void
339 shutdown_handler(int sig STG_UNUSED)
340 {
341 #ifdef SMP
342     // if I'm a worker thread, send this signal to the guy who
343     // originally called startupHaskell().  Since we're handling
344     // the signal, it won't be a "send to all threads" type of signal
345     // (according to the POSIX threads spec).
346     if (pthread_self() != startup_guy) {
347         pthread_kill(startup_guy, sig);
348         return;
349     }
350 #endif
351
352     // If we're already trying to interrupt the RTS, terminate with
353     // extreme prejudice.  So the first ^C tries to exit the program
354     // cleanly, and the second one just kills it.
355     if (interrupted) {
356         exit(EXIT_INTERRUPTED);
357     } else {
358         interruptStgRts();
359     }
360 }
361
362 /* -----------------------------------------------------------------------------
363  * Install default signal handlers.
364  *
365  * The RTS installs a default signal handler for catching
366  * SIGINT, so that we can perform an orderly shutdown.
367  *
368  * Haskell code may install their own SIGINT handler, which is
369  * fine, provided they're so kind as to put back the old one
370  * when they de-install.
371  *
372  * In addition to handling SIGINT, the RTS also handles SIGFPE
373  * by ignoring it.  Apparently IEEE requires floating-point
374  * exceptions to be ignored by default, but alpha-dec-osf3
375  * doesn't seem to do so.
376  * -------------------------------------------------------------------------- */
377 void
378 initDefaultHandlers()
379 {
380     struct sigaction action,oact;
381
382 #ifdef SMP
383     startup_guy = pthread_self();
384 #endif
385
386     // install the SIGINT handler
387     action.sa_handler = shutdown_handler;
388     sigemptyset(&action.sa_mask);
389     action.sa_flags = 0;
390     if (sigaction(SIGINT, &action, &oact) != 0) {
391         prog_belch("warning: failed to install SIGINT handler");
392     }
393
394 #ifndef cygwin32_TARGET_OS
395     siginterrupt(SIGINT, 1);    // isn't this the default? --SDM
396 #endif
397
398     // install the SIGCONT handler
399     action.sa_handler = cont_handler;
400     sigemptyset(&action.sa_mask);
401     action.sa_flags = 0;
402     if (sigaction(SIGCONT, &action, &oact) != 0) {
403         prog_belch("warning: failed to install SIGCONT handler");
404     }
405
406     // install the SIGFPE handler
407
408     // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
409     // Apparently IEEE requires floating-point exceptions to be ignored by
410     // default, but alpha-dec-osf3 doesn't seem to do so.
411
412     // Commented out by SDM 2/7/2002: this causes an infinite loop on
413     // some architectures when an integer division by zero occurs: we
414     // don't recover from the floating point exception, and the
415     // program just generates another one immediately.
416 #if 0
417     action.sa_handler = SIG_IGN;
418     sigemptyset(&action.sa_mask);
419     action.sa_flags = 0;
420     if (sigaction(SIGFPE, &action, &oact) != 0) {
421         prog_belch("warning: failed to install SIGFPE handler");
422     }
423 #endif
424
425 #ifdef alpha_TARGET_ARCH
426     ieee_set_fp_control(0);
427 #endif
428 }
429
430 #endif /*! mingw32_TARGET_OS */