diff options
Diffstat (limited to 'arch/um/os-Linux/signal.c')
-rw-r--r-- | arch/um/os-Linux/signal.c | 203 |
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 | |||
38 | static int signals_enabled = 1; | ||
39 | static int pending = 0; | ||
40 | |||
23 | void sig_handler(ARCH_SIGHDLR_PARAM) | 41 | void 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 | ||
32 | extern int timer_irq_inited; | 67 | extern int timer_irq_inited; |
33 | 68 | ||
34 | void alarm_handler(ARCH_SIGHDLR_PARAM) | 69 | static 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 | |||
87 | void 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 | ||
51 | extern void do_boot_timer_handler(struct sigcontext * sc); | 109 | extern void do_boot_timer_handler(struct sigcontext * sc); |
@@ -53,10 +111,22 @@ extern void do_boot_timer_handler(struct sigcontext * sc); | |||
53 | void boot_timer_handler(ARCH_SIGHDLR_PARAM) | 111 | void 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 | ||
62 | void set_sigstack(void *sig_stack, int size) | 132 | void 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 | ||
101 | int change_sig(int signal, int on) | 177 | int 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 | |||
115 | static 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 | |||
127 | void block_signals(void) | 187 | void block_signals(void) |
128 | { | 188 | { |
129 | change_signals(SIG_BLOCK); | 189 | signals_enabled = 0; |
130 | } | 190 | } |
131 | 191 | ||
132 | void unblock_signals(void) | 192 | void 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 | |||
146 | static 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 | ||
156 | int get_signals(void) | 238 | int 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 | ||
165 | int set_signals(int enable) | 243 | int 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 | ||
198 | void os_usr1_signal(int on) | 257 | void os_usr1_signal(int on) |