* the system call. That must prevent normal entry so no system call is
* made. If @task ever returns to user mode after this, its register state
* is unspecified, but should be something harmless like an %ENOSYS error
- * return.
+ * return. It should preserve enough information so that syscall_rollback()
+ * can work (see asm-generic/syscall.h).
*
* Called without locks, just after entering kernel mode.
*/
* tracehook_finish_clone - new child created and being attached
* @child: new child task
* @clone_flags: %CLONE_* flags from clone/fork/vfork system call
- * @trace: return value from tracehook_clone_prepare()
+ * @trace: return value from tracehook_prepare_clone()
*
* This is called immediately after adding @child to its parent's children list.
* The @trace value is that returned by tracehook_prepare_clone().
/**
* tracehook_report_clone - in parent, new child is about to start running
- * @trace: return value from tracehook_clone_prepare()
* @regs: parent's user register state
* @clone_flags: flags from parent's system call
* @pid: new child's PID in the parent's namespace
* @child: new child task
*
* Called after a child is set up, but before it has been started running.
- * The @trace value is that returned by tracehook_clone_prepare().
- * This is not a good place to block, because the child has not started yet.
- * Suspend the child here if desired, and block in tracehook_clone_complete().
- * This must prevent the child from self-reaping if tracehook_clone_complete()
- * uses the @child pointer; otherwise it might have died and been released by
- * the time tracehook_report_clone_complete() is called.
+ * This is not a good place to block, because the child has not started
+ * yet. Suspend the child here if desired, and then block in
+ * tracehook_report_clone_complete(). This must prevent the child from
+ * self-reaping if tracehook_report_clone_complete() uses the @child
+ * pointer; otherwise it might have died and been released by the time
+ * tracehook_report_clone_complete() is called.
*
* Called with no locks held, but the child cannot run until this returns.
*/
-static inline void tracehook_report_clone(int trace, struct pt_regs *regs,
+static inline void tracehook_report_clone(struct pt_regs *regs,
unsigned long clone_flags,
pid_t pid, struct task_struct *child)
{
- if (unlikely(trace)) {
+ if (unlikely(task_ptrace(child))) {
/*
- * The child starts up with an immediate SIGSTOP.
+ * It doesn't matter who attached/attaching to this
+ * task, the pending SIGSTOP is right in any case.
*/
sigaddset(&child->pending.signal, SIGSTOP);
set_tsk_thread_flag(child, TIF_SIGPENDING);
/**
* tracehook_report_clone_complete - new child is running
- * @trace: return value from tracehook_clone_prepare()
+ * @trace: return value from tracehook_prepare_clone()
* @regs: parent's user register state
* @clone_flags: flags from parent's system call
* @pid: new child's PID in the parent's namespace
}
/**
- * tracehook_finish_release_task - task is being reaped, clean up tracing
+ * tracehook_finish_release_task - final tracing clean-up
* @task: task in %EXIT_DEAD state
*
* This is called in release_task() when @task is being in the middle of
* tracehook_consider_ignored_signal - suppress short-circuit of ignored signal
* @task: task receiving the signal
* @sig: signal number being sent
- * @handler: %SIG_IGN or %SIG_DFL
*
* Return zero iff tracing doesn't care to examine this ignored signal,
* so it can short-circuit normal delivery and never even get queued.
- * Either @handler is %SIG_DFL and @sig's default is ignore, or it's %SIG_IGN.
*
* Called with @task->sighand->siglock held.
*/
static inline int tracehook_consider_ignored_signal(struct task_struct *task,
- int sig,
- void __user *handler)
+ int sig)
{
return (task_ptrace(task) & PT_PTRACED) != 0;
}
* tracehook_consider_fatal_signal - suppress special handling of fatal signal
* @task: task receiving the signal
* @sig: signal number being sent
- * @handler: %SIG_DFL or %SIG_IGN
*
* Return nonzero to prevent special handling of this termination signal.
- * Normally @handler is %SIG_DFL. It can be %SIG_IGN if @sig is ignored,
- * in which case force_sig() is about to reset it to %SIG_DFL.
+ * Normally handler for signal is %SIG_DFL. It can be %SIG_IGN if @sig is
+ * ignored, in which case force_sig() is about to reset it to %SIG_DFL.
* When this returns zero, this signal might cause a quick termination
* that does not give the debugger a chance to intercept the signal.
*
* Called with or without @task->sighand->siglock held.
*/
static inline int tracehook_consider_fatal_signal(struct task_struct *task,
- int sig,
- void __user *handler)
+ int sig)
{
return (task_ptrace(task) & PT_PTRACED) != 0;
}
return notify || (current->ptrace & PT_PTRACED);
}
+#define DEATH_REAP -1
+#define DEATH_DELAYED_GROUP_LEADER -2
+
/**
* 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.
+ * A return value >= 0 means call do_notify_parent() with that signal
+ * number. Negative return value can be %DEATH_REAP to self-reap right
+ * now, or %DEATH_DELAYED_GROUP_LEADER to a zombie without notifying our
+ * parent. Note that a return value of 0 means a do_notify_parent() call
+ * that sends no signal, but still wakes up a parent blocked in wait*().
*
* 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 (task_detached(task))
+ return task->ptrace ? SIGCHLD : DEATH_REAP;
/*
* If something other than our normal parent is ptracing us, then
if (thread_group_empty(task) && !ptrace_reparented(task))
return task->exit_signal;
- return task->ptrace ? SIGCHLD : 0;
+ return task->ptrace ? SIGCHLD : DEATH_DELAYED_GROUP_LEADER;
}
/**
* 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
+ * @signal: return value from tracheook_notify_death()
* @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 @signal is %DEATH_REAP, this thread will self-reap. If @signal is
+ * %DEATH_DELAYED_GROUP_LEADER, 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.