diff options
Diffstat (limited to 'arch/um/os-Linux/signal.c')
| -rw-r--r-- | arch/um/os-Linux/signal.c | 100 | 
1 files changed, 58 insertions, 42 deletions
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 6ae180703a6..7b605e4dfff 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -9,18 +9,13 @@  #include <errno.h>  #include <signal.h>  #include <strings.h> -#include "as-layout.h" -#include "kern_util.h" -#include "os.h" -#include "process.h" -#include "sysdep/barrier.h" -#include "sysdep/sigcontext.h" -#include "user.h" - -/* Copied from linux/compiler-gcc.h since we can't include it directly */ -#define barrier() __asm__ __volatile__("": : :"memory") - -void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { +#include <as-layout.h> +#include <kern_util.h> +#include <os.h> +#include <sysdep/mcontext.h> +#include "internal.h" + +void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {  	[SIGTRAP]	= relay_signal,  	[SIGFPE]	= relay_signal,  	[SIGILL]	= relay_signal, @@ -30,7 +25,7 @@ void (*sig_info[NSIG])(int, struct uml_pt_regs *) = {  	[SIGIO]		= sigio_handler,  	[SIGVTALRM]	= timer_handler }; -static void sig_handler_common(int sig, struct sigcontext *sc) +static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)  {  	struct uml_pt_regs r;  	int save_errno = errno; @@ -38,15 +33,15 @@ static void sig_handler_common(int sig, struct sigcontext *sc)  	r.is_user = 0;  	if (sig == SIGSEGV) {  		/* For segfaults, we want the data from the sigcontext. */ -		copy_sc(&r, sc); -		GET_FAULTINFO_FROM_SC(r.faultinfo, sc); +		get_regs_from_mc(&r, mc); +		GET_FAULTINFO_FROM_MC(r.faultinfo, mc);  	}  	/* enable signals if sig isn't IRQ signal */  	if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))  		unblock_signals(); -	(*sig_info[sig])(sig, &r); +	(*sig_info[sig])(sig, si, &r);  	errno = save_errno;  } @@ -66,7 +61,7 @@ static void sig_handler_common(int sig, struct sigcontext *sc)  static int signals_enabled;  static unsigned int signals_pending; -void sig_handler(int sig, struct sigcontext *sc) +void sig_handler(int sig, struct siginfo *si, mcontext_t *mc)  {  	int enabled; @@ -78,23 +73,23 @@ void sig_handler(int sig, struct sigcontext *sc)  	block_signals(); -	sig_handler_common(sig, sc); +	sig_handler_common(sig, si, mc);  	set_signals(enabled);  } -static void real_alarm_handler(struct sigcontext *sc) +static void real_alarm_handler(mcontext_t *mc)  {  	struct uml_pt_regs regs; -	if (sc != NULL) -		copy_sc(®s, sc); +	if (mc != NULL) +		get_regs_from_mc(®s, mc);  	regs.is_user = 0;  	unblock_signals(); -	timer_handler(SIGVTALRM, ®s); +	timer_handler(SIGVTALRM, NULL, ®s);  } -void alarm_handler(int sig, struct sigcontext *sc) +void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)  {  	int enabled; @@ -106,14 +101,13 @@ void alarm_handler(int sig, struct sigcontext *sc)  	block_signals(); -	real_alarm_handler(sc); +	real_alarm_handler(mc);  	set_signals(enabled);  }  void timer_init(void)  { -	set_handler(SIGVTALRM, (__sighandler_t) alarm_handler, -		    SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, -1); +	set_handler(SIGVTALRM);  }  void set_sigstack(void *sig_stack, int size) @@ -126,10 +120,23 @@ void set_sigstack(void *sig_stack, int size)  		panic("enabling signal stack failed, errno = %d\n", errno);  } -static void (*handlers[_NSIG])(int sig, struct sigcontext *sc); +static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { +	[SIGSEGV] = sig_handler, +	[SIGBUS] = sig_handler, +	[SIGILL] = sig_handler, +	[SIGFPE] = sig_handler, +	[SIGTRAP] = sig_handler, + +	[SIGIO] = sig_handler, +	[SIGWINCH] = sig_handler, +	[SIGVTALRM] = alarm_handler +}; + -void handle_signal(int sig, struct sigcontext *sc) +static void hard_handler(int sig, siginfo_t *si, void *p)  { +	struct ucontext *uc = p; +	mcontext_t *mc = &uc->uc_mcontext;  	unsigned long pending = 1UL << sig;  	do { @@ -155,7 +162,7 @@ void handle_signal(int sig, struct sigcontext *sc)  		while ((sig = ffs(pending)) != 0){  			sig--;  			pending &= ~(1 << sig); -			(*handlers[sig])(sig, sc); +			(*handlers[sig])(sig, (struct siginfo *)si, mc);  		}  		/* @@ -169,28 +176,26 @@ void handle_signal(int sig, struct sigcontext *sc)  	} while (pending);  } -extern void hard_handler(int sig); - -void set_handler(int sig, void (*handler)(int), int flags, ...) +void set_handler(int sig)  {  	struct sigaction action; -	va_list ap; +	int flags = SA_SIGINFO | SA_ONSTACK;  	sigset_t sig_mask; -	int mask; -	handlers[sig] = (void (*)(int, struct sigcontext *)) handler; -	action.sa_handler = hard_handler; +	action.sa_sigaction = hard_handler; +	/* block irq ones */  	sigemptyset(&action.sa_mask); - -	va_start(ap, flags); -	while ((mask = va_arg(ap, int)) != -1) -		sigaddset(&action.sa_mask, mask); -	va_end(ap); +	sigaddset(&action.sa_mask, SIGVTALRM); +	sigaddset(&action.sa_mask, SIGIO); +	sigaddset(&action.sa_mask, SIGWINCH);  	if (sig == SIGSEGV)  		flags |= SA_NODEFER; +	if (sigismember(&action.sa_mask, sig)) +		flags |= SA_RESTART; /* if it's an irq signal */ +  	action.sa_flags = flags;  	action.sa_restorer = NULL;  	if (sigaction(sig, &action, NULL) < 0) @@ -269,9 +274,12 @@ void unblock_signals(void)  		 * Deal with SIGIO first because the alarm handler might  		 * schedule, leaving the pending SIGIO stranded until we come  		 * back here. +		 * +		 * SIGIO's handler doesn't use siginfo or mcontext, +		 * so they can be NULL.  		 */  		if (save_pending & SIGIO_MASK) -			sig_handler_common(SIGIO, NULL); +			sig_handler_common(SIGIO, NULL, NULL);  		if (save_pending & SIGVTALRM_MASK)  			real_alarm_handler(NULL); @@ -296,3 +304,11 @@ int set_signals(int enable)  	return ret;  } + +int os_is_signal_stack(void) +{ +	stack_t ss; +	sigaltstack(NULL, &ss); + +	return ss.ss_flags & SS_ONSTACK; +}  | 
