diff options
Diffstat (limited to 'arch/um/os-Linux/signal.c')
| -rw-r--r-- | arch/um/os-Linux/signal.c | 52 | 
1 files changed, 37 insertions, 15 deletions
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 75b10235d369..b58bc68cbe64 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -1,15 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})   * Copyright (C) 2015 Thomas Meyer ([email protected])   * Copyright (C) 2004 PathScale, Inc   * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL   */  #include <stdlib.h>  #include <stdarg.h>  #include <errno.h>  #include <signal.h> +#include <string.h>  #include <strings.h>  #include <as-layout.h>  #include <kern_util.h> @@ -26,7 +27,6 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {  	[SIGBUS]	= bus_handler,  	[SIGSEGV]	= segv_handler,  	[SIGIO]		= sigio_handler, -	[SIGALRM]	= timer_handler  };  static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) @@ -42,8 +42,8 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)  	}  	/* enable signals if sig isn't IRQ signal */ -	if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGALRM)) -		unblock_signals(); +	if ((sig != SIGIO) && (sig != SIGWINCH)) +		unblock_signals_trace();  	(*sig_info[sig])(sig, si, &r); @@ -76,11 +76,11 @@ void sig_handler(int sig, struct siginfo *si, mcontext_t *mc)  		return;  	} -	block_signals(); +	block_signals_trace();  	sig_handler_common(sig, si, mc); -	set_signals(enabled); +	set_signals_trace(enabled);  }  static void timer_real_alarm_handler(mcontext_t *mc) @@ -89,6 +89,8 @@ static void timer_real_alarm_handler(mcontext_t *mc)  	if (mc != NULL)  		get_regs_from_mc(®s, mc); +	else +		memset(®s, 0, sizeof(regs));  	timer_handler(SIGALRM, NULL, ®s);  } @@ -102,7 +104,7 @@ void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)  		return;  	} -	block_signals(); +	block_signals_trace();  	signals_active |= SIGALRM_MASK; @@ -110,7 +112,7 @@ void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)  	signals_active &= ~SIGALRM_MASK; -	set_signals(enabled); +	set_signals_trace(enabled);  }  void deliver_alarm(void) { @@ -251,6 +253,8 @@ void unblock_signals(void)  	if (signals_enabled == 1)  		return; +	signals_enabled = 1; +  	/*  	 * We loop because the IRQ handler returns with interrupts off.  So,  	 * interrupts may have arrived and we need to re-enable them and @@ -260,12 +264,9 @@ void unblock_signals(void)  		/*  		 * Save and reset save_pending after enabling signals.  This  		 * way, signals_pending won't be changed while we're reading it. -		 */ -		signals_enabled = 1; - -		/* +		 *  		 * Setting signals_enabled and reading signals_pending must -		 * happen in this order. +		 * happen in this order, so have the barrier here.  		 */  		barrier(); @@ -278,10 +279,13 @@ void unblock_signals(void)  		/*  		 * We have pending interrupts, so disable signals, as the  		 * handlers expect them off when they are called.  They will -		 * be enabled again above. +		 * be enabled again above. We need to trace this, as we're +		 * expected to be enabling interrupts already, but any more +		 * tracing that happens inside the handlers we call for the +		 * pending signals will mess up the tracing state.  		 */ -  		signals_enabled = 0; +		um_trace_signals_off();  		/*  		 * Deal with SIGIO first because the alarm handler might @@ -304,6 +308,9 @@ void unblock_signals(void)  		if (!(signals_pending & SIGIO_MASK) && (signals_active & SIGALRM_MASK))  			return; +		/* Re-enable signals and trace that we're doing so. */ +		um_trace_signals_on(); +		signals_enabled = 1;  	}  } @@ -326,6 +333,21 @@ int set_signals(int enable)  	return ret;  } +int set_signals_trace(int enable) +{ +	int ret; +	if (signals_enabled == enable) +		return enable; + +	ret = signals_enabled; +	if (enable) +		unblock_signals_trace(); +	else +		block_signals_trace(); + +	return ret; +} +  int os_is_signal_stack(void)  {  	stack_t ss;  |