aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/os-Linux/signal.c
diff options
context:
space:
mode:
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)