diff options
Diffstat (limited to 'arch/um/kernel/signal_user.c')
| -rw-r--r-- | arch/um/kernel/signal_user.c | 157 | 
1 files changed, 157 insertions, 0 deletions
diff --git a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c new file mode 100644 index 00000000000..62f457835fb --- /dev/null +++ b/arch/um/kernel/signal_user.c @@ -0,0 +1,157 @@ +/*  + * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <errno.h> +#include <stdarg.h> +#include <string.h> +#include <sys/mman.h> +#include "user_util.h" +#include "kern_util.h" +#include "user.h" +#include "signal_user.h" +#include "signal_kern.h" +#include "sysdep/sigcontext.h" +#include "sigcontext.h" + +void set_sigstack(void *sig_stack, int size) +{ +	stack_t stack = ((stack_t) { .ss_flags	= 0, +				     .ss_sp	= (__ptr_t) sig_stack, +				     .ss_size 	= size - sizeof(void *) }); + +	if(sigaltstack(&stack, NULL) != 0) +		panic("enabling signal stack failed, errno = %d\n", errno); +} + +void set_handler(int sig, void (*handler)(int), int flags, ...) +{ +	struct sigaction action; +	va_list ap; +	int mask; + +	va_start(ap, flags); +	action.sa_handler = handler; +	sigemptyset(&action.sa_mask); +	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) +		panic("sigaction failed"); +} + +int change_sig(int signal, int on) +{ +	sigset_t sigset, old; + +	sigemptyset(&sigset); +	sigaddset(&sigset, signal); +	sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old); +	return(!sigismember(&old, signal)); +} + +/* Both here and in set/get_signal we don't touch SIGPROF, because we must not + * disable profiling; it's safe because the profiling code does not interact + * with the kernel code at all.*/ + +static void change_signals(int type) +{ +	sigset_t mask; + +	sigemptyset(&mask); +	sigaddset(&mask, SIGVTALRM); +	sigaddset(&mask, SIGALRM); +	sigaddset(&mask, SIGIO); +	if(sigprocmask(type, &mask, NULL) < 0) +		panic("Failed to change signal mask - errno = %d", errno); +} + +void block_signals(void) +{ +	change_signals(SIG_BLOCK); +} + +void unblock_signals(void) +{ +	change_signals(SIG_UNBLOCK); +} + +/* These are the asynchronous signals.  SIGVTALRM and SIGARLM are handled + * together under SIGVTALRM_BIT.  SIGPROF is excluded because we want to + * be able to profile all of UML, not just the non-critical sections.  If + * profiling is not thread-safe, then that is not my problem.  We can disable + * profiling when SMP is enabled in that case. + */ +#define SIGIO_BIT 0 +#define SIGVTALRM_BIT 1 + +static int enable_mask(sigset_t *mask) +{ +	int sigs; + +	sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT; +	sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT; +	sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT; +	return(sigs); +} + +int get_signals(void) +{ +	sigset_t mask; +	 +	if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0) +		panic("Failed to get signal mask"); +	return(enable_mask(&mask)); +} + +int set_signals(int enable) +{ +	sigset_t mask; +	int ret; + +	sigemptyset(&mask); +	if(enable & (1 << SIGIO_BIT))  +		sigaddset(&mask, SIGIO); +	if(enable & (1 << SIGVTALRM_BIT)){ +		sigaddset(&mask, SIGVTALRM); +		sigaddset(&mask, SIGALRM); +	} + +	/* This is safe - sigprocmask is guaranteed to copy locally the +	 * value of new_set, do his work and then, at the end, write to +	 * old_set. +	 */ +	if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) +		panic("Failed to enable signals"); +	ret = enable_mask(&mask); +	sigemptyset(&mask); +	if((enable & (1 << SIGIO_BIT)) == 0)  +		sigaddset(&mask, SIGIO); +	if((enable & (1 << SIGVTALRM_BIT)) == 0){ +		sigaddset(&mask, SIGVTALRM); +		sigaddset(&mask, SIGALRM); +	} +	if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0) +		panic("Failed to block signals"); + +	return(ret); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only.  This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */  | 
