Import Debian changes 20180207-1
[hcoop/debian/mlton.git] / runtime / gc / handler.c
1 /* Copyright (C) 1999-2007 Henry Cejtin, Matthew Fluet, Suresh
2 * Jagannathan, and Stephen Weeks.
3 * Copyright (C) 1997-2000 NEC Research Institute.
4 *
5 * MLton is released under a BSD-style license.
6 * See the file MLton-LICENSE for details.
7 */
8
9 /* GC_startSignalHandler does not do an enter()/leave(), even though
10 * it is exported. The basis library uses it via _import, not _prim,
11 * and so does not treat it as a runtime call -- so the invariant in
12 * enter would fail miserably. It is OK because GC_startHandler must
13 * be called from within a critical section.
14 *
15 * Don't make it inline, because it is also called in basis/Thread.c,
16 * and when compiling with COMPILE_FAST, they may appear out of order.
17 */
18 void GC_startSignalHandler (GC_state s) {
19 /* Switch to the signal handler thread. */
20 if (DEBUG_SIGNALS) {
21 fprintf (stderr, "GC_startSignalHandler\n");
22 }
23 assert (s->atomicState == 1);
24 assert (s->signalsInfo.signalIsPending);
25 s->signalsInfo.signalIsPending = FALSE;
26 s->signalsInfo.amInSignalHandler = TRUE;
27 assert (s->savedThread == BOGUS_OBJPTR);
28 s->savedThread = s->currentThread;
29 /* Set s->atomicState to 2 when switching to the signal handler
30 * thread; leaving the runtime will decrement s->atomicState to 1,
31 * the signal handler will then run atomically and will finish by
32 * switching to the thread to continue with, which will decrement
33 * s->atomicState to 0.
34 */
35 s->atomicState = 2;
36 }
37
38 void GC_finishSignalHandler (GC_state s) {
39 if (DEBUG_SIGNALS)
40 fprintf (stderr, "GC_finishSignalHandler ()\n");
41 assert (s->atomicState == 1);
42 s->signalsInfo.amInSignalHandler = FALSE;
43 }
44
45 void switchToSignalHandlerThreadIfNonAtomicAndSignalPending (GC_state s) {
46 if (s->atomicState == 1
47 and s->signalsInfo.signalIsPending) {
48 GC_startSignalHandler (s);
49 switchToThread (s, s->signalHandlerThread);
50 }
51 }
52
53 /* GC_handler sets s->limit = 0 so that the next limit check will
54 * fail. Signals need to be blocked during the handler (i.e. it
55 * should run atomically) because sigaddset does both a read and a
56 * write of s->signalsInfo.signalsPending. The signals are blocked
57 * by Posix_Signal_handle (see Posix/Signal/Signal.c).
58 */
59 void GC_handler (GC_state s, int signum) {
60 if (DEBUG_SIGNALS)
61 fprintf (stderr, "GC_handler signum = %d\n", signum);
62 assert (sigismember (&s->signalsInfo.signalsHandled, signum));
63 if (s->atomicState == 0)
64 s->limit = 0;
65 s->signalsInfo.signalIsPending = TRUE;
66 sigaddset (&s->signalsInfo.signalsPending, signum);
67 if (DEBUG_SIGNALS)
68 fprintf (stderr, "GC_handler done\n");
69 }