aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2006-09-26 02:33:04 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-26 11:49:07 -0400
commit4b84c69b5f6c08a540e3683f1360a6cdef2806c7 (patch)
tree708f1e4cbc2771886aaeb8eadb3ae4d458bc8133
parent19bdf0409f25a85a45874a5a8da6f3e4edcf4a49 (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.h27
-rw-r--r--arch/um/include/sysdep-x86_64/signal.h29
-rw-r--r--arch/um/os-Linux/irq.c2
-rw-r--r--arch/um/os-Linux/main.c34
-rw-r--r--arch/um/os-Linux/process.c12
-rw-r--r--arch/um/os-Linux/signal.c31
-rw-r--r--arch/um/os-Linux/skas/process.c17
-rw-r--r--arch/um/os-Linux/sys-i386/Makefile2
-rw-r--r--arch/um/os-Linux/sys-i386/signal.c15
-rw-r--r--arch/um/os-Linux/sys-x86_64/Makefile2
-rw-r--r--arch/um/os-Linux/sys-x86_64/signal.c16
-rw-r--r--arch/um/os-Linux/time.c4
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
133void os_set_ioignore(void) 133void os_set_ioignore(void)
134{ 134{
135 set_handler(SIGIO, SIG_IGN, 0, -1); 135 signal(SIGIO, SIG_IGN);
136} 136}
137 137
138void init_irq_signals(int on_sigstack) 138void 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
68static void last_ditch_exit(int sig) 68static 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
74static 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
79static void setup_env_path(void) 98static 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
252void init_new_thread_signals(void) 262void 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 @@
38static int signals_enabled = 1; 37static int signals_enabled = 1;
39static int pending = 0; 38static int pending = 0;
40 39
41void sig_handler(ARCH_SIGHDLR_PARAM) 40void 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
87void alarm_handler(ARCH_SIGHDLR_PARAM) 78void 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
117void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
118
119extern void hard_handler(int sig);
120
129void set_handler(int sig, void (*handler)(int), int flags, ...) 121void 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
6obj-$(CONFIG_MODE_SKAS) = registers.o tls.o 6obj-$(CONFIG_MODE_SKAS) = registers.o signal.o tls.o
7 7
8USER_OBJS := $(obj-y) 8USER_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
8extern void (*handlers[])(int sig, struct sigcontext *sc);
9
10void 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
6obj-$(CONFIG_MODE_SKAS) = registers.o 6obj-$(CONFIG_MODE_SKAS) = registers.o signal.o
7 7
8USER_OBJS := $(obj-y) 8USER_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
8extern void (*handlers[])(int sig, struct sigcontext *sc);
9
10void 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
47void switch_timers(int to_real) 47void switch_timers(int to_real)