Skip to content

Commit

Permalink
[PATCH] uml: Move signal handlers to arch code
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
cfd-36 authored and Linus Torvalds committed Sep 26, 2006
1 parent 19bdf04 commit 4b84c69
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 89 deletions.
27 changes: 0 additions & 27 deletions arch/um/include/sysdep-i386/signal.h

This file was deleted.

29 changes: 0 additions & 29 deletions arch/um/include/sysdep-x86_64/signal.h

This file was deleted.

2 changes: 1 addition & 1 deletion arch/um/os-Linux/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ void os_set_pollfd(int i, int fd)

void os_set_ioignore(void)
{
set_handler(SIGIO, SIG_IGN, 0, -1);
signal(SIGIO, SIG_IGN);
}

void init_irq_signals(int on_sigstack)
Expand Down
34 changes: 28 additions & 6 deletions arch/um/os-Linux/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,32 @@ static __init void do_uml_initcalls(void)

static void last_ditch_exit(int sig)
{
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGHUP, SIG_DFL);
uml_cleanup();
exit(1);
}

static void install_fatal_handler(int sig)
{
struct sigaction action;

/* All signals are enabled in this handler ... */
sigemptyset(&action.sa_mask);

/* ... including the signal being handled, plus we want the
* handler reset to the default behavior, so that if an exit
* handler is hanging for some reason, the UML will just die
* after this signal is sent a second time.
*/
action.sa_flags = SA_RESETHAND | SA_NODEFER;
action.sa_restorer = NULL;
action.sa_handler = last_ditch_exit;
if(sigaction(sig, &action, NULL) < 0){
printf("failed to install handler for signal %d - errno = %d\n",
errno);
exit(1);
}
}

#define UML_LIB_PATH ":/usr/lib/uml"

static void setup_env_path(void)
Expand Down Expand Up @@ -158,9 +177,12 @@ int main(int argc, char **argv, char **envp)
}
new_argv[argc] = NULL;

set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
/* Allow these signals to bring down a UML if all other
* methods of control fail.
*/
install_fatal_handler(SIGINT);
install_fatal_handler(SIGTERM);
install_fatal_handler(SIGHUP);

scan_elf_aux( envp);

Expand Down
12 changes: 11 additions & 1 deletion arch/um/os-Linux/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,17 @@ void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
set_sigstack(sig_stack, pages * page_size());
flags = SA_ONSTACK;
}
if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
if(usr1_handler){
struct sigaction sa;

sa.sa_handler = usr1_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = flags;
sa.sa_restorer = NULL;
if(sigaction(SIGUSR1, &sa, NULL) < 0)
panic("init_new_thread_stack - sigaction failed - "
"errno = %d\n", errno);
}
}

void init_new_thread_signals(void)
Expand Down
31 changes: 13 additions & 18 deletions arch/um/os-Linux/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include "user.h"
#include "signal_kern.h"
#include "sysdep/sigcontext.h"
#include "sysdep/signal.h"
#include "sigcontext.h"
#include "mode.h"
#include "os.h"
Expand All @@ -38,18 +37,10 @@
static int signals_enabled = 1;
static int pending = 0;

void sig_handler(ARCH_SIGHDLR_PARAM)
void sig_handler(int sig, struct sigcontext *sc)
{
struct sigcontext *sc;
int enabled;

/* Must be the first thing that this handler does - x86_64 stores
* the sigcontext in %rdx, and we need to save it before it has a
* chance to get trashed.
*/

ARCH_GET_SIGCONTEXT(sc, sig);

enabled = signals_enabled;
if(!enabled && (sig == SIGIO)){
pending |= SIGIO_MASK;
Expand Down Expand Up @@ -84,13 +75,10 @@ static void real_alarm_handler(int sig, struct sigcontext *sc)

}

void alarm_handler(ARCH_SIGHDLR_PARAM)
void alarm_handler(int sig, struct sigcontext *sc)
{
struct sigcontext *sc;
int enabled;

ARCH_GET_SIGCONTEXT(sc, sig);

enabled = signals_enabled;
if(!signals_enabled){
if(sig == SIGVTALRM)
Expand Down Expand Up @@ -126,20 +114,27 @@ void remove_sigstack(void)
panic("disabling signal stack failed, errno = %d\n", errno);
}

void (*handlers[_NSIG])(int sig, struct sigcontext *sc);

extern void hard_handler(int sig);

void set_handler(int sig, void (*handler)(int), int flags, ...)
{
struct sigaction action;
va_list ap;
sigset_t sig_mask;
int mask;

va_start(ap, flags);
action.sa_handler = handler;
handlers[sig] = (void (*)(int, struct sigcontext *)) handler;
action.sa_handler = hard_handler;

sigemptyset(&action.sa_mask);
while((mask = va_arg(ap, int)) != -1){

va_start(ap, flags);
while((mask = va_arg(ap, int)) != -1)
sigaddset(&action.sa_mask, mask);
}
va_end(ap);

action.sa_flags = flags;
action.sa_restorer = NULL;
if(sigaction(sig, &action, NULL) < 0)
Expand Down
17 changes: 14 additions & 3 deletions arch/um/os-Linux/skas/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,25 @@ static int userspace_tramp(void *stack)
}
}
if(!ptrace_faultinfo && (stack != NULL)){
struct sigaction sa;

unsigned long v = UML_CONFIG_STUB_CODE +
(unsigned long) stub_segv_handler -
(unsigned long) &__syscall_stub_start;

set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
SIGUSR1, -1);
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGIO);
sigaddset(&sa.sa_mask, SIGWINCH);
sigaddset(&sa.sa_mask, SIGALRM);
sigaddset(&sa.sa_mask, SIGVTALRM);
sigaddset(&sa.sa_mask, SIGUSR1);
sa.sa_flags = SA_ONSTACK;
sa.sa_handler = (void *) v;
sa.sa_restorer = NULL;
if(sigaction(SIGSEGV, &sa, NULL) < 0)
panic("userspace_tramp - setting SIGSEGV handler "
"failed - errno = %d\n", errno);
}

os_stop_process(os_getpid());
Expand Down
2 changes: 1 addition & 1 deletion arch/um/os-Linux/sys-i386/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Licensed under the GPL
#

obj-$(CONFIG_MODE_SKAS) = registers.o tls.o
obj-$(CONFIG_MODE_SKAS) = registers.o signal.o tls.o

USER_OBJS := $(obj-y)

Expand Down
15 changes: 15 additions & 0 deletions arch/um/os-Linux/sys-i386/signal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (C) 2006 Jeff Dike ([email protected])
* Licensed under the GPL
*/

#include <signal.h>

extern void (*handlers[])(int sig, struct sigcontext *sc);

void hard_handler(int sig)
{
struct sigcontext *sc = (struct sigcontext *) (&sig + 1);

(*handlers[sig])(sig, sc);
}
2 changes: 1 addition & 1 deletion arch/um/os-Linux/sys-x86_64/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Licensed under the GPL
#

obj-$(CONFIG_MODE_SKAS) = registers.o
obj-$(CONFIG_MODE_SKAS) = registers.o signal.o

USER_OBJS := $(obj-y)

Expand Down
16 changes: 16 additions & 0 deletions arch/um/os-Linux/sys-x86_64/signal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright (C) 2006 Jeff Dike ([email protected])
* Licensed under the GPL
*/

#include <signal.h>

extern void (*handlers[])(int sig, struct sigcontext *sc);

void hard_handler(int sig)
{
struct ucontext *uc;
asm("movq %%rdx, %0" : "=r" (uc));

(*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext);
}
4 changes: 2 additions & 2 deletions arch/um/os-Linux/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ void disable_timer(void)
printk("disnable_timer - setitimer failed, errno = %d\n",
errno);
/* If there are signals already queued, after unblocking ignore them */
set_handler(SIGALRM, SIG_IGN, 0, -1);
set_handler(SIGVTALRM, SIG_IGN, 0, -1);
signal(SIGALRM, SIG_IGN);
signal(SIGVTALRM, SIG_IGN);
}

void switch_timers(int to_real)
Expand Down

0 comments on commit 4b84c69

Please sign in to comment.