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