aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/os-Linux/signal.c
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2006-01-18 20:42:49 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-18 22:20:20 -0500
commit1d7173baf286c8b720f97f119ec92be43076ebde (patch)
tree4d562c25063c73a690fe1777fa86c3f48dfbbf13 /arch/um/os-Linux/signal.c
parent09ee011eb322c2072ec184a88763c250a5485d8b (diff)
[PATCH] uml: implement soft interrupts
This patch implements soft interrupts. Interrupt enabling and disabling no longer map to sigprocmask. Rather, a flag is set indicating whether interrupts may be handled. If a signal comes in and interrupts are marked as OK, then it is handled normally. If interrupts are marked as off, then the signal handler simply returns after noting that a signal needs handling. When interrupts are enabled later on, this pending signals flag is checked, and the IRQ handlers are called at that point. The point of this is to reduce the cost of local_irq_save et al, since they are very much more common than the signals that they are enabling and disabling. Soft interrupts produce a speed-up of ~25% on a kernel build. Subtleties - UML uses sigsetjmp/siglongjmp to switch contexts. sigsetjmp has been wrapped in a save_flags-like macro which remembers the interrupt state at setjmp time, and restores it when it is longjmp-ed back to. The enable_signals function has to loop because the IRQ handler disables interrupts before returning. enable_signals has to return with signals enabled, and signals may come in between the disabling and the return to enable_signals. So, it loops for as long as there are pending signals, ensuring that signals are enabled when it finally returns, and that there are no pending signals that need to be dealt with. Signed-off-by: Jeff Dike <jdike@addtoit.com> Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/um/os-Linux/signal.c')
-rw-r--r--arch/um/os-Linux/signal.c203
1 files changed, 131 insertions, 72 deletions
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 56ca95931b41..f11b3124a0c8 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -20,23 +20,58 @@
20#include "mode.h" 20#include "mode.h"
21#include "os.h" 21#include "os.h"
22 22
23/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled
24 * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to
25 * be able to profile all of UML, not just the non-critical sections. If
26 * profiling is not thread-safe, then that is not my problem. We can disable
27 * profiling when SMP is enabled in that case.
28 */
29#define SIGIO_BIT 0
30#define SIGIO_MASK (1 << SIGIO_BIT)
31
32#define SIGVTALRM_BIT 1
33#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)
34
35#define SIGALRM_BIT 2
36#define SIGALRM_MASK (1 << SIGALRM_BIT)
37
38static int signals_enabled = 1;
39static int pending = 0;
40
23void sig_handler(ARCH_SIGHDLR_PARAM) 41void sig_handler(ARCH_SIGHDLR_PARAM)
24{ 42{
25 struct sigcontext *sc; 43 struct sigcontext *sc;
44 int enabled;
45
46 /* Must be the first thing that this handler does - x86_64 stores
47 * the sigcontext in %rdx, and we need to save it before it has a
48 * chance to get trashed.
49 */
26 50
27 ARCH_GET_SIGCONTEXT(sc, sig); 51 ARCH_GET_SIGCONTEXT(sc, sig);
52
53 enabled = signals_enabled;
54 if(!enabled && (sig == SIGIO)){
55 pending |= SIGIO_MASK;
56 return;
57 }
58
59 block_signals();
60
28 CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, 61 CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
29 sig, sc); 62 sig, sc);
63
64 set_signals(enabled);
30} 65}
31 66
32extern int timer_irq_inited; 67extern int timer_irq_inited;
33 68
34void alarm_handler(ARCH_SIGHDLR_PARAM) 69static void real_alarm_handler(int sig, struct sigcontext *sc)
35{ 70{
36 struct sigcontext *sc; 71 if(!timer_irq_inited){
37 72 signals_enabled = 1;
38 ARCH_GET_SIGCONTEXT(sc, sig); 73 return;
39 if(!timer_irq_inited) return; 74 }
40 75
41 if(sig == SIGALRM) 76 if(sig == SIGALRM)
42 switch_timers(0); 77 switch_timers(0);
@@ -46,6 +81,29 @@ void alarm_handler(ARCH_SIGHDLR_PARAM)
46 81
47 if(sig == SIGALRM) 82 if(sig == SIGALRM)
48 switch_timers(1); 83 switch_timers(1);
84
85}
86
87void alarm_handler(ARCH_SIGHDLR_PARAM)
88{
89 struct sigcontext *sc;
90 int enabled;
91
92 ARCH_GET_SIGCONTEXT(sc, sig);
93
94 enabled = signals_enabled;
95 if(!signals_enabled){
96 if(sig == SIGVTALRM)
97 pending |= SIGVTALRM_MASK;
98 else pending |= SIGALRM_MASK;
99
100 return;
101 }
102
103 block_signals();
104
105 real_alarm_handler(sig, sc);
106 set_signals(enabled);
49} 107}
50 108
51extern void do_boot_timer_handler(struct sigcontext * sc); 109extern void do_boot_timer_handler(struct sigcontext * sc);
@@ -53,10 +111,22 @@ extern void do_boot_timer_handler(struct sigcontext * sc);
53void boot_timer_handler(ARCH_SIGHDLR_PARAM) 111void boot_timer_handler(ARCH_SIGHDLR_PARAM)
54{ 112{
55 struct sigcontext *sc; 113 struct sigcontext *sc;
114 int enabled;
56 115
57 ARCH_GET_SIGCONTEXT(sc, sig); 116 ARCH_GET_SIGCONTEXT(sc, sig);
58 117
118 enabled = signals_enabled;
119 if(!enabled){
120 if(sig == SIGVTALRM)
121 pending |= SIGVTALRM_MASK;
122 else pending |= SIGALRM_MASK;
123 return;
124 }
125
126 block_signals();
127
59 do_boot_timer_handler(sc); 128 do_boot_timer_handler(sc);
129 set_signals(enabled);
60} 130}
61 131
62void set_sigstack(void *sig_stack, int size) 132void set_sigstack(void *sig_stack, int size)
@@ -83,6 +153,7 @@ void set_handler(int sig, void (*handler)(int), int flags, ...)
83{ 153{
84 struct sigaction action; 154 struct sigaction action;
85 va_list ap; 155 va_list ap;
156 sigset_t sig_mask;
86 int mask; 157 int mask;
87 158
88 va_start(ap, flags); 159 va_start(ap, flags);
@@ -95,7 +166,12 @@ void set_handler(int sig, void (*handler)(int), int flags, ...)
95 action.sa_flags = flags; 166 action.sa_flags = flags;
96 action.sa_restorer = NULL; 167 action.sa_restorer = NULL;
97 if(sigaction(sig, &action, NULL) < 0) 168 if(sigaction(sig, &action, NULL) < 0)
98 panic("sigaction failed"); 169 panic("sigaction failed - errno = %d\n", errno);
170
171 sigemptyset(&sig_mask);
172 sigaddset(&sig_mask, sig);
173 if(sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0)
174 panic("sigprocmask failed - errno = %d\n", errno);
99} 175}
100 176
101int change_sig(int signal, int on) 177int change_sig(int signal, int on)
@@ -108,91 +184,74 @@ int change_sig(int signal, int on)
108 return(!sigismember(&old, signal)); 184 return(!sigismember(&old, signal));
109} 185}
110 186
111/* Both here and in set/get_signal we don't touch SIGPROF, because we must not
112 * disable profiling; it's safe because the profiling code does not interact
113 * with the kernel code at all.*/
114
115static void change_signals(int type)
116{
117 sigset_t mask;
118
119 sigemptyset(&mask);
120 sigaddset(&mask, SIGVTALRM);
121 sigaddset(&mask, SIGALRM);
122 sigaddset(&mask, SIGIO);
123 if(sigprocmask(type, &mask, NULL) < 0)
124 panic("Failed to change signal mask - errno = %d", errno);
125}
126
127void block_signals(void) 187void block_signals(void)
128{ 188{
129 change_signals(SIG_BLOCK); 189 signals_enabled = 0;
130} 190}
131 191
132void unblock_signals(void) 192void unblock_signals(void)
133{ 193{
134 change_signals(SIG_UNBLOCK); 194 int save_pending;
135}
136 195
137/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled 196 if(signals_enabled == 1)
138 * together under SIGVTALRM_BIT. SIGPROF is excluded because we want to 197 return;
139 * be able to profile all of UML, not just the non-critical sections. If
140 * profiling is not thread-safe, then that is not my problem. We can disable
141 * profiling when SMP is enabled in that case.
142 */
143#define SIGIO_BIT 0
144#define SIGVTALRM_BIT 1
145
146static int enable_mask(sigset_t *mask)
147{
148 int sigs;
149 198
150 sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT; 199 /* We loop because the IRQ handler returns with interrupts off. So,
151 sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT; 200 * interrupts may have arrived and we need to re-enable them and
152 sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT; 201 * recheck pending.
153 return(sigs); 202 */
203 while(1){
204 /* Save and reset save_pending after enabling signals. This
205 * way, pending won't be changed while we're reading it.
206 */
207 signals_enabled = 1;
208
209 save_pending = pending;
210 if(save_pending == 0)
211 return;
212
213 pending = 0;
214
215 /* We have pending interrupts, so disable signals, as the
216 * handlers expect them off when they are called. They will
217 * be enabled again above.
218 */
219
220 signals_enabled = 0;
221
222 /* Deal with SIGIO first because the alarm handler might
223 * schedule, leaving the pending SIGIO stranded until we come
224 * back here.
225 */
226 if(save_pending & SIGIO_MASK)
227 CHOOSE_MODE_PROC(sig_handler_common_tt,
228 sig_handler_common_skas, SIGIO, NULL);
229
230 if(save_pending & SIGALRM_MASK)
231 real_alarm_handler(SIGALRM, NULL);
232
233 if(save_pending & SIGVTALRM_MASK)
234 real_alarm_handler(SIGVTALRM, NULL);
235 }
154} 236}
155 237
156int get_signals(void) 238int get_signals(void)
157{ 239{
158 sigset_t mask; 240 return signals_enabled;
159
160 if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
161 panic("Failed to get signal mask");
162 return(enable_mask(&mask));
163} 241}
164 242
165int set_signals(int enable) 243int set_signals(int enable)
166{ 244{
167 sigset_t mask;
168 int ret; 245 int ret;
246 if(signals_enabled == enable)
247 return enable;
169 248
170 sigemptyset(&mask); 249 ret = signals_enabled;
171 if(enable & (1 << SIGIO_BIT)) 250 if(enable)
172 sigaddset(&mask, SIGIO); 251 unblock_signals();
173 if(enable & (1 << SIGVTALRM_BIT)){ 252 else block_signals();
174 sigaddset(&mask, SIGVTALRM);
175 sigaddset(&mask, SIGALRM);
176 }
177
178 /* This is safe - sigprocmask is guaranteed to copy locally the
179 * value of new_set, do his work and then, at the end, write to
180 * old_set.
181 */
182 if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
183 panic("Failed to enable signals");
184 ret = enable_mask(&mask);
185 sigemptyset(&mask);
186 if((enable & (1 << SIGIO_BIT)) == 0)
187 sigaddset(&mask, SIGIO);
188 if((enable & (1 << SIGVTALRM_BIT)) == 0){
189 sigaddset(&mask, SIGVTALRM);
190 sigaddset(&mask, SIGALRM);
191 }
192 if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
193 panic("Failed to block signals");
194 253
195 return(ret); 254 return ret;
196} 255}
197 256
198void os_usr1_signal(int on) 257void os_usr1_signal(int on)