diff options
| author | Sascha Hauer <s.hauer@pengutronix.de> | 2011-08-03 09:42:39 +0200 | 
|---|---|---|
| committer | Sascha Hauer <s.hauer@pengutronix.de> | 2011-08-03 09:42:39 +0200 | 
| commit | c61daf6b0a2f7048c6e74d52b043fa6a779b128a (patch) | |
| tree | a4a38656ac79775f38ce5fd6b00dd9b89cd5ccec /kernel/exit.c | |
| parent | 786c89f7a24b4ed8b68dfb136347267875315c30 (diff) | |
| parent | 160a84cfc975f4aaec1cb32a48bba23ccaf43761 (diff) | |
Merge branch 'imx-cleanup' of git://git.pengutronix.de/git/ukl/linux-2.6 into imx-cleanup
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 94 | 
1 files changed, 41 insertions, 53 deletions
| diff --git a/kernel/exit.c b/kernel/exit.c index f2b321bae44..2913b3509d4 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -85,7 +85,6 @@ static void __exit_signal(struct task_struct *tsk)  	struct tty_struct *uninitialized_var(tty);  	sighand = rcu_dereference_check(tsk->sighand, -					rcu_read_lock_held() ||  					lockdep_tasklist_lock_is_held());  	spin_lock(&sighand->siglock); @@ -169,7 +168,6 @@ void release_task(struct task_struct * p)  	struct task_struct *leader;  	int zap_leader;  repeat: -	tracehook_prepare_release_task(p);  	/* don't need to get the RCU readlock here - the process is dead and  	 * can't be modifying its own credentials. But shut RCU-lockdep up */  	rcu_read_lock(); @@ -179,7 +177,7 @@ repeat:  	proc_flush_task(p);  	write_lock_irq(&tasklist_lock); -	tracehook_finish_release_task(p); +	ptrace_release_task(p);  	__exit_signal(p);  	/* @@ -190,22 +188,12 @@ repeat:  	zap_leader = 0;  	leader = p->group_leader;  	if (leader != p && thread_group_empty(leader) && leader->exit_state == EXIT_ZOMBIE) { -		BUG_ON(task_detached(leader)); -		do_notify_parent(leader, leader->exit_signal);  		/*  		 * If we were the last child thread and the leader has  		 * exited already, and the leader's parent ignores SIGCHLD,  		 * then we are the one who should release the leader. -		 * -		 * do_notify_parent() will have marked it self-reaping in -		 * that case. -		 */ -		zap_leader = task_detached(leader); - -		/* -		 * This maintains the invariant that release_task() -		 * only runs on a task in EXIT_DEAD, just for sanity.  		 */ +		zap_leader = do_notify_parent(leader, leader->exit_signal);  		if (zap_leader)  			leader->exit_state = EXIT_DEAD;  	} @@ -277,18 +265,16 @@ int is_current_pgrp_orphaned(void)  	return retval;  } -static int has_stopped_jobs(struct pid *pgrp) +static bool has_stopped_jobs(struct pid *pgrp)  { -	int retval = 0;  	struct task_struct *p;  	do_each_pid_task(pgrp, PIDTYPE_PGID, p) { -		if (!task_is_stopped(p)) -			continue; -		retval = 1; -		break; +		if (p->signal->flags & SIGNAL_STOP_STOPPED) +			return true;  	} while_each_pid_task(pgrp, PIDTYPE_PGID, p); -	return retval; + +	return false;  }  /* @@ -751,7 +737,7 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,  {  	list_move_tail(&p->sibling, &p->real_parent->children); -	if (task_detached(p)) +	if (p->exit_state == EXIT_DEAD)  		return;  	/*  	 * If this is a threaded reparent there is no need to @@ -764,10 +750,9 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,  	p->exit_signal = SIGCHLD;  	/* If it has exited notify the new parent about this child's death. */ -	if (!task_ptrace(p) && +	if (!p->ptrace &&  	    p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) { -		do_notify_parent(p, p->exit_signal); -		if (task_detached(p)) { +		if (do_notify_parent(p, p->exit_signal)) {  			p->exit_state = EXIT_DEAD;  			list_move_tail(&p->sibling, dead);  		} @@ -794,7 +779,7 @@ static void forget_original_parent(struct task_struct *father)  		do {  			t->real_parent = reaper;  			if (t->parent == father) { -				BUG_ON(task_ptrace(t)); +				BUG_ON(t->ptrace);  				t->parent = t->real_parent;  			}  			if (t->pdeath_signal) @@ -819,8 +804,7 @@ static void forget_original_parent(struct task_struct *father)   */  static void exit_notify(struct task_struct *tsk, int group_dead)  { -	int signal; -	void *cookie; +	bool autoreap;  	/*  	 * This does two things: @@ -851,26 +835,33 @@ static void exit_notify(struct task_struct *tsk, int group_dead)  	 * we have changed execution domain as these two values started  	 * the same after a fork.  	 */ -	if (tsk->exit_signal != SIGCHLD && !task_detached(tsk) && +	if (thread_group_leader(tsk) && tsk->exit_signal != SIGCHLD &&  	    (tsk->parent_exec_id != tsk->real_parent->self_exec_id ||  	     tsk->self_exec_id != tsk->parent_exec_id))  		tsk->exit_signal = SIGCHLD; -	signal = tracehook_notify_death(tsk, &cookie, group_dead); -	if (signal >= 0) -		signal = do_notify_parent(tsk, signal); +	if (unlikely(tsk->ptrace)) { +		int sig = thread_group_leader(tsk) && +				thread_group_empty(tsk) && +				!ptrace_reparented(tsk) ? +			tsk->exit_signal : SIGCHLD; +		autoreap = do_notify_parent(tsk, sig); +	} else if (thread_group_leader(tsk)) { +		autoreap = thread_group_empty(tsk) && +			do_notify_parent(tsk, tsk->exit_signal); +	} else { +		autoreap = true; +	} -	tsk->exit_state = signal == DEATH_REAP ? EXIT_DEAD : EXIT_ZOMBIE; +	tsk->exit_state = autoreap ? EXIT_DEAD : EXIT_ZOMBIE;  	/* 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); -  	/* If the process is dead, release it - nobody will wait for it */ -	if (signal == DEATH_REAP) +	if (autoreap)  		release_task(tsk);  } @@ -906,7 +897,6 @@ NORET_TYPE void do_exit(long code)  	profile_task_exit(tsk); -	WARN_ON(atomic_read(&tsk->fs_excl));  	WARN_ON(blk_needs_flush_plug(tsk));  	if (unlikely(in_interrupt())) @@ -923,7 +913,7 @@ NORET_TYPE void do_exit(long code)  	 */  	set_fs(USER_DS); -	tracehook_report_exit(&code); +	ptrace_event(PTRACE_EVENT_EXIT, code);  	validate_creds_for_do_exit(tsk); @@ -990,6 +980,7 @@ NORET_TYPE void do_exit(long code)  	trace_sched_process_exit(tsk);  	exit_sem(tsk); +	exit_shm(tsk);  	exit_files(tsk);  	exit_fs(tsk);  	check_stack_usage(); @@ -1235,9 +1226,9 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)  	traced = ptrace_reparented(p);  	/*  	 * It can be ptraced but not reparented, check -	 * !task_detached() to filter out sub-threads. +	 * thread_group_leader() to filter out sub-threads.  	 */ -	if (likely(!traced) && likely(!task_detached(p))) { +	if (likely(!traced) && thread_group_leader(p)) {  		struct signal_struct *psig;  		struct signal_struct *sig;  		unsigned long maxrss; @@ -1345,16 +1336,13 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)  		/* We dropped tasklist, ptracer could die and untrace */  		ptrace_unlink(p);  		/* -		 * If this is not a detached task, notify the parent. -		 * If it's still not detached after that, don't release -		 * it now. +		 * If this is not a sub-thread, notify the parent. +		 * If parent wants a zombie, don't release it now.  		 */ -		if (!task_detached(p)) { -			do_notify_parent(p, p->exit_signal); -			if (!task_detached(p)) { -				p->exit_state = EXIT_ZOMBIE; -				p = NULL; -			} +		if (thread_group_leader(p) && +		    !do_notify_parent(p, p->exit_signal)) { +			p->exit_state = EXIT_ZOMBIE; +			p = NULL;  		}  		write_unlock_irq(&tasklist_lock);  	} @@ -1367,7 +1355,8 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)  static int *task_stopped_code(struct task_struct *p, bool ptrace)  {  	if (ptrace) { -		if (task_is_stopped_or_traced(p)) +		if (task_is_stopped_or_traced(p) && +		    !(p->jobctl & JOBCTL_LISTENING))  			return &p->exit_code;  	} else {  		if (p->signal->flags & SIGNAL_STOP_STOPPED) @@ -1563,7 +1552,7 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,  		 * Notification and reaping will be cascaded to the real  		 * parent when the ptracer detaches.  		 */ -		if (likely(!ptrace) && unlikely(task_ptrace(p))) { +		if (likely(!ptrace) && unlikely(p->ptrace)) {  			/* it will become visible, clear notask_error */  			wo->notask_error = 0;  			return 0; @@ -1606,8 +1595,7 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,  		 * own children, it should create a separate process which  		 * takes the role of real parent.  		 */ -		if (likely(!ptrace) && task_ptrace(p) && -		    same_thread_group(p->parent, p->real_parent)) +		if (likely(!ptrace) && p->ptrace && !ptrace_reparented(p))  			return 0;  		/* | 
