aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2005-01-09 23:18:02 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-01-09 23:18:02 -0800
commita9625ef18290632e9b2abf9e63bb90c0b9cb64a6 (patch)
tree0029159d4b4e9e3e98af07803527ae0cb09115d3 /kernel
parent819509c9c2185717899d9224ee81d74123f616ad (diff)
downloadhistory-a9625ef18290632e9b2abf9e63bb90c0b9cb64a6.tar.gz
[PATCH] fix __ptrace_unlink TASK_TRACED recovery for real parent
The __ptrace_unlink code that checks for TASK_TRACED fixed the problem of a thread being left in TASK_TRACED when no longer being ptraced. However, an oversight in the original fix made it fail to handle the case where the child is ptraced by its real parent. Fixed thus. Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/ptrace.c47
2 files changed, 26 insertions, 23 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 54a59c727356ce..7127c15faf28c3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -557,7 +557,7 @@ static inline void reparent_thread(task_t *p, task_t *father, int traced)
* a normal stop since it's no longer being
* traced.
*/
- p->state = TASK_STOPPED;
+ ptrace_untrace(p);
}
}
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 60801c692810e6..794f7d0a670dc2 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -45,6 +45,23 @@ static inline int pending_resume_signal(struct sigpending *pending)
}
/*
+ * Turn a tracing stop into a normal stop now, since with no tracer there
+ * would be no way to wake it up with SIGCONT or SIGKILL. If there was a
+ * signal sent that would resume the child, but didn't because it was in
+ * TASK_TRACED, resume it now.
+ */
+void ptrace_untrace(task_t *child)
+{
+ spin_lock(&child->sighand->siglock);
+ child->state = TASK_STOPPED;
+ if (pending_resume_signal(&child->pending) ||
+ pending_resume_signal(&child->signal->shared_pending)) {
+ signal_wake_up(child, 1);
+ }
+ spin_unlock(&child->sighand->siglock);
+}
+
+/*
* unptrace a task: move it back to its original parent and
* remove it from the ptrace list.
*
@@ -55,29 +72,15 @@ void __ptrace_unlink(task_t *child)
if (!child->ptrace)
BUG();
child->ptrace = 0;
- if (list_empty(&child->ptrace_list))
- return;
- list_del_init(&child->ptrace_list);
- REMOVE_LINKS(child);
- child->parent = child->real_parent;
- SET_LINKS(child);
-
- if (child->state == TASK_TRACED) {
- /*
- * Turn a tracing stop into a normal stop now,
- * since with no tracer there would be no way
- * to wake it up with SIGCONT or SIGKILL.
- * If there was a signal sent that would resume the child,
- * but didn't because it was in TASK_TRACED, resume it now.
- */
- spin_lock(&child->sighand->siglock);
- child->state = TASK_STOPPED;
- if (pending_resume_signal(&child->pending) ||
- pending_resume_signal(&child->signal->shared_pending)) {
- signal_wake_up(child, 1);
- }
- spin_unlock(&child->sighand->siglock);
+ if (!list_empty(&child->ptrace_list)) {
+ list_del_init(&child->ptrace_list);
+ REMOVE_LINKS(child);
+ child->parent = child->real_parent;
+ SET_LINKS(child);
}
+
+ if (child->state == TASK_TRACED)
+ ptrace_untrace(child);
}
/*