diff options
Diffstat (limited to 'kernel/signal.c')
| -rw-r--r-- | kernel/signal.c | 17 | 
1 files changed, 15 insertions, 2 deletions
| diff --git a/kernel/signal.c b/kernel/signal.c index d4ccea599692..9c33163a6165 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1961,14 +1961,27 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)  			return;  	} +	set_special_state(TASK_TRACED); +  	/*  	 * We're committing to trapping.  TRACED should be visible before  	 * TRAPPING is cleared; otherwise, the tracer might fail do_wait().  	 * Also, transition to TRACED and updates to ->jobctl should be  	 * atomic with respect to siglock and should be done after the arch  	 * hook as siglock is released and regrabbed across it. +	 * +	 *     TRACER				    TRACEE +	 * +	 *     ptrace_attach() +	 * [L]   wait_on_bit(JOBCTL_TRAPPING)	[S] set_special_state(TRACED) +	 *     do_wait() +	 *       set_current_state()                smp_wmb(); +	 *       ptrace_do_wait() +	 *         wait_task_stopped() +	 *           task_stopped_code() +	 * [L]         task_is_traced()		[S] task_clear_jobctl_trapping();  	 */ -	set_current_state(TASK_TRACED); +	smp_wmb();  	current->last_siginfo = info;  	current->exit_code = exit_code; @@ -2176,7 +2189,7 @@ static bool do_signal_stop(int signr)  		if (task_participate_group_stop(current))  			notify = CLD_STOPPED; -		__set_current_state(TASK_STOPPED); +		set_special_state(TASK_STOPPED);  		spin_unlock_irq(¤t->sighand->siglock);  		/* |