diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 43 | 
1 files changed, 17 insertions, 26 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 7f2683a10ac4..ceffc67b564a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -55,15 +55,14 @@  #include <asm/unistd.h>  #include <asm/pgtable.h>  #include <asm/mmu_context.h> -#include "cred-internals.h"  static void exit_mm(struct task_struct * tsk); -static void __unhash_process(struct task_struct *p) +static void __unhash_process(struct task_struct *p, bool group_dead)  {  	nr_threads--;  	detach_pid(p, PIDTYPE_PID); -	if (thread_group_leader(p)) { +	if (group_dead) {  		detach_pid(p, PIDTYPE_PGID);  		detach_pid(p, PIDTYPE_SID); @@ -80,10 +79,9 @@ static void __unhash_process(struct task_struct *p)  static void __exit_signal(struct task_struct *tsk)  {  	struct signal_struct *sig = tsk->signal; +	bool group_dead = thread_group_leader(tsk);  	struct sighand_struct *sighand; - -	BUG_ON(!sig); -	BUG_ON(!atomic_read(&sig->count)); +	struct tty_struct *uninitialized_var(tty);  	sighand = rcu_dereference_check(tsk->sighand,  					rcu_read_lock_held() || @@ -91,14 +89,16 @@ static void __exit_signal(struct task_struct *tsk)  	spin_lock(&sighand->siglock);  	posix_cpu_timers_exit(tsk); -	if (atomic_dec_and_test(&sig->count)) +	if (group_dead) {  		posix_cpu_timers_exit_group(tsk); -	else { +		tty = sig->tty; +		sig->tty = NULL; +	} else {  		/*  		 * If there is any task waiting for the group exit  		 * then notify it:  		 */ -		if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count) +		if (sig->notify_count > 0 && !--sig->notify_count)  			wake_up_process(sig->group_exit_task);  		if (tsk == sig->curr_target) @@ -124,32 +124,24 @@ static void __exit_signal(struct task_struct *tsk)  		sig->oublock += task_io_get_oublock(tsk);  		task_io_accounting_add(&sig->ioac, &tsk->ioac);  		sig->sum_sched_runtime += tsk->se.sum_exec_runtime; -		sig = NULL; /* Marker for below. */  	} -	__unhash_process(tsk); +	sig->nr_threads--; +	__unhash_process(tsk, group_dead);  	/*  	 * Do this under ->siglock, we can race with another thread  	 * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals.  	 */  	flush_sigqueue(&tsk->pending); - -	tsk->signal = NULL;  	tsk->sighand = NULL;  	spin_unlock(&sighand->siglock);  	__cleanup_sighand(sighand);  	clear_tsk_thread_flag(tsk,TIF_SIGPENDING); -	if (sig) { +	if (group_dead) {  		flush_sigqueue(&sig->shared_pending); -		taskstats_tgid_free(sig); -		/* -		 * Make sure ->signal can't go away under rq->lock, -		 * see account_group_exec_runtime(). -		 */ -		task_rq_unlock_wait(tsk); -		__cleanup_signal(sig); +		tty_kref_put(tty);  	}  } @@ -857,12 +849,9 @@ static void exit_notify(struct task_struct *tsk, int group_dead)  	tsk->exit_state = signal == DEATH_REAP ? EXIT_DEAD : EXIT_ZOMBIE; -	/* mt-exec, de_thread() is waiting for us */ -	if (thread_group_leader(tsk) && -	    tsk->signal->group_exit_task && -	    tsk->signal->notify_count < 0) +	/* mt-exec, de_thread() is waiting for group leader */ +	if (unlikely(tsk->signal->notify_count < 0))  		wake_up_process(tsk->signal->group_exit_task); -  	write_unlock_irq(&tasklist_lock);  	tracehook_report_death(tsk, signal, cookie, group_dead); @@ -1003,8 +992,10 @@ NORET_TYPE void do_exit(long code)  	exit_notify(tsk, group_dead);  #ifdef CONFIG_NUMA +	task_lock(tsk);  	mpol_put(tsk->mempolicy);  	tsk->mempolicy = NULL; +	task_unlock(tsk);  #endif  #ifdef CONFIG_FUTEX  	if (unlikely(current->pi_state_cache))  | 
