uml: install panic notifier earlier
[deliverable/linux.git] / arch / um / os-Linux / signal.c
CommitLineData
1da177e4
LT
1/*
2 * Copyright (C) 2004 PathScale, Inc
ba180fd4 3 * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
1da177e4
LT
4 * Licensed under the GPL
5 */
6
0805d89c 7#include <stdlib.h>
0805d89c 8#include <stdarg.h>
ba180fd4
JD
9#include <errno.h>
10#include <signal.h>
11#include <strings.h>
edea1385 12#include "kern_util.h"
cff65c4f 13#include "os.h"
ba180fd4
JD
14#include "sysdep/barrier.h"
15#include "sysdep/sigcontext.h"
16#include "user.h"
1da177e4 17
ba180fd4 18/*
61b63c55 19 * These are the asynchronous signals. SIGPROF is excluded because we want to
1d7173ba
JD
20 * be able to profile all of UML, not just the non-critical sections. If
21 * profiling is not thread-safe, then that is not my problem. We can disable
22 * profiling when SMP is enabled in that case.
23 */
24#define SIGIO_BIT 0
25#define SIGIO_MASK (1 << SIGIO_BIT)
26
27#define SIGVTALRM_BIT 1
28#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)
29
ba180fd4
JD
30/*
31 * These are used by both the signal handlers and
53b17332
JD
32 * block/unblock_signals. I don't want modifications cached in a
33 * register - they must go straight to memory.
34 */
35static volatile int signals_enabled = 1;
36static volatile int pending = 0;
1d7173ba 37
4b84c69b 38void sig_handler(int sig, struct sigcontext *sc)
1da177e4 39{
1d7173ba
JD
40 int enabled;
41
1d7173ba 42 enabled = signals_enabled;
ba180fd4 43 if (!enabled && (sig == SIGIO)) {
1d7173ba
JD
44 pending |= SIGIO_MASK;
45 return;
46 }
47
48 block_signals();
49
6aa802ce 50 sig_handler_common_skas(sig, sc);
1d7173ba
JD
51
52 set_signals(enabled);
1da177e4
LT
53}
54
61b63c55 55static void real_alarm_handler(struct sigcontext *sc)
1da177e4 56{
77bf4400 57 struct uml_pt_regs regs;
2ea5bc5e 58
ba180fd4 59 if (sc != NULL)
2ea5bc5e 60 copy_sc(&regs, sc);
77bf4400 61 regs.is_user = 0;
2ea5bc5e 62 unblock_signals();
61b63c55 63 timer_handler(SIGVTALRM, &regs);
1d7173ba
JD
64}
65
4b84c69b 66void alarm_handler(int sig, struct sigcontext *sc)
1d7173ba 67{
1d7173ba
JD
68 int enabled;
69
1d7173ba 70 enabled = signals_enabled;
ba180fd4 71 if (!signals_enabled) {
61b63c55 72 pending |= SIGVTALRM_MASK;
1d7173ba
JD
73 return;
74 }
75
76 block_signals();
77
61b63c55 78 real_alarm_handler(sc);
1d7173ba 79 set_signals(enabled);
1da177e4
LT
80}
81
78a26e25
JD
82void timer_init(void)
83{
84 set_handler(SIGVTALRM, (__sighandler_t) alarm_handler,
61b63c55 85 SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, -1);
78a26e25
JD
86}
87
0805d89c
GS
88void set_sigstack(void *sig_stack, int size)
89{
90 stack_t stack = ((stack_t) { .ss_flags = 0,
91 .ss_sp = (__ptr_t) sig_stack,
92 .ss_size = size - sizeof(void *) });
93
ba180fd4 94 if (sigaltstack(&stack, NULL) != 0)
0805d89c
GS
95 panic("enabling signal stack failed, errno = %d\n", errno);
96}
97
98void remove_sigstack(void)
99{
100 stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE,
101 .ss_sp = NULL,
102 .ss_size = 0 });
103
ba180fd4 104 if (sigaltstack(&stack, NULL) != 0)
0805d89c
GS
105 panic("disabling signal stack failed, errno = %d\n", errno);
106}
107
4b84c69b
JD
108void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
109
c14b8494
JD
110void handle_signal(int sig, struct sigcontext *sc)
111{
508a9274 112 unsigned long pending = 1UL << sig;
c14b8494
JD
113
114 do {
115 int nested, bail;
116
117 /*
118 * pending comes back with one bit set for each
119 * interrupt that arrived while setting up the stack,
120 * plus a bit for this interrupt, plus the zero bit is
121 * set if this is a nested interrupt.
122 * If bail is true, then we interrupted another
123 * handler setting up the stack. In this case, we
124 * have to return, and the upper handler will deal
125 * with this interrupt.
126 */
508a9274 127 bail = to_irq_stack(&pending);
ba180fd4 128 if (bail)
c14b8494
JD
129 return;
130
131 nested = pending & 1;
132 pending &= ~1;
133
ba180fd4 134 while ((sig = ffs(pending)) != 0){
c14b8494
JD
135 sig--;
136 pending &= ~(1 << sig);
137 (*handlers[sig])(sig, sc);
138 }
139
ba180fd4
JD
140 /*
141 * Again, pending comes back with a mask of signals
c14b8494
JD
142 * that arrived while tearing down the stack. If this
143 * is non-zero, we just go back, set up the stack
144 * again, and handle the new interrupts.
145 */
ba180fd4 146 if (!nested)
c14b8494 147 pending = from_irq_stack(nested);
ba180fd4 148 } while (pending);
c14b8494
JD
149}
150
4b84c69b
JD
151extern void hard_handler(int sig);
152
0805d89c
GS
153void set_handler(int sig, void (*handler)(int), int flags, ...)
154{
155 struct sigaction action;
156 va_list ap;
1d7173ba 157 sigset_t sig_mask;
0805d89c
GS
158 int mask;
159
4b84c69b
JD
160 handlers[sig] = (void (*)(int, struct sigcontext *)) handler;
161 action.sa_handler = hard_handler;
162
0805d89c 163 sigemptyset(&action.sa_mask);
4b84c69b
JD
164
165 va_start(ap, flags);
ba180fd4 166 while ((mask = va_arg(ap, int)) != -1)
0805d89c 167 sigaddset(&action.sa_mask, mask);
0805d89c 168 va_end(ap);
4b84c69b 169
0805d89c
GS
170 action.sa_flags = flags;
171 action.sa_restorer = NULL;
ba180fd4 172 if (sigaction(sig, &action, NULL) < 0)
1d7173ba
JD
173 panic("sigaction failed - errno = %d\n", errno);
174
175 sigemptyset(&sig_mask);
176 sigaddset(&sig_mask, sig);
ba180fd4 177 if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0)
1d7173ba 178 panic("sigprocmask failed - errno = %d\n", errno);
0805d89c
GS
179}
180
181int change_sig(int signal, int on)
182{
183 sigset_t sigset, old;
184
185 sigemptyset(&sigset);
186 sigaddset(&sigset, signal);
c9a3072d
WC
187 if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old) < 0)
188 return -errno;
ba180fd4 189 return !sigismember(&old, signal);
0805d89c
GS
190}
191
0805d89c
GS
192void block_signals(void)
193{
1d7173ba 194 signals_enabled = 0;
ba180fd4
JD
195 /*
196 * This must return with signals disabled, so this barrier
53b17332
JD
197 * ensures that writes are flushed out before the return.
198 * This might matter if gcc figures out how to inline this and
199 * decides to shuffle this code into the caller.
200 */
201 mb();
0805d89c
GS
202}
203
204void unblock_signals(void)
205{
1d7173ba 206 int save_pending;
0805d89c 207
ba180fd4 208 if (signals_enabled == 1)
1d7173ba 209 return;
0805d89c 210
ba180fd4
JD
211 /*
212 * We loop because the IRQ handler returns with interrupts off. So,
1d7173ba
JD
213 * interrupts may have arrived and we need to re-enable them and
214 * recheck pending.
215 */
ba180fd4
JD
216 while(1) {
217 /*
218 * Save and reset save_pending after enabling signals. This
1d7173ba
JD
219 * way, pending won't be changed while we're reading it.
220 */
221 signals_enabled = 1;
222
ba180fd4
JD
223 /*
224 * Setting signals_enabled and reading pending must
53b17332
JD
225 * happen in this order.
226 */
227 mb();
228
1d7173ba 229 save_pending = pending;
ba180fd4
JD
230 if (save_pending == 0) {
231 /*
232 * This must return with signals enabled, so
53b17332
JD
233 * this barrier ensures that writes are
234 * flushed out before the return. This might
235 * matter if gcc figures out how to inline
236 * this (unlikely, given its size) and decides
237 * to shuffle this code into the caller.
238 */
239 mb();
1d7173ba 240 return;
53b17332 241 }
1d7173ba
JD
242
243 pending = 0;
244
ba180fd4
JD
245 /*
246 * We have pending interrupts, so disable signals, as the
1d7173ba
JD
247 * handlers expect them off when they are called. They will
248 * be enabled again above.
249 */
250
251 signals_enabled = 0;
252
ba180fd4
JD
253 /*
254 * Deal with SIGIO first because the alarm handler might
1d7173ba
JD
255 * schedule, leaving the pending SIGIO stranded until we come
256 * back here.
257 */
ba180fd4 258 if (save_pending & SIGIO_MASK)
6aa802ce 259 sig_handler_common_skas(SIGIO, NULL);
1d7173ba 260
ba180fd4 261 if (save_pending & SIGVTALRM_MASK)
61b63c55 262 real_alarm_handler(NULL);
1d7173ba 263 }
0805d89c
GS
264}
265
266int get_signals(void)
267{
1d7173ba 268 return signals_enabled;
0805d89c
GS
269}
270
271int set_signals(int enable)
272{
0805d89c 273 int ret;
ba180fd4 274 if (signals_enabled == enable)
1d7173ba 275 return enable;
0805d89c 276
1d7173ba 277 ret = signals_enabled;
ba180fd4 278 if (enable)
1d7173ba
JD
279 unblock_signals();
280 else block_signals();
0805d89c 281
1d7173ba 282 return ret;
0805d89c 283}
This page took 0.349915 seconds and 5 git commands to generate.