Commit | Line | Data |
---|---|---|
7f918cf1 CE |
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 | } |