Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b2a1ff6 authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds
Browse files

tracehook: death



This moves the ptrace logic in task death (exit_notify) into tracehook.h
inlines.  Some code is rearranged slightly to make things nicer.  There is
no change, only cleanup.

There is one hook called with the tasklist_lock write-locked, as ptrace
needs.  There is also a new hook called after exit_state changes and
without locks.  This is a better place for tracing work to be in the
future, since it doesn't delay the whole system with locking.

Signed-off-by: default avatarRoland McGrath <roland@redhat.com>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Reviewed-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent fa00b80b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1796,7 +1796,7 @@ extern int kill_pid_info_as_uid(int, struct siginfo *, struct pid *, uid_t, uid_
extern int kill_pgrp(struct pid *pid, int sig, int priv);
extern int kill_pid(struct pid *pid, int sig, int priv);
extern int kill_proc_info(int, struct siginfo *, pid_t);
extern void do_notify_parent(struct task_struct *, int);
extern int do_notify_parent(struct task_struct *, int);
extern void force_sig(int, struct task_struct *);
extern void force_sig_specific(int, struct task_struct *);
extern int send_sig(int, struct task_struct *, int);
+52 −0
Original line number Diff line number Diff line
@@ -471,4 +471,56 @@ static inline int tracehook_notify_jctl(int notify, int why)
	return notify || (current->ptrace & PT_PTRACED);
}

/**
 * tracehook_notify_death - task is dead, ready to notify parent
 * @task:		@current task now exiting
 * @death_cookie:	value to pass to tracehook_report_death()
 * @group_dead:		nonzero if this was the last thread in the group to die
 *
 * Return the signal number to send our parent with do_notify_parent(), or
 * zero to send no signal and leave a zombie, or -1 to self-reap right now.
 *
 * Called with write_lock_irq(&tasklist_lock) held.
 */
static inline int tracehook_notify_death(struct task_struct *task,
					 void **death_cookie, int group_dead)
{
	if (task->exit_signal == -1)
		return task->ptrace ? SIGCHLD : -1;

	/*
	 * If something other than our normal parent is ptracing us, then
	 * send it a SIGCHLD instead of honoring exit_signal.  exit_signal
	 * only has special meaning to our real parent.
	 */
	if (thread_group_empty(task) && !ptrace_reparented(task))
		return task->exit_signal;

	return task->ptrace ? SIGCHLD : 0;
}

/**
 * tracehook_report_death - task is dead and ready to be reaped
 * @task:		@current task now exiting
 * @signal:		signal number sent to parent, or 0 or -1
 * @death_cookie:	value passed back from tracehook_notify_death()
 * @group_dead:		nonzero if this was the last thread in the group to die
 *
 * Thread has just become a zombie or is about to self-reap.  If positive,
 * @signal is the signal number just sent to the parent (usually %SIGCHLD).
 * If @signal is -1, this thread will self-reap.  If @signal is 0, this is
 * a delayed_group_leader() zombie.  The @death_cookie was passed back by
 * tracehook_notify_death().
 *
 * If normal reaping is not inhibited, @task->exit_state might be changing
 * in parallel.
 *
 * Called without locks.
 */
static inline void tracehook_report_death(struct task_struct *task,
					  int signal, void *death_cookie,
					  int group_dead)
{
}

#endif	/* <linux/tracehook.h> */
+9 −17
Original line number Diff line number Diff line
@@ -885,7 +885,8 @@ static void forget_original_parent(struct task_struct *father)
 */
static void exit_notify(struct task_struct *tsk, int group_dead)
{
	int state;
	int signal;
	void *cookie;

	/*
	 * This does two things:
@@ -922,22 +923,11 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
	    !capable(CAP_KILL))
		tsk->exit_signal = SIGCHLD;

	/* If something other than our normal parent is ptracing us, then
	 * send it a SIGCHLD instead of honoring exit_signal.  exit_signal
	 * only has special meaning to our real parent.
	 */
	if (!task_detached(tsk) && thread_group_empty(tsk)) {
		int signal = ptrace_reparented(tsk) ?
				SIGCHLD : tsk->exit_signal;
		do_notify_parent(tsk, signal);
	} else if (tsk->ptrace) {
		do_notify_parent(tsk, SIGCHLD);
	}
	signal = tracehook_notify_death(tsk, &cookie, group_dead);
	if (signal > 0)
		signal = do_notify_parent(tsk, signal);

	state = EXIT_ZOMBIE;
	if (task_detached(tsk) && likely(!tsk->ptrace))
		state = EXIT_DEAD;
	tsk->exit_state = state;
	tsk->exit_state = signal < 0 ? EXIT_DEAD : EXIT_ZOMBIE;

	/* mt-exec, de_thread() is waiting for us */
	if (thread_group_leader(tsk) &&
@@ -947,8 +937,10 @@ static void exit_notify(struct task_struct *tsk, int group_dead)

	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 (state == EXIT_DEAD)
	if (signal < 0)
		release_task(tsk);
}

+7 −3
Original line number Diff line number Diff line
@@ -1326,9 +1326,11 @@ static inline void __wake_up_parent(struct task_struct *p,
/*
 * Let a parent know about the death of a child.
 * For a stopped/continued status change, use do_notify_parent_cldstop instead.
 *
 * Returns -1 if our parent ignored us and so we've switched to
 * self-reaping, or else @sig.
 */

void do_notify_parent(struct task_struct *tsk, int sig)
int do_notify_parent(struct task_struct *tsk, int sig)
{
	struct siginfo info;
	unsigned long flags;
@@ -1399,12 +1401,14 @@ void do_notify_parent(struct task_struct *tsk, int sig)
		 */
		tsk->exit_signal = -1;
		if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN)
			sig = 0;
			sig = -1;
	}
	if (valid_signal(sig) && sig > 0)
		__group_send_sig_info(sig, &info, tsk->parent);
	__wake_up_parent(tsk, tsk->parent);
	spin_unlock_irqrestore(&psig->siglock, flags);

	return sig;
}

static void do_notify_parent_cldstop(struct task_struct *tsk, int why)