33c0adf6c72d7d8bca154f25e546f9d5f4d5f479
[sbcl.git] / doc / internals / signals.texinfo
1 @node Signal handling
2 @comment  node-name,  next,  previous,  up
3 @chapter Signal handling
4
5 @menu
6 * Groups of signals::           
7 * The deferral mechanism::      
8 * Implementation warts::        
9 * Programming with signal handling in mind::  
10 @end menu
11
12 @node Groups of signals
13 @section Groups of signals
14
15 There are two distinct groups of signals.
16
17 @subsection Semi-synchronous signals
18
19 The first group, tentatively named ``semi-synchronous'', consists of
20 signals that are raised on illegal instruction, hitting a protected
21 page, or on a trap. Examples from this group are:
22 @code{SIGBUS}/@code{SIGSEGV}, @code{SIGTRAP}, @code{SIGILL} and
23 @code{SIGEMT}. The exact meaning and function of these signals varies
24 by platform and OS. Understandably, because these signals are raised
25 in a controllable manner they are never blocked or deferred.
26
27 @subsection Blockable signals
28
29 The other group is of blockable signals. Typically, signal handlers
30 block them to protect against being interrupted at all. For example
31 @code{SIGHUP}, @code{SIGINT}, @code{SIGQUIT} belong to this group.
32
33 With the exception of @code{SIG_STOP_FOR_GC} all blockable signals are
34 deferrable.
35
36 @node The deferral mechanism
37 @section The deferral mechanism
38
39 @subsection Pseudo atomic sections
40
41 Some operations, such as allocation, consist of several steps and
42 temporarily break for instance gc invariants. Interrupting said
43 operations is therefore dangerous to one's health. Blocking the
44 signals for each allocation is out of question as the overhead of the
45 two @code{sigsetmask} system calls would be enormous. Instead, pseudo
46 atomic sections are implemented with a simple flag.
47
48 When a deferrable signal is delivered to a thread within a pseudo
49 atomic section the pseudo-atomic-interrupted flag is set, the signal
50 and its context are stored, and all deferrable signals blocked. This
51 is to guarantee that there is at most one pending handler in
52 SBCL. While the signals are blocked, the responsibilty of keeping
53 track of other pending signals lies with the OS.
54
55 On leaving the pseudo atomic section, the pending handler is run and
56 the signals are unblocked.
57
58 @subsection @code{WITHOUT-INTERRUPTS}
59
60 Similar to pseudo atomic, @code{WITHOUT-INTERRUPTS} defers deferrable
61 signals in its thread until the end of its body, provided it is not
62 nested in another @code{WITHOUT-INTERRUPTS}.
63
64 Not so frequently used as pseudo atomic, @code{WITHOUT-INTERRUPTS}
65 benefits less from the deferral mechanism.
66
67 @subsection Stop the world
68
69 Something of a special case, a signal that is blockable but not
70 deferrable by @code{WITHOUT-INTERRUPTS} is @code{SIG_STOP_FOR_GC}. It
71 is deferred by pseudo atomic and @code{WITHOUT-GCING}.
72
73 @node Implementation warts
74 @section Implementation warts
75
76 @subsection Miscellaneous issues
77
78 Signal handlers should automatically restore errno and fp
79 state. Currently, this is not the case.
80
81 @subsection POSIX -- Letter and Spirit
82
83 POSIX restricts signal handlers to a use only a narrow subset of POSIX
84 functions, and declares anything else to have undefined semantics.
85
86 Apparently the real reason is that a signal handler is potentially
87 interrupting a POSIX call: so the signal safety requirement is really
88 a re-entrancy requirement. We can work around the letter of the
89 standard by arranging to handle the interrupt when the signal handler
90 returns (see: @code{arrange_return_to_lisp_function}.) This does,
91 however, in no way protect us from the real issue of re-entrancy: even
92 though we would no longer be in a signal handler, we might still be in
93 the middle of an interrupted POSIX call.
94
95 For some signals this appears to be a non-issue: @code{SIGSEGV} and
96 other semi-synchronous signals are raised by our code for our code,
97 and so we can be sure that we are not interrupting a POSIX call with
98 any of them.
99
100 For asynchronous signals like @code{SIGALARM} and @code{SIGINT} this
101 is a real issue.
102
103 The right thing to do in multithreaded builds would probably be to use
104 POSIX semaphores (which are signal safe) to inform a separate handler
105 thread about such asynchronous events. In single-threaded builds there
106 does not seem to be any other option aside from generally blocking
107 asynch signals and listening for them every once and a while at safe
108 points. Neither of these is implemented as of SBCL 1.0.4.
109
110 Currently all our handlers invoke unsafe functions without hesitation.
111
112 @node Programming with signal handling in mind
113 @section Programming with signal handling in mind
114
115 @subsection On reentrancy
116
117 Since they might be invoked in the middle of just about anything,
118 signal handlers must invoke only reentrant functions or async signal
119 safe functions to be more precise. Functions passed to
120 @code{INTERRUPT-THREAD} have the same restrictions and considerations
121 as signal handlers.
122
123 Destructive modification, and holding mutexes to protect desctructive
124 modifications from interfering with each other are often the cause of
125 non-reentrancy. Recursive locks are not likely to help, and while
126 @code{WITHOUT-INTERRUPTS} is, it is considered untrendy to litter the
127 code with it.
128
129 Some basic functionality, such as streams and the debugger are
130 intended to be reentrant, but not much effort has been spent on
131 verifying it.
132
133 @subsection More deadlocks
134
135 If functions A and B directly or indirectly lock mutexes M and N, they
136 should do so in the same order to avoid deadlocks.
137
138 A less trivial scenario is where there is only one lock involved but
139 it is acquired in a @code{WITHOUT-GCING} in thread A, and outside of
140 @code{WITHOUT-GCING} in thread B. If thread A has entered
141 @code{WITHOUT-GCING} but thread B has the lock when the gc hits, then
142 A cannot leave @code{WITHOUT-GCING} because it is waiting for the lock
143 the already suspended thread B has. From this scenario one can easily
144 derive the rule: in a @code{WITHOUT-GCING} form (or pseudo atomic for
145 that matter) never wait for another thread that's not in
146 @code{WITHOUT-GCING}.
147
148 @subsection Calling user code
149
150 For the reasons above, calling user code, i.e. functions passed in, or
151 in other words code that one cannot reason about, from non-reentrant
152 code (holding locks), @code{WITHOUT-INTERRUPTS}, @code{WITHOUT-GCING}
153 is dangerous and best avoided.
154
155 @section Debugging
156
157 It is not easy to debug signal problems. The best bet probably is to
158 enable @code{QSHOW} and @code{QSHOW_SIGNALS} in runtime.h and once
159 SBCL runs into problems attach gdb. A simple @code{thread apply all
160 ba} is already tremendously useful. Another possibility is to send a
161 SIGABORT to SBCL to provoke landing in LDB, if it's compiled with it
162 and it has not yet done so on its own.
163
164 Note, that fprintf used by QSHOW is not reentrant and at least on x86
165 linux it is known to cause deadlocks, so place SHOW and co carefully,
166 ideally to places where blockable signals are blocked. Use
167 @code{QSHOW_SAFE} if you like.