[project @ 2002-09-17 12:11:44 by simonmar]
[ghc-hetmet.git] / ghc / rts / Signals.c
1 /* -----------------------------------------------------------------------------
2  * $Id: Signals.c,v 1.29 2002/09/17 12:11:45 simonmar 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         handlers[sig] = (StgInt)*handler;
232         sigaddset(&userSignals, sig);
233         action.sa_handler = generic_handler;
234         n_haskell_handlers++;
235         break;
236
237     default:
238         barf("stg_sig_install: bad spi");
239     }
240
241     if (mask != NULL)
242         action.sa_mask = *(sigset_t *)mask;
243     else
244         sigemptyset(&action.sa_mask);
245
246     action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
247
248     if (sigaction(sig, &action, NULL) || 
249         sigprocmask(SIG_SETMASK, &osignals, NULL)) 
250     {
251         // need to return an error code, so avoid a stable pointer leak
252         // by freeing the previous handler if there was one.
253         if (previous_spi >= 0) {
254             freeStablePtr(stgCast(StgStablePtr,handlers[sig]));
255             n_haskell_handlers--;
256         }
257         return STG_SIG_ERR;
258     }
259     
260     if (previous_spi == STG_SIG_DFL || previous_spi == STG_SIG_IGN
261         || previous_spi == STG_SIG_ERR) {
262         return previous_spi;
263     } else {
264         *handler = (StgStablePtr)previous_spi;
265         return STG_SIG_HAN;
266     }
267 }
268
269 /* -----------------------------------------------------------------------------
270  * Creating new threads for the pending signal handlers.
271  * -------------------------------------------------------------------------- */
272 void
273 startSignalHandlers(void)
274 {
275   blockUserSignals();
276   
277   while (next_pending_handler != pending_handler_buf) {
278
279     next_pending_handler--;
280
281     scheduleThread(
282        createIOThread(RtsFlags.GcFlags.initialStkSize, 
283                       (StgClosure *) *next_pending_handler));
284   }
285
286   unblockUserSignals();
287 }
288
289 /* ----------------------------------------------------------------------------
290  * Mark signal handlers during GC.
291  *
292  * We do this rather than trying to start all the signal handlers
293  * prior to GC, because that requires extra heap for the new threads.
294  * Signals must be blocked (see blockUserSignals() above) during GC to
295  * avoid race conditions.
296  * -------------------------------------------------------------------------- */
297
298 void
299 markSignalHandlers (evac_fn evac)
300 {
301     StgPtr *p;
302
303     p = next_pending_handler;
304     while (p != pending_handler_buf) {
305         p--;
306         evac((StgClosure **)p);
307     }
308 }
309
310 #else // PAR
311 StgInt 
312 stg_sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
313 {
314     // don't fflush(stdout); WORKAROUND bug in Linux glibc
315     barf("no signal handling support in a parallel implementation");
316 }
317
318 void
319 startSignalHandlers(void)
320 {
321 }
322 #endif
323
324 /* -----------------------------------------------------------------------------
325  * SIGINT handler.
326  *
327  * We like to shutdown nicely after receiving a SIGINT, write out the
328  * stats, write profiling info, close open files and flush buffers etc.
329  * -------------------------------------------------------------------------- */
330 #ifdef SMP
331 pthread_t startup_guy;
332 #endif
333
334 static void
335 shutdown_handler(int sig STG_UNUSED)
336 {
337 #ifdef SMP
338     // if I'm a worker thread, send this signal to the guy who
339     // originally called startupHaskell().  Since we're handling
340     // the signal, it won't be a "send to all threads" type of signal
341     // (according to the POSIX threads spec).
342     if (pthread_self() != startup_guy) {
343         pthread_kill(startup_guy, sig);
344         return;
345     }
346 #endif
347
348     // If we're already trying to interrupt the RTS, terminate with
349     // extreme prejudice.  So the first ^C tries to exit the program
350     // cleanly, and the second one just kills it.
351     if (interrupted) {
352         exit(EXIT_INTERRUPTED);
353     } else {
354         interruptStgRts();
355     }
356 }
357
358 /* -----------------------------------------------------------------------------
359  * Install default signal handlers.
360  *
361  * The RTS installs a default signal handler for catching
362  * SIGINT, so that we can perform an orderly shutdown.
363  *
364  * Haskell code may install their own SIGINT handler, which is
365  * fine, provided they're so kind as to put back the old one
366  * when they de-install.
367  *
368  * In addition to handling SIGINT, the RTS also handles SIGFPE
369  * by ignoring it.  Apparently IEEE requires floating-point
370  * exceptions to be ignored by default, but alpha-dec-osf3
371  * doesn't seem to do so.
372  * -------------------------------------------------------------------------- */
373 void
374 initDefaultHandlers()
375 {
376     struct sigaction action,oact;
377
378 #ifdef SMP
379     startup_guy = pthread_self();
380 #endif
381
382     // install the SIGINT handler
383     action.sa_handler = shutdown_handler;
384     sigemptyset(&action.sa_mask);
385     action.sa_flags = 0;
386     if (sigaction(SIGINT, &action, &oact) != 0) {
387         prog_belch("warning: failed to install SIGINT handler");
388     }
389
390 #ifndef cygwin32_TARGET_OS
391     siginterrupt(SIGINT, 1);    // isn't this the default? --SDM
392 #endif
393
394     // install the SIGCONT handler
395     action.sa_handler = cont_handler;
396     sigemptyset(&action.sa_mask);
397     action.sa_flags = 0;
398     if (sigaction(SIGCONT, &action, &oact) != 0) {
399         prog_belch("warning: failed to install SIGCONT handler");
400     }
401
402     // install the SIGFPE handler
403
404     // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
405     // Apparently IEEE requires floating-point exceptions to be ignored by
406     // default, but alpha-dec-osf3 doesn't seem to do so.
407
408     // Commented out by SDM 2/7/2002: this causes an infinite loop on
409     // some architectures when an integer division by zero occurs: we
410     // don't recover from the floating point exception, and the
411     // program just generates another one immediately.
412 #if 0
413     action.sa_handler = SIG_IGN;
414     sigemptyset(&action.sa_mask);
415     action.sa_flags = 0;
416     if (sigaction(SIGFPE, &action, &oact) != 0) {
417         prog_belch("warning: failed to install SIGFPE handler");
418     }
419 #endif
420
421 #ifdef alpha_TARGET_ARCH
422     ieee_set_fp_control(0);
423 #endif
424 }
425
426 #endif /*! mingw32_TARGET_OS */