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