|
@@ -744,6 +744,38 @@ static int ignoring_children(struct sighand_struct *sigh)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/* Returns nonzero if the tracee should be released. */
|
|
|
+int __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
|
|
|
+{
|
|
|
+ __ptrace_unlink(p);
|
|
|
+
|
|
|
+ if (p->exit_state != EXIT_ZOMBIE)
|
|
|
+ return 0;
|
|
|
+ /*
|
|
|
+ * If it's a zombie, our attachedness prevented normal
|
|
|
+ * parent notification or self-reaping. Do notification
|
|
|
+ * now if it would have happened earlier. If it should
|
|
|
+ * reap itself we return true.
|
|
|
+ *
|
|
|
+ * If it's our own child, there is no notification to do.
|
|
|
+ * But if our normal children self-reap, then this child
|
|
|
+ * was prevented by ptrace and we must reap it now.
|
|
|
+ */
|
|
|
+ if (!task_detached(p) && thread_group_empty(p)) {
|
|
|
+ if (!same_thread_group(p->real_parent, tracer))
|
|
|
+ do_notify_parent(p, p->exit_signal);
|
|
|
+ else if (ignoring_children(tracer->sighand))
|
|
|
+ p->exit_signal = -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!task_detached(p))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* Mark it as in the process of being reaped. */
|
|
|
+ p->exit_state = EXIT_DEAD;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Detach all tasks we were using ptrace on.
|
|
|
* Any that need to be release_task'd are put on the @dead list.
|
|
@@ -755,36 +787,8 @@ static void ptrace_exit(struct task_struct *parent, struct list_head *dead)
|
|
|
struct task_struct *p, *n;
|
|
|
|
|
|
list_for_each_entry_safe(p, n, &parent->ptraced, ptrace_entry) {
|
|
|
- __ptrace_unlink(p);
|
|
|
-
|
|
|
- if (p->exit_state != EXIT_ZOMBIE)
|
|
|
- continue;
|
|
|
-
|
|
|
- /*
|
|
|
- * If it's a zombie, our attachedness prevented normal
|
|
|
- * parent notification or self-reaping. Do notification
|
|
|
- * now if it would have happened earlier. If it should
|
|
|
- * reap itself, add it to the @dead list. We can't call
|
|
|
- * release_task() here because we already hold tasklist_lock.
|
|
|
- *
|
|
|
- * If it's our own child, there is no notification to do.
|
|
|
- * But if our normal children self-reap, then this child
|
|
|
- * was prevented by ptrace and we must reap it now.
|
|
|
- */
|
|
|
- if (!task_detached(p) && thread_group_empty(p)) {
|
|
|
- if (!same_thread_group(p->real_parent, parent))
|
|
|
- do_notify_parent(p, p->exit_signal);
|
|
|
- else if (ignoring_children(parent->sighand))
|
|
|
- p->exit_signal = -1;
|
|
|
- }
|
|
|
-
|
|
|
- if (task_detached(p)) {
|
|
|
- /*
|
|
|
- * Mark it as in the process of being reaped.
|
|
|
- */
|
|
|
- p->exit_state = EXIT_DEAD;
|
|
|
+ if (__ptrace_detach(parent, p))
|
|
|
list_add(&p->ptrace_entry, dead);
|
|
|
- }
|
|
|
}
|
|
|
}
|
|
|
|