This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [RFC]: fix for recycled thread ids
On Wed, Mar 24, 2004 at 11:39:50PM -0500, Daniel Jacobowitz wrote:
> Do you have any code for PTRACE_EVENT_CLONE yet, or should I put
> something together in the morning to verify whether that's the problem?
Here you go. Again, this patch is obviously not ready to go into GDB,
but I have not been able to make it misbehave yet. I don't know if all
the bits it needs work right in RHEL3, or if my testing was conclusive.
The highlights:
- Includes most of the previous patch
- Uses PTRACE_EVENT_CLONE to attach to new threads
- Moves handling of events closer to the waitpid call
There are some potential races but I haven't hit any of them in
practice. I suspect that with a heavy fork or vfork load (not clone)
you could produce interesting failure modes.
Give it a try, please. If it works I'll clean it up.
--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer
Index: lin-lwp.c
===================================================================
RCS file: /cvs/src/src/gdb/lin-lwp.c,v
retrieving revision 1.53
diff -u -p -r1.53 lin-lwp.c
--- lin-lwp.c 22 Mar 2004 20:18:33 -0000 1.53
+++ lin-lwp.c 25 Mar 2004 16:31:30 -0000
@@ -183,6 +183,8 @@ add_lwp (ptid_t ptid)
memset (lp, 0, sizeof (struct lwp_info));
+ lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+
lp->ptid = ptid;
lp->next = lwp_list;
@@ -278,7 +280,7 @@ lin_lwp_open (char *args, int from_tty)
void
lin_lwp_attach_lwp (ptid_t ptid, int verbose)
{
- struct lwp_info *lp;
+ struct lwp_info *lp, *found_lp;
gdb_assert (is_lwp (ptid));
@@ -293,13 +295,13 @@ lin_lwp_attach_lwp (ptid_t ptid, int ver
if (verbose)
printf_filtered ("[New %s]\n", target_pid_to_str (ptid));
- lp = find_lwp_pid (ptid);
+ found_lp = lp = find_lwp_pid (ptid);
if (lp == NULL)
lp = add_lwp (ptid);
/* We assume that we're already attached to any LWP that has an
id equal to the overall process id. */
- if (GET_LWP (ptid) != GET_PID (ptid))
+ if (GET_LWP (ptid) != GET_PID (ptid) && found_lp == NULL)
{
pid_t pid;
int status;
@@ -658,6 +660,30 @@ wait_lwp (struct lwp_info *lp)
gdb_assert (WIFSTOPPED (status));
+ /* Handle GNU/Linux's extended waitstatus for trace events. */
+ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "WL: Handling extended status 0x%06x\n",
+ status);
+ linux_handle_extended_wait (GET_LWP (lp->ptid), status,
+ &lp->waitstatus);
+ if (lp->waitstatus.kind == TARGET_WAITKIND_SPURIOUS)
+ {
+ struct lwp_info *new_lp;
+ new_lp = add_lwp (BUILD_LWP (lp->waitstatus.value.related_pid,
+ GET_PID (inferior_ptid)));
+ new_lp->cloned = 1;
+ new_lp->stopped = 1;
+ lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+ fprintf_unfiltered (gdb_stdlog,
+ "WL: Got clone event from LWP %d, resuming\n",
+ GET_LWP (lp->ptid));
+ ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+ return wait_lwp (lp);
+ }
+ }
+
return status;
}
@@ -1161,7 +1187,14 @@ child_wait (ptid_t ptid, struct target_w
/* Handle GNU/Linux's extended waitstatus for trace events. */
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
- return linux_handle_extended_wait (pid, status, ourstatus);
+ {
+ ptid_t wait_ptid;
+ wait_ptid = linux_handle_extended_wait (pid, status, ourstatus);
+ if (ourstatus->kind == TARGET_WAITKIND_SPURIOUS)
+ ptrace (PTRACE_DETACH, ourstatus->value.related_pid,
+ 0, 0);
+ return wait_ptid;
+ }
store_waitstatus (ourstatus, status);
return pid_to_ptid (pid);
@@ -1371,6 +1404,31 @@ retry:
}
}
+ /* Handle GNU/Linux's extended waitstatus for trace events. */
+ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: Handling extended status 0x%06x\n",
+ status);
+ linux_handle_extended_wait (GET_LWP (lp->ptid), status,
+ &lp->waitstatus);
+ if (lp->waitstatus.kind == TARGET_WAITKIND_SPURIOUS)
+ {
+ struct lwp_info *new_lp;
+ new_lp = add_lwp (BUILD_LWP (lp->waitstatus.value.related_pid,
+ GET_PID (inferior_ptid)));
+ new_lp->cloned = 1;
+ new_lp->stopped = 1;
+ lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+ fprintf_unfiltered (gdb_stdlog,
+ "LLW: Got clone event from LWP %d, resuming\n",
+ GET_LWP (lp->ptid));
+ ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+ status = 0;
+ continue;
+ }
+ }
+
/* Check if the thread has exited. */
if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
{
@@ -1588,14 +1646,14 @@ retry:
else
trap_ptid = null_ptid;
- /* Handle GNU/Linux's extended waitstatus for trace events. */
- if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+ if (lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
{
- linux_handle_extended_wait (GET_LWP (lp->ptid), status, ourstatus);
- return trap_ptid;
+ *ourstatus = lp->waitstatus;
+ lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
}
+ else
+ store_waitstatus (ourstatus, status);
- store_waitstatus (ourstatus, status);
return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
}
Index: linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.c,v
retrieving revision 1.5
diff -u -p -r1.5 linux-nat.c
--- linux-nat.c 17 Aug 2003 20:17:02 -0000 1.5
+++ linux-nat.c 25 Mar 2004 16:31:30 -0000
@@ -224,7 +224,8 @@ linux_enable_event_reporting (ptid_t pti
if (! linux_supports_tracefork ())
return;
- options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC;
+ options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC
+ | PTRACE_O_TRACECLONE;
if (linux_supports_tracevforkdone ())
options |= PTRACE_O_TRACEVFORKDONE;
@@ -391,11 +392,8 @@ linux_handle_extended_wait (int pid, int
{
int event = status >> 16;
- if (event == PTRACE_EVENT_CLONE)
- internal_error (__FILE__, __LINE__,
- "unexpected clone event");
-
- if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK)
+ if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK
+ || event == PTRACE_EVENT_CLONE)
{
unsigned long new_pid;
int ret;
@@ -406,12 +404,10 @@ linux_handle_extended_wait (int pid, int
if (! pull_pid_from_list (&stopped_pids, new_pid))
{
/* The new child has a pending SIGSTOP. We can't affect it until it
- hits the SIGSTOP, but we're already attached.
-
- It won't be a clone (we didn't ask for clones in the event mask)
- so we can just call waitpid and wait for the SIGSTOP. */
+ hits the SIGSTOP, but we're already attached. */
do {
- ret = waitpid (new_pid, &status, 0);
+ ret = waitpid (new_pid, &status,
+ (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
} while (ret == -1 && errno == EINTR);
if (ret == -1)
perror_with_name ("waiting for new child");
@@ -423,8 +419,13 @@ linux_handle_extended_wait (int pid, int
"wait returned unexpected status 0x%x", status);
}
- ourstatus->kind = (event == PTRACE_EVENT_FORK)
- ? TARGET_WAITKIND_FORKED : TARGET_WAITKIND_VFORKED;
+ if (event == PTRACE_EVENT_FORK)
+ ourstatus->kind = TARGET_WAITKIND_FORKED;
+ else if (event == PTRACE_EVENT_VFORK)
+ ourstatus->kind = TARGET_WAITKIND_VFORKED;
+ else
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+
ourstatus->value.related_pid = new_pid;
return inferior_ptid;
}
Index: linux-nat.h
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.h,v
retrieving revision 1.5
diff -u -p -r1.5 linux-nat.h
--- linux-nat.h 14 Sep 2003 02:04:44 -0000 1.5
+++ linux-nat.h 25 Mar 2004 16:31:30 -0000
@@ -1,5 +1,5 @@
/* Native debugging support for GNU/Linux (LWP layer).
- Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
@@ -18,6 +18,8 @@
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#include "target.h"
+
/* Structure describing an LWP. */
struct lwp_info
@@ -52,6 +54,10 @@ struct lwp_info
/* Non-zero if we were stepping this LWP. */
int step;
+ /* If WAITSTATUS->KIND != TARGET_WAITKIND_SPURIOUS, the waitstatus
+ corresponding to STATUS above. */
+ struct target_waitstatus waitstatus;
+
/* Next LWP in list. */
struct lwp_info *next;
};
@@ -60,7 +66,6 @@ struct lwp_info
system". */
struct mem_attrib;
struct target_ops;
-struct target_waitstatus;
extern int linux_proc_xfer_memory (CORE_ADDR addr, char *myaddr, int len,
int write, struct mem_attrib *attrib,
Index: thread-db.c
===================================================================
RCS file: /cvs/src/src/gdb/thread-db.c,v
retrieving revision 1.37
diff -u -p -r1.37 thread-db.c
--- thread-db.c 29 Feb 2004 02:39:47 -0000 1.37
+++ thread-db.c 25 Mar 2004 16:31:31 -0000
@@ -1,6 +1,6 @@
/* libthread_db assisted debugging support, generic parts.
- Copyright 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+ Copyright 1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
This file is part of GDB.
@@ -130,6 +130,7 @@ static CORE_ADDR td_death_bp_addr;
static void thread_db_find_new_threads (void);
static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
const td_thrinfo_t *ti_p, int verbose);
+static void detach_thread (ptid_t ptid, int verbose);
/* Building process ids. */
@@ -154,6 +155,8 @@ struct private_thread_info
unsigned int th_valid:1;
unsigned int ti_valid:1;
+ unsigned int dying:1;
+
td_thrhandle_t th;
td_thrinfo_t ti;
};
@@ -501,7 +504,7 @@ enable_thread_event_reporting (void)
/* Set the process wide mask saying which events we're interested in. */
td_event_emptyset (&events);
td_event_addset (&events, TD_CREATE);
-#if 0
+#if 1
/* FIXME: kettenis/2000-04-23: The event reporting facility is
broken for TD_DEATH events in glibc 2.1.3, so don't enable it for
now. */
@@ -696,6 +699,20 @@ attach_thread (ptid_t ptid, const td_thr
struct thread_info *tp;
td_err_e err;
+ /* We may already know about this thread, for instance when the
+ user has issued the `info threads' command before the SIGTRAP
+ for hitting the thread creation breakpoint was reported. */
+ if (in_thread_list (ptid))
+ {
+ tp = find_thread_pid (ptid);
+ gdb_assert (tp != NULL);
+
+ if (!tp->private->dying)
+ return;
+
+ delete_thread (ptid);
+ }
+
check_thread_signals ();
/* Add the thread to GDB's thread list. */
@@ -741,8 +758,16 @@ thread_db_attach (char *args, int from_t
static void
detach_thread (ptid_t ptid, int verbose)
{
+ struct thread_info *thread_info;
+
if (verbose)
printf_unfiltered ("[%s exited]\n", target_pid_to_str (ptid));
+
+ /* Don't delete the thread now, because it still reports as active until
+ it has executed a few instructions after the event breakpoint. */
+ thread_info = find_thread_pid (ptid);
+ gdb_assert (thread_info != NULL);
+ thread_info->private->dying = 1;
}
static void
@@ -848,11 +873,7 @@ check_event (ptid_t ptid)
{
case TD_CREATE:
- /* We may already know about this thread, for instance when the
- user has issued the `info threads' command before the SIGTRAP
- for hitting the thread creation breakpoint was reported. */
- if (!in_thread_list (ptid))
- attach_thread (ptid, msg.th_p, &ti, 1);
+ attach_thread (ptid, msg.th_p, &ti, 1);
break;