diff options
author | Jeff Dike <jdike@addtoit.com> | 2006-09-26 02:33:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-26 11:49:07 -0400 |
commit | 4b84c69b5f6c08a540e3683f1360a6cdef2806c7 (patch) | |
tree | 708f1e4cbc2771886aaeb8eadb3ae4d458bc8133 | |
parent | 19bdf0409f25a85a45874a5a8da6f3e4edcf4a49 (diff) |
[PATCH] uml: Move signal handlers to arch code
Have most signals go through an arch-provided handler which recovers the
sigcontext and then calls a generic handler. This replaces the
ARCH_GET_SIGCONTEXT macro, which was somewhat fragile. On x86_64, recovering
%rdx (which holds the sigcontext pointer) must be the first thing that
happens. sig_handler duly invokes that first, but there is no guarantee that
I can see that instructions won't be reordered such that %rdx is used before
that. Having the arch provide the handler seems much more robust.
Some signals in some parts of UML require their own handlers - these places
don't call set_handler any more. They call sigaction or signal themselves.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | arch/um/include/sysdep-i386/signal.h | 27 | ||||
-rw-r--r-- | arch/um/include/sysdep-x86_64/signal.h | 29 | ||||
-rw-r--r-- | arch/um/os-Linux/irq.c | 2 | ||||
-rw-r--r-- | arch/um/os-Linux/main.c | 34 | ||||
-rw-r--r-- | arch/um/os-Linux/process.c | 12 | ||||
-rw-r--r-- | arch/um/os-Linux/signal.c | 31 | ||||
-rw-r--r-- | arch/um/os-Linux/skas/process.c | 17 | ||||
-rw-r--r-- | arch/um/os-Linux/sys-i386/Makefile | 2 | ||||
-rw-r--r-- | arch/um/os-Linux/sys-i386/signal.c | 15 | ||||
-rw-r--r-- | arch/um/os-Linux/sys-x86_64/Makefile | 2 | ||||
-rw-r--r-- | arch/um/os-Linux/sys-x86_64/signal.c | 16 | ||||
-rw-r--r-- | arch/um/os-Linux/time.c | 4 |
12 files changed, 102 insertions, 89 deletions
diff --git a/arch/um/include/sysdep-i386/signal.h b/arch/um/include/sysdep-i386/signal.h deleted file mode 100644 index 07518b162136..000000000000 --- a/arch/um/include/sysdep-i386/signal.h +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 PathScale, Inc | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __I386_SIGNAL_H_ | ||
7 | #define __I386_SIGNAL_H_ | ||
8 | |||
9 | #include <signal.h> | ||
10 | |||
11 | #define ARCH_SIGHDLR_PARAM int sig | ||
12 | |||
13 | #define ARCH_GET_SIGCONTEXT(sc, sig) \ | ||
14 | do sc = (struct sigcontext *) (&sig + 1); while(0) | ||
15 | |||
16 | #endif | ||
17 | |||
18 | /* | ||
19 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
20 | * Emacs will notice this stuff at the end of the file and automatically | ||
21 | * adjust the settings for this buffer only. This must remain at the end | ||
22 | * of the file. | ||
23 | * --------------------------------------------------------------------------- | ||
24 | * Local variables: | ||
25 | * c-file-style: "linux" | ||
26 | * End: | ||
27 | */ | ||
diff --git a/arch/um/include/sysdep-x86_64/signal.h b/arch/um/include/sysdep-x86_64/signal.h deleted file mode 100644 index 6142897af3d1..000000000000 --- a/arch/um/include/sysdep-x86_64/signal.h +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004 PathScale, Inc | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __X86_64_SIGNAL_H_ | ||
7 | #define __X86_64_SIGNAL_H_ | ||
8 | |||
9 | #define ARCH_SIGHDLR_PARAM int sig | ||
10 | |||
11 | #define ARCH_GET_SIGCONTEXT(sc, sig_addr) \ | ||
12 | do { \ | ||
13 | struct ucontext *__uc; \ | ||
14 | asm("movq %%rdx, %0" : "=r" (__uc)); \ | ||
15 | sc = (struct sigcontext *) &__uc->uc_mcontext; \ | ||
16 | } while(0) | ||
17 | |||
18 | #endif | ||
19 | |||
20 | /* | ||
21 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
22 | * Emacs will notice this stuff at the end of the file and automatically | ||
23 | * adjust the settings for this buffer only. This must remain at the end | ||
24 | * of the file. | ||
25 | * --------------------------------------------------------------------------- | ||
26 | * Local variables: | ||
27 | * c-file-style: "linux" | ||
28 | * End: | ||
29 | */ | ||
diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c index 7555bf9c33d9..a97206df5b52 100644 --- a/arch/um/os-Linux/irq.c +++ b/arch/um/os-Linux/irq.c | |||
@@ -132,7 +132,7 @@ void os_set_pollfd(int i, int fd) | |||
132 | 132 | ||
133 | void os_set_ioignore(void) | 133 | void os_set_ioignore(void) |
134 | { | 134 | { |
135 | set_handler(SIGIO, SIG_IGN, 0, -1); | 135 | signal(SIGIO, SIG_IGN); |
136 | } | 136 | } |
137 | 137 | ||
138 | void init_irq_signals(int on_sigstack) | 138 | void init_irq_signals(int on_sigstack) |
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index 90912aaca7aa..d1c5670787dc 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c | |||
@@ -67,13 +67,32 @@ static __init void do_uml_initcalls(void) | |||
67 | 67 | ||
68 | static void last_ditch_exit(int sig) | 68 | static void last_ditch_exit(int sig) |
69 | { | 69 | { |
70 | signal(SIGINT, SIG_DFL); | ||
71 | signal(SIGTERM, SIG_DFL); | ||
72 | signal(SIGHUP, SIG_DFL); | ||
73 | uml_cleanup(); | 70 | uml_cleanup(); |
74 | exit(1); | 71 | exit(1); |
75 | } | 72 | } |
76 | 73 | ||
74 | static void install_fatal_handler(int sig) | ||
75 | { | ||
76 | struct sigaction action; | ||
77 | |||
78 | /* All signals are enabled in this handler ... */ | ||
79 | sigemptyset(&action.sa_mask); | ||
80 | |||
81 | /* ... including the signal being handled, plus we want the | ||
82 | * handler reset to the default behavior, so that if an exit | ||
83 | * handler is hanging for some reason, the UML will just die | ||
84 | * after this signal is sent a second time. | ||
85 | */ | ||
86 | action.sa_flags = SA_RESETHAND | SA_NODEFER; | ||
87 | action.sa_restorer = NULL; | ||
88 | action.sa_handler = last_ditch_exit; | ||
89 | if(sigaction(sig, &action, NULL) < 0){ | ||
90 | printf("failed to install handler for signal %d - errno = %d\n", | ||
91 | errno); | ||
92 | exit(1); | ||
93 | } | ||
94 | } | ||
95 | |||
77 | #define UML_LIB_PATH ":/usr/lib/uml" | 96 | #define UML_LIB_PATH ":/usr/lib/uml" |
78 | 97 | ||
79 | static void setup_env_path(void) | 98 | static void setup_env_path(void) |
@@ -158,9 +177,12 @@ int main(int argc, char **argv, char **envp) | |||
158 | } | 177 | } |
159 | new_argv[argc] = NULL; | 178 | new_argv[argc] = NULL; |
160 | 179 | ||
161 | set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); | 180 | /* Allow these signals to bring down a UML if all other |
162 | set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); | 181 | * methods of control fail. |
163 | set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); | 182 | */ |
183 | install_fatal_handler(SIGINT); | ||
184 | install_fatal_handler(SIGTERM); | ||
185 | install_fatal_handler(SIGHUP); | ||
164 | 186 | ||
165 | scan_elf_aux( envp); | 187 | scan_elf_aux( envp); |
166 | 188 | ||
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 3afde92ad2c0..ff203625a4bd 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c | |||
@@ -246,7 +246,17 @@ void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) | |||
246 | set_sigstack(sig_stack, pages * page_size()); | 246 | set_sigstack(sig_stack, pages * page_size()); |
247 | flags = SA_ONSTACK; | 247 | flags = SA_ONSTACK; |
248 | } | 248 | } |
249 | if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); | 249 | if(usr1_handler){ |
250 | struct sigaction sa; | ||
251 | |||
252 | sa.sa_handler = usr1_handler; | ||
253 | sigemptyset(&sa.sa_mask); | ||
254 | sa.sa_flags = flags; | ||
255 | sa.sa_restorer = NULL; | ||
256 | if(sigaction(SIGUSR1, &sa, NULL) < 0) | ||
257 | panic("init_new_thread_stack - sigaction failed - " | ||
258 | "errno = %d\n", errno); | ||
259 | } | ||
250 | } | 260 | } |
251 | 261 | ||
252 | void init_new_thread_signals(void) | 262 | void init_new_thread_signals(void) |
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 60e4faedf254..55b62e2b8f41 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include "user.h" | 15 | #include "user.h" |
16 | #include "signal_kern.h" | 16 | #include "signal_kern.h" |
17 | #include "sysdep/sigcontext.h" | 17 | #include "sysdep/sigcontext.h" |
18 | #include "sysdep/signal.h" | ||
19 | #include "sigcontext.h" | 18 | #include "sigcontext.h" |
20 | #include "mode.h" | 19 | #include "mode.h" |
21 | #include "os.h" | 20 | #include "os.h" |
@@ -38,18 +37,10 @@ | |||
38 | static int signals_enabled = 1; | 37 | static int signals_enabled = 1; |
39 | static int pending = 0; | 38 | static int pending = 0; |
40 | 39 | ||
41 | void sig_handler(ARCH_SIGHDLR_PARAM) | 40 | void sig_handler(int sig, struct sigcontext *sc) |
42 | { | 41 | { |
43 | struct sigcontext *sc; | ||
44 | int enabled; | 42 | int enabled; |
45 | 43 | ||
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 | */ | ||
50 | |||
51 | ARCH_GET_SIGCONTEXT(sc, sig); | ||
52 | |||
53 | enabled = signals_enabled; | 44 | enabled = signals_enabled; |
54 | if(!enabled && (sig == SIGIO)){ | 45 | if(!enabled && (sig == SIGIO)){ |
55 | pending |= SIGIO_MASK; | 46 | pending |= SIGIO_MASK; |
@@ -84,13 +75,10 @@ static void real_alarm_handler(int sig, struct sigcontext *sc) | |||
84 | 75 | ||
85 | } | 76 | } |
86 | 77 | ||
87 | void alarm_handler(ARCH_SIGHDLR_PARAM) | 78 | void alarm_handler(int sig, struct sigcontext *sc) |
88 | { | 79 | { |
89 | struct sigcontext *sc; | ||
90 | int enabled; | 80 | int enabled; |
91 | 81 | ||
92 | ARCH_GET_SIGCONTEXT(sc, sig); | ||
93 | |||
94 | enabled = signals_enabled; | 82 | enabled = signals_enabled; |
95 | if(!signals_enabled){ | 83 | if(!signals_enabled){ |
96 | if(sig == SIGVTALRM) | 84 | if(sig == SIGVTALRM) |
@@ -126,6 +114,10 @@ void remove_sigstack(void) | |||
126 | panic("disabling signal stack failed, errno = %d\n", errno); | 114 | panic("disabling signal stack failed, errno = %d\n", errno); |
127 | } | 115 | } |
128 | 116 | ||
117 | void (*handlers[_NSIG])(int sig, struct sigcontext *sc); | ||
118 | |||
119 | extern void hard_handler(int sig); | ||
120 | |||
129 | void set_handler(int sig, void (*handler)(int), int flags, ...) | 121 | void set_handler(int sig, void (*handler)(int), int flags, ...) |
130 | { | 122 | { |
131 | struct sigaction action; | 123 | struct sigaction action; |
@@ -133,13 +125,16 @@ void set_handler(int sig, void (*handler)(int), int flags, ...) | |||
133 | sigset_t sig_mask; | 125 | sigset_t sig_mask; |
134 | int mask; | 126 | int mask; |
135 | 127 | ||
136 | va_start(ap, flags); | 128 | handlers[sig] = (void (*)(int, struct sigcontext *)) handler; |
137 | action.sa_handler = handler; | 129 | action.sa_handler = hard_handler; |
130 | |||
138 | sigemptyset(&action.sa_mask); | 131 | sigemptyset(&action.sa_mask); |
139 | while((mask = va_arg(ap, int)) != -1){ | 132 | |
133 | va_start(ap, flags); | ||
134 | while((mask = va_arg(ap, int)) != -1) | ||
140 | sigaddset(&action.sa_mask, mask); | 135 | sigaddset(&action.sa_mask, mask); |
141 | } | ||
142 | va_end(ap); | 136 | va_end(ap); |
137 | |||
143 | action.sa_flags = flags; | 138 | action.sa_flags = flags; |
144 | action.sa_restorer = NULL; | 139 | action.sa_restorer = NULL; |
145 | if(sigaction(sig, &action, NULL) < 0) | 140 | if(sigaction(sig, &action, NULL) < 0) |
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 50418a5e7134..88ff0de95cd3 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c | |||
@@ -189,14 +189,25 @@ static int userspace_tramp(void *stack) | |||
189 | } | 189 | } |
190 | } | 190 | } |
191 | if(!ptrace_faultinfo && (stack != NULL)){ | 191 | if(!ptrace_faultinfo && (stack != NULL)){ |
192 | struct sigaction sa; | ||
193 | |||
192 | unsigned long v = UML_CONFIG_STUB_CODE + | 194 | unsigned long v = UML_CONFIG_STUB_CODE + |
193 | (unsigned long) stub_segv_handler - | 195 | (unsigned long) stub_segv_handler - |
194 | (unsigned long) &__syscall_stub_start; | 196 | (unsigned long) &__syscall_stub_start; |
195 | 197 | ||
196 | set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size()); | 198 | set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size()); |
197 | set_handler(SIGSEGV, (void *) v, SA_ONSTACK, | 199 | sigemptyset(&sa.sa_mask); |
198 | SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, | 200 | sigaddset(&sa.sa_mask, SIGIO); |
199 | SIGUSR1, -1); | 201 | sigaddset(&sa.sa_mask, SIGWINCH); |
202 | sigaddset(&sa.sa_mask, SIGALRM); | ||
203 | sigaddset(&sa.sa_mask, SIGVTALRM); | ||
204 | sigaddset(&sa.sa_mask, SIGUSR1); | ||
205 | sa.sa_flags = SA_ONSTACK; | ||
206 | sa.sa_handler = (void *) v; | ||
207 | sa.sa_restorer = NULL; | ||
208 | if(sigaction(SIGSEGV, &sa, NULL) < 0) | ||
209 | panic("userspace_tramp - setting SIGSEGV handler " | ||
210 | "failed - errno = %d\n", errno); | ||
200 | } | 211 | } |
201 | 212 | ||
202 | os_stop_process(os_getpid()); | 213 | os_stop_process(os_getpid()); |
diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile index b3213613c41c..37806621b25d 100644 --- a/arch/um/os-Linux/sys-i386/Makefile +++ b/arch/um/os-Linux/sys-i386/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-$(CONFIG_MODE_SKAS) = registers.o tls.o | 6 | obj-$(CONFIG_MODE_SKAS) = registers.o signal.o tls.o |
7 | 7 | ||
8 | USER_OBJS := $(obj-y) | 8 | USER_OBJS := $(obj-y) |
9 | 9 | ||
diff --git a/arch/um/os-Linux/sys-i386/signal.c b/arch/um/os-Linux/sys-i386/signal.c new file mode 100644 index 000000000000..0d3eae518352 --- /dev/null +++ b/arch/um/os-Linux/sys-i386/signal.c | |||
@@ -0,0 +1,15 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <signal.h> | ||
7 | |||
8 | extern void (*handlers[])(int sig, struct sigcontext *sc); | ||
9 | |||
10 | void hard_handler(int sig) | ||
11 | { | ||
12 | struct sigcontext *sc = (struct sigcontext *) (&sig + 1); | ||
13 | |||
14 | (*handlers[sig])(sig, sc); | ||
15 | } | ||
diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile index 340ef26f5944..f67842a7735b 100644 --- a/arch/um/os-Linux/sys-x86_64/Makefile +++ b/arch/um/os-Linux/sys-x86_64/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-$(CONFIG_MODE_SKAS) = registers.o | 6 | obj-$(CONFIG_MODE_SKAS) = registers.o signal.o |
7 | 7 | ||
8 | USER_OBJS := $(obj-y) | 8 | USER_OBJS := $(obj-y) |
9 | 9 | ||
diff --git a/arch/um/os-Linux/sys-x86_64/signal.c b/arch/um/os-Linux/sys-x86_64/signal.c new file mode 100644 index 000000000000..3f369e5f976b --- /dev/null +++ b/arch/um/os-Linux/sys-x86_64/signal.c | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <signal.h> | ||
7 | |||
8 | extern void (*handlers[])(int sig, struct sigcontext *sc); | ||
9 | |||
10 | void hard_handler(int sig) | ||
11 | { | ||
12 | struct ucontext *uc; | ||
13 | asm("movq %%rdx, %0" : "=r" (uc)); | ||
14 | |||
15 | (*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext); | ||
16 | } | ||
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index 4ae73c0e5485..7f5ebbadca63 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c | |||
@@ -40,8 +40,8 @@ void disable_timer(void) | |||
40 | printk("disnable_timer - setitimer failed, errno = %d\n", | 40 | printk("disnable_timer - setitimer failed, errno = %d\n", |
41 | errno); | 41 | errno); |
42 | /* If there are signals already queued, after unblocking ignore them */ | 42 | /* If there are signals already queued, after unblocking ignore them */ |
43 | set_handler(SIGALRM, SIG_IGN, 0, -1); | 43 | signal(SIGALRM, SIG_IGN); |
44 | set_handler(SIGVTALRM, SIG_IGN, 0, -1); | 44 | signal(SIGVTALRM, SIG_IGN); |
45 | } | 45 | } |
46 | 46 | ||
47 | void switch_timers(int to_real) | 47 | void switch_timers(int to_real) |