summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2010-09-11 23:42:04 -0400
committerRuss Cox <rsc@golang.org>2010-09-11 23:42:04 -0400
commit9948d45f42f64eea0f6335b3a7a6b641e21c0a38 (patch)
tree21b70ed0ed60ce2b087b9cc698f092d07821eced
parent0c102e2385bfbb55e9806dd324b7fb5671a3dda7 (diff)
downloadgo-9948d45f42f64eea0f6335b3a7a6b641e21c0a38.tar.gz
libmach: fix new thread race with Linux
If you look at the sequence of values returned by waitpid, it simply tells us about the child of clone before it tells us that the parent called clone. There's nothing we can do but assume unexpected tids are newly cloned children. Tested with 6prof on godoc. Fixes issue 251. R=r CC=golang-dev http://codereview.appspot.com/2167045
-rw-r--r--src/libmach/linux.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/src/libmach/linux.c b/src/libmach/linux.c
index 8ddcea8cd..e4e2fd5c7 100644
--- a/src/libmach/linux.c
+++ b/src/libmach/linux.c
@@ -202,6 +202,8 @@ attachthread(int pid, int tid, int *new, int newstate)
memset(t, 0, sizeof *t);
thr[nthr++] = t;
+ if(pid == 0 && nthr > 0)
+ pid = thr[0]->pid;
t->pid = pid;
t->tid = tid;
t->state = newstate;
@@ -296,7 +298,9 @@ wait1(int nohang)
if(nohang != 0)
nohang = WNOHANG;
+ status = 0;
tid = waitpid(-1, &status, __WALL|WUNTRACED|WSTOPPED|WCONTINUED|nohang);
+
if(tid < 0)
return -1;
if(tid == 0)
@@ -305,11 +309,15 @@ wait1(int nohang)
if(trace > 0 && status != NormalStop)
fprint(2, "TID %d: %#x\n", tid, status);
- // If we've not heard of this tid, something is wrong.
t = findthread(tid);
if(t == nil) {
- fprint(2, "ptrace waitpid: unexpected new tid %d status %#x\n", tid, status);
- return -1;
+ // Sometimes the kernel tells us about new threads
+ // before we see the parent clone.
+ t = attachthread(0, tid, &new, Stopped);
+ if(t == nil) {
+ fprint(2, "failed to attach to new thread %d\n", tid);
+ return -1;
+ }
}
if(WIFSTOPPED(status)) {
@@ -339,8 +347,6 @@ wait1(int nohang)
}
t->child = data;
attachthread(t->pid, t->child, &new, Running);
- if(!new)
- fprint(2, "ptrace child: not new\n");
break;
case PTRACE_EVENT_EXEC: