This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [non-stop] 08/10 linux native support


A Wednesday 25 June 2008 23:12:20, Daniel Jacobowitz wrote:

> > That's right, the only thing we'll miss if we do that, is the
> > thread_db id of the thread in output like:
> >
> > [New Thread 0xf7e11b90 (LWP 26100)]
> >              ^^^^^^^^
> > And info threads:
> >
> >   2 Thread 0xf7e11b90 (LWP 26100)  (running)
> >              ^^^^^^^^
> >
> > Those will only show up on the next stop event (of any thread).
> > It may take a while, if all threads are running (unless we do
> > momentarily stop threads trick).
>
> Oh, dear.  Options:
>
>   - delay the notification until thread_db discovers the thread,
>     if libthread_db is already active
>
>   - display the notification without the thread ID; we'll have the
>     LWP ID and we could add the GDB thread number
>
>   - go with your code and fix broken situations as they arise
>
> I'm undecided.  Note that your code is unnecessarily quadratic, by the
> way.  It'll walk the entire thread list; we could just load the new
> thread since we know its LWP ID.  libthread_db may still do a walk in
> that case though...

I'd prefer the third, if it's still on the plate.
I've tried not calling into target_find_new_threads, but wasn't
convinced that the saving justifies the possible ugliness we
introduce.  The walk is most surelly still performed to map an
LWP to a user thread.

If it is justifiable, what is the prefered interface to call
into thread_db in this case?  A new target method?  The double
call I'm making into thread db, is because this may be the
earliest that we can get thread_db info on the main thread (the
parent of the first clone).  I couldn't find another place to
put it that didn't end up introducing more walks.

>
> > > SIGKILL should work even if the thread is stopped.
> >
> > I think I'll need a SIGCONT as well in that case.  For some
> > reason, I wasn't getting that to work all the times.  I'll
> > experiment some more.
>
> Kernels may vary in this regard.  Your code seems reasonable.
> PTRACE_KILL is supposed to be just SIGKILL + PTRACE_CONT, and SIGKILL
> is supposed to work even on stopped processes, but the details come
> and go... as you know, signal handling is a very touchy area and hard
> to write tests for.

I had second thoughts on the code.  It's racy.  If a running thread
happens to stop (and GDB doesn't know about it yet) just before
sending SIGKILL, I'd miss sending PTRACE_CONT in kernels that need
it.  I think it's just better to stop all threads before killing
them, and then killing them like we used to.

Obviously, the patch still needs the new thread management part
to be resolved, but otherwise, it should be done.

-- 
Pedro Alves
2008-07-02  Pedro Alves  <pedro@codesourcery.com>

	Non-stop linux native.

	* linux-fork.c (linux_fork_killall): Use SIGKILL instead of
	PTRACE_KILL.

	* linux-nat.c (linux_test_for_tracefork): Block events while we're
	here.
	(find_lwp_pid): Rename to...
	(linux_nat_find_lwp_pid): ... this.  Make public.  Update all
	callers.
	(get_pending_status): Implement non-stop mode.
	(linux_nat_detach): Stop threads before detaching.
	(linux_nat_resume): In non-stop mode, always resume only a single
	PTID.
	(linux_handle_extended_wait): On a clone event, add new lwp to
	GDB's thread table, and mark as running, executing and stopped
	appropriatelly.
	(linux_nat_filter_event): Don't assume there are other running
	threads when a thread exits.
	(linux_nat_wait): Mark the main thread as running and executing.
	In non-stop mode, don't stop all lwps.
	(linux_nat_kill): Stop lwps before killing them.
	(linux_nat_thread_alive): Use signal 0 to detect if a thread is
	alive.
	(send_sigint_callback): New.
	(linux_nat_stop): New.
	(linux_nat_add_target): Set to_stop to linux_nat_stop.

	* linux-nat.h (thread_db_attach_lwp): Declare.
	(linux_nat_find_lwp_pid): Declare.

	* linux-thread-db.c (thread_from_lwp, enable_thread_event)
	(check_event): Set proc_handle.pid to the stopped lwp.
	(thread_db_attach_lwp): New.
	(thread_db_find_new_threads): If current lwp is executing, don't
	try to read from it.

---
 gdb/linux-fork.c      |    4 
 gdb/linux-nat.c       |  258 ++++++++++++++++++++++++++++++++++++++++----------
 gdb/linux-nat.h       |    4 
 gdb/linux-thread-db.c |   50 +++++++++
 4 files changed, 268 insertions(+), 48 deletions(-)

Index: src/gdb/linux-fork.c
===================================================================
--- src.orig/gdb/linux-fork.c	2008-07-01 16:31:23.000000000 +0100
+++ src/gdb/linux-fork.c	2008-07-01 16:31:31.000000000 +0100
@@ -337,7 +337,9 @@ linux_fork_killall (void)
     {
       pid = PIDGET (fp->ptid);
       do {
-	ptrace (PT_KILL, pid, 0, 0);
+	/* Use SIGKILL instead of PTRACE_KILL because the former works even
+	   if the thread is running, while the later doesn't.  */
+	kill (pid, SIGKILL);
 	ret = waitpid (pid, &status, 0);
 	/* We might get a SIGCHLD instead of an exit status.  This is
 	 aggravated by the first kill above - a child has just
Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c	2008-07-01 16:31:29.000000000 +0100
+++ src/gdb/linux-nat.c	2008-07-01 20:18:03.000000000 +0100
@@ -285,6 +285,9 @@ static void linux_nat_async (void (*call
 static int linux_nat_async_mask (int mask);
 static int kill_lwp (int lwpid, int signo);
 
+static int send_sigint_callback (struct lwp_info *lp, void *data);
+static int stop_callback (struct lwp_info *lp, void *data);
+
 /* Captures the result of a successful waitpid call, along with the
    options used in that call.  */
 struct waitpid_result
@@ -487,6 +490,9 @@ linux_test_for_tracefork (int original_p
 {
   int child_pid, ret, status;
   long second_pid;
+  enum sigchld_state async_events_original_state;
+
+  async_events_original_state = linux_nat_async_events (sigchld_sync);
 
   linux_supports_tracefork_flag = 0;
   linux_supports_tracevforkdone_flag = 0;
@@ -517,6 +523,7 @@ linux_test_for_tracefork (int original_p
       if (ret != 0)
 	{
 	  warning (_("linux_test_for_tracefork: failed to kill child"));
+	  linux_nat_async_events (async_events_original_state);
 	  return;
 	}
 
@@ -527,6 +534,7 @@ linux_test_for_tracefork (int original_p
 	warning (_("linux_test_for_tracefork: unexpected wait status 0x%x from "
 		 "killed child"), status);
 
+      linux_nat_async_events (async_events_original_state);
       return;
     }
 
@@ -566,6 +574,8 @@ linux_test_for_tracefork (int original_p
   if (ret != 0)
     warning (_("linux_test_for_tracefork: failed to kill child"));
   my_waitpid (child_pid, &status, 0);
+
+  linux_nat_async_events (async_events_original_state);
 }
 
 /* Return non-zero iff we have tracefork functionality available.
@@ -985,8 +995,8 @@ delete_lwp (ptid_t ptid)
 /* Return a pointer to the structure describing the LWP corresponding
    to PID.  If no corresponding LWP could be found, return NULL.  */
 
-static struct lwp_info *
-find_lwp_pid (ptid_t ptid)
+struct lwp_info *
+linux_nat_find_lwp_pid (ptid_t ptid)
 {
   struct lwp_info *lp;
   int lwp;
@@ -1207,7 +1217,7 @@ lin_lwp_attach_lwp (ptid_t ptid)
 
   async_events_original_state = linux_nat_async_events (sigchld_sync);
 
-  lp = find_lwp_pid (ptid);
+  lp = linux_nat_find_lwp_pid (ptid);
 
   /* We assume that we're already attached to any LWP that has an id
      equal to the overall process id, and to any LWP that is already
@@ -1376,16 +1386,80 @@ get_pending_status (struct lwp_info *lp,
      events are always cached in waitpid_queue.  */
 
   *status = 0;
-  if (GET_LWP (lp->ptid) == GET_LWP (last_ptid))
+
+  if (non_stop)
     {
-      if (stop_signal != TARGET_SIGNAL_0
-	  && signal_pass_state (stop_signal))
-	*status = W_STOPCODE (target_signal_to_host (stop_signal));
+      enum target_signal signo = TARGET_SIGNAL_0;
+
+      if (is_executing (lp->ptid))
+	{
+	  /* If the core thought this lwp was executing --- e.g., the
+	     executing property hasn't been updated yet, but the
+	     thread has been stopped with a stop_callback /
+	     stop_wait_callback sequence (see linux_nat_detach for
+	     example) --- we can only have pending events in the local
+	     queue.  */
+	  if (queued_waitpid (GET_LWP (lp->ptid), status, __WALL) != -1)
+	    {
+	      if (WIFSTOPPED (status))
+		signo = target_signal_from_host (WSTOPSIG (status));
+
+	      /* If not stopped, then the lwp is gone, no use in
+		 resending a signal.  */
+	    }
+	}
+      else
+	{
+	  /* If the core knows the thread is not executing, then we
+	     have the last signal recorded in
+	     thread_info->stop_signal, unless this is inferior_ptid,
+	     in which case, it's in the global stop_signal, due to
+	     context switching.  */
+
+	  if (ptid_equal (lp->ptid, inferior_ptid))
+	    signo = stop_signal;
+	  else
+	    {
+	      struct thread_info *tp = find_thread_pid (lp->ptid);
+	      gdb_assert (tp);
+	      signo = tp->stop_signal;
+	    }
+	}
+
+      if (signo != TARGET_SIGNAL_0
+	  && !signal_pass_state (signo))
+	{
+	  if (debug_linux_nat)
+	    fprintf_unfiltered (gdb_stdlog, "\
+GPT: lwp %s had signal %s, but it is in no pass state\n",
+				target_pid_to_str (lp->ptid),
+				target_signal_to_string (signo));
+	}
+      else
+	{
+	  if (signo != TARGET_SIGNAL_0)
+	    *status = W_STOPCODE (target_signal_to_host (signo));
+
+	  if (debug_linux_nat)
+	    fprintf_unfiltered (gdb_stdlog,
+				"GPT: lwp %s as pending signal %s\n",
+				target_pid_to_str (lp->ptid),
+				target_signal_to_string (signo));
+	}
     }
-  else if (target_can_async_p ())
-    queued_waitpid (GET_LWP (lp->ptid), status, __WALL);
   else
-    *status = lp->status;
+    {
+      if (GET_LWP (lp->ptid) == GET_LWP (last_ptid))
+	{
+	  if (stop_signal != TARGET_SIGNAL_0
+	      && signal_pass_state (stop_signal))
+	    *status = W_STOPCODE (target_signal_to_host (stop_signal));
+	}
+      else if (target_can_async_p ())
+	queued_waitpid (GET_LWP (lp->ptid), status, __WALL);
+      else
+	*status = lp->status;
+    }
 
   return 0;
 }
@@ -1449,6 +1523,13 @@ linux_nat_detach (char *args, int from_t
   if (target_can_async_p ())
     linux_nat_async (NULL, 0);
 
+  /* Stop all threads before detaching.  ptrace requires that the
+     thread is stopped to sucessfully detach.  */
+  iterate_over_lwps (stop_callback, NULL);
+  /* ... and wait until all of them have reported back that
+     they're no longer running.  */
+  iterate_over_lwps (stop_wait_callback, NULL);
+
   iterate_over_lwps (detach_callback, NULL);
 
   /* Only the initial process should be left right now.  */
@@ -1538,19 +1619,27 @@ linux_nat_resume (ptid_t ptid, int step,
   /* A specific PTID means `step only this process id'.  */
   resume_all = (PIDGET (ptid) == -1);
 
-  if (resume_all)
-    iterate_over_lwps (resume_set_callback, NULL);
-  else
-    iterate_over_lwps (resume_clear_callback, NULL);
+  if (non_stop && resume_all)
+    internal_error (__FILE__, __LINE__,
+		    "can't resume all in non-stop mode");
+
+  if (!non_stop)
+    {
+      if (resume_all)
+	iterate_over_lwps (resume_set_callback, NULL);
+      else
+	iterate_over_lwps (resume_clear_callback, NULL);
+    }
 
   /* If PID is -1, it's the current inferior that should be
      handled specially.  */
   if (PIDGET (ptid) == -1)
     ptid = inferior_ptid;
 
-  lp = find_lwp_pid (ptid);
+  lp = linux_nat_find_lwp_pid (ptid);
   gdb_assert (lp != NULL);
 
+  /* Convert to something the lower layer understands.  */
   ptid = pid_to_ptid (GET_LWP (lp->ptid));
 
   /* Remember if we're stepping.  */
@@ -1701,6 +1790,8 @@ linux_handle_extended_wait (struct lwp_i
 	ourstatus->kind = TARGET_WAITKIND_VFORKED;
       else
 	{
+	  struct cleanup *old_chain;
+
 	  ourstatus->kind = TARGET_WAITKIND_IGNORE;
 	  new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (inferior_ptid)));
 	  new_lp->cloned = 1;
@@ -1720,20 +1811,54 @@ linux_handle_extended_wait (struct lwp_i
 	  else
 	    status = 0;
 
+#if 0
+	  /* Make thread_db aware of this thread.  We do this this
+	     early, so in non-stop mode, threads show up as they're
+	     created, instead of on next stop, and so that they have
+	     the correct running state.  thread_db_find_new_threads
+	     needs a stopped inferior_ptid --- since we know LP is
+	     stopped, use it this time.  */
+	  old_chain = save_inferior_ptid ();
+	  inferior_ptid = lp->ptid;
+	  lp->stopped = 1;
+	  target_find_new_threads ();
+	  do_cleanups (old_chain);
+	  if (!in_thread_list (new_lp->ptid))
+#else
+	  /* "Attach"ing to the parent forces the thread_db target to
+	     build its private data structures for the parent, which
+	     may have not had them setup yet.  */
+	  thread_db_attach_lwp (lp->ptid);
+	  /* Do the same to the child, which, if thread_db is active,
+	     adds the child to GDB's thread list.  */
+	  if (!thread_db_attach_lwp (new_lp->ptid))
+#endif
+	    {
+	      /* We're not using thread_db.  Attach and add it to
+		 GDB's list.  */
+	      lin_lwp_attach_lwp (new_lp->ptid);
+	      target_post_attach (GET_LWP (new_lp->ptid));
+	      add_thread (new_lp->ptid);
+	    }
+
 	  if (stopping)
 	    new_lp->stopped = 1;
 	  else
 	    {
+	      new_lp->stopped = 0;
 	      new_lp->resumed = 1;
 	      ptrace (PTRACE_CONT,
 		      PIDGET (lp->waitstatus.value.related_pid), 0,
 		      status ? WSTOPSIG (status) : 0);
+	      set_running (new_lp->ptid, 1);
+	      set_executing (new_lp->ptid, 1);
 	    }
 
 	  if (debug_linux_nat)
 	    fprintf_unfiltered (gdb_stdlog,
 				"LHEW: Got clone event from LWP %ld, resuming\n",
 				GET_LWP (lp->ptid));
+	  lp->stopped = 0;
 	  ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
 
 	  return 1;
@@ -2358,7 +2483,7 @@ linux_nat_filter_event (int lwpid, int s
 {
   struct lwp_info *lp;
 
-  lp = find_lwp_pid (pid_to_ptid (lwpid));
+  lp = linux_nat_find_lwp_pid (pid_to_ptid (lwpid));
 
   /* Check for stop events reported by a process we didn't already
      know about - anything not already in our LWP list.
@@ -2453,13 +2578,7 @@ linux_nat_filter_event (int lwpid, int s
 	 not the end of the debugged application and should be
 	 ignored.  */
       if (num_lwps > 0)
-	{
-	  /* Make sure there is at least one thread running.  */
-	  gdb_assert (iterate_over_lwps (running_callback, NULL));
-
-	  /* Discard the event.  */
-	  return NULL;
-	}
+	return NULL;
     }
 
   /* Check if the current LWP has previously exited.  In the nptl
@@ -2589,6 +2708,8 @@ linux_nat_wait (ptid_t ptid, struct targ
       lp->resumed = 1;
       /* Add the main thread to GDB's thread list.  */
       add_thread_silent (lp->ptid);
+      set_running (lp->ptid, 1);
+      set_executing (lp->ptid, 1);
     }
 
   sigemptyset (&flush_mask);
@@ -2635,7 +2756,7 @@ retry:
 			    target_pid_to_str (ptid));
 
       /* We have a specific LWP to check.  */
-      lp = find_lwp_pid (ptid);
+      lp = linux_nat_find_lwp_pid (ptid);
       gdb_assert (lp);
       status = lp->status;
       lp->status = 0;
@@ -2816,19 +2937,23 @@ retry:
     fprintf_unfiltered (gdb_stdlog, "LLW: Candidate event %s in %s.\n",
 			status_to_str (status), target_pid_to_str (lp->ptid));
 
-  /* Now stop all other LWP's ...  */
-  iterate_over_lwps (stop_callback, NULL);
+  if (!non_stop)
+    {
+      /* Now stop all other LWP's ...  */
+      iterate_over_lwps (stop_callback, NULL);
 
-  /* ... and wait until all of them have reported back that they're no
-     longer running.  */
-  iterate_over_lwps (stop_wait_callback, &flush_mask);
-  iterate_over_lwps (flush_callback, &flush_mask);
-
-  /* If we're not waiting for a specific LWP, choose an event LWP from
-     among those that have had events.  Giving equal priority to all
-     LWPs that have had events helps prevent starvation.  */
-  if (pid == -1)
-    select_event_lwp (&lp, &status);
+      /* ... and wait until all of them have reported back that
+	 they're no longer running.  */
+      iterate_over_lwps (stop_wait_callback, &flush_mask);
+      iterate_over_lwps (flush_callback, &flush_mask);
+
+      /* If we're not waiting for a specific LWP, choose an event LWP
+	 from among those that have had events.  Giving equal priority
+	 to all LWPs that have had events helps prevent
+	 starvation.  */
+      if (pid == -1)
+	select_event_lwp (&lp, &status);
+    }
 
   /* Now that we've selected our final event LWP, cancel any
      breakpoints in other LWPs that have hit a GDB breakpoint.  See
@@ -2960,6 +3085,13 @@ linux_nat_kill (void)
     }
   else
     {
+      /* Stop all threads before killing them, since ptrace requires
+	 that the thread is stopped to sucessfully PTRACE_KILL.  */
+      iterate_over_lwps (stop_callback, NULL);
+      /* ... and wait until all of them have reported back that
+	 they're no longer running.  */
+      iterate_over_lwps (stop_wait_callback, NULL);
+
       /* Kill all LWP's ...  */
       iterate_over_lwps (kill_callback, NULL);
 
@@ -3012,22 +3144,22 @@ linux_nat_xfer_partial (struct target_op
 static int
 linux_nat_thread_alive (ptid_t ptid)
 {
+  int err;
+
   gdb_assert (is_lwp (ptid));
 
-  errno = 0;
-  ptrace (PTRACE_PEEKUSER, GET_LWP (ptid), 0, 0);
+  /* Send signal 0 instead of anything ptrace, because ptracing a
+     running thread errors out claiming that the thread doesn't
+     exist.  */
+  err = kill_lwp (GET_LWP (ptid), 0);
+
   if (debug_linux_nat)
     fprintf_unfiltered (gdb_stdlog,
-			"LLTA: PTRACE_PEEKUSER %s, 0, 0 (%s)\n",
+			"LLTA: KILL(SIG0) %s (%s)\n",
 			target_pid_to_str (ptid),
-			errno ? safe_strerror (errno) : "OK");
+			err ? safe_strerror (err) : "OK");
 
-  /* Not every Linux kernel implements PTRACE_PEEKUSER.  But we can
-     handle that case gracefully since ptrace will first do a lookup
-     for the process based upon the passed-in pid.  If that fails we
-     will get either -ESRCH or -EPERM, otherwise the child exists and
-     is alive.  */
-  if (errno == ESRCH || errno == EPERM)
+  if (err != 0)
     return 0;
 
   return 1;
@@ -4229,6 +4361,35 @@ linux_nat_set_async_mode (int on)
   linux_nat_async_enabled = on;
 }
 
+static int
+send_sigint_callback (struct lwp_info *lp, void *data)
+{
+  /* Use is_running instead of !lp->stopped, because the lwp may be
+     stopped due to an internal event, and we want to interrupt it in
+     that case too.  What we want is to check if the thread is stopped
+     from the point of view of the user.  */
+  if (is_running (lp->ptid))
+    kill_lwp (GET_LWP (lp->ptid), SIGINT);
+  return 0;
+}
+
+static void
+linux_nat_stop (ptid_t ptid)
+{
+  if (non_stop)
+    {
+      if (ptid_equal (ptid, minus_one_ptid))
+	iterate_over_lwps (send_sigint_callback, &ptid);
+      else
+	{
+	  struct lwp_info *lp = linux_nat_find_lwp_pid (ptid);
+	  send_sigint_callback (lp, NULL);
+	}
+    }
+  else
+    linux_ops->to_stop (ptid);
+}
+
 void
 linux_nat_add_target (struct target_ops *t)
 {
@@ -4259,6 +4420,9 @@ linux_nat_add_target (struct target_ops 
   t->to_terminal_inferior = linux_nat_terminal_inferior;
   t->to_terminal_ours = linux_nat_terminal_ours;
 
+  /* Methods for non-stop support.  */
+  t->to_stop = linux_nat_stop;
+
   /* We don't change the stratum; this target will sit at
      process_stratum and thread_db will set at thread_stratum.  This
      is a little strange, since this is a multi-threaded-capable
@@ -4286,7 +4450,7 @@ linux_nat_set_new_thread (struct target_
 struct siginfo *
 linux_nat_get_siginfo (ptid_t ptid)
 {
-  struct lwp_info *lp = find_lwp_pid (ptid);
+  struct lwp_info *lp = linux_nat_find_lwp_pid (ptid);
 
   gdb_assert (lp != NULL);
 
Index: src/gdb/linux-nat.h
===================================================================
--- src.orig/gdb/linux-nat.h	2008-07-01 16:31:23.000000000 +0100
+++ src/gdb/linux-nat.h	2008-07-01 16:31:31.000000000 +0100
@@ -94,6 +94,8 @@ void check_for_thread_db (void);
 /* Tell the thread_db layer what native target operations to use.  */
 void thread_db_init (struct target_ops *);
 
+int thread_db_attach_lwp (ptid_t ptid);
+
 /* Find process PID's pending signal set from /proc/pid/status.  */
 void linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigset_t *ignored);
 
@@ -107,6 +109,8 @@ struct lwp_info *iterate_over_lwps (int 
 						     void *), 
 				    void *data);
 
+struct lwp_info *linux_nat_find_lwp_pid (ptid_t ptid);
+
 /* Create a prototype generic GNU/Linux target.  The client can
    override it with local methods.  */
 struct target_ops * linux_target (void);
Index: src/gdb/linux-thread-db.c
===================================================================
--- src.orig/gdb/linux-thread-db.c	2008-07-01 16:31:23.000000000 +0100
+++ src/gdb/linux-thread-db.c	2008-07-01 20:17:54.000000000 +0100
@@ -308,6 +308,8 @@ thread_from_lwp (ptid_t ptid)
      LWP.  */
   gdb_assert (GET_LWP (ptid) != 0);
 
+  /* Access an lwp we know is stopped.  */
+  proc_handle.pid = GET_LWP (ptid);
   err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th);
   if (err != TD_OK)
     error (_("Cannot find user-level thread for LWP %ld: %s"),
@@ -332,6 +334,41 @@ thread_from_lwp (ptid_t ptid)
 }
 
 
+/* Attach to lwp PTID, doing whatever else is required to have this
+   LWP under the debugger's control --- e.g., enabling event
+   reporting.  Returns true on success.  */
+int
+thread_db_attach_lwp (ptid_t ptid)
+{
+  td_thrhandle_t th;
+  td_thrinfo_t ti;
+  td_err_e err;
+
+  if (!using_thread_db)
+    return 0;
+
+  /* This ptid comes from linux-nat.c, which should always fill in the
+     LWP.  */
+  gdb_assert (GET_LWP (ptid) != 0);
+
+  /* Access an lwp we know is stopped.  */
+  proc_handle.pid = GET_LWP (ptid);
+  err = td_ta_map_lwp2thr_p (thread_agent, GET_LWP (ptid), &th);
+  if (err != TD_OK)
+    /* Cannot find user-level thread.  */
+    return 0;
+
+  err = td_thr_get_info_p (&th, &ti);
+  if (err != TD_OK)
+    {
+      warning (_("Cannot get thread info: %s"), thread_db_err_str (err));
+      return 0;
+    }
+
+  attach_thread (ptid, &th, &ti);
+  return 1;
+}
+
 void
 thread_db_init (struct target_ops *target)
 {
@@ -418,6 +455,9 @@ enable_thread_event (td_thragent_t *thre
   td_notify_t notify;
   td_err_e err;
 
+  /* Access an lwp we know is stopped.  */
+  proc_handle.pid = GET_LWP (inferior_ptid);
+
   /* Get the breakpoint address for thread EVENT.  */
   err = td_ta_event_addr_p (thread_agent, event, &notify);
   if (err != TD_OK)
@@ -761,6 +801,9 @@ check_event (ptid_t ptid)
   if (stop_pc != td_create_bp_addr && stop_pc != td_death_bp_addr)
     return;
 
+  /* Access an lwp we know is stopped.  */
+  proc_handle.pid = GET_LWP (ptid);
+
   /* If we are at a create breakpoint, we do not know what new lwp
      was created and cannot specifically locate the event message for it.
      We have to call td_ta_event_getmsg() to get
@@ -955,7 +998,14 @@ static void
 thread_db_find_new_threads (void)
 {
   td_err_e err;
+  struct lwp_info *lp = linux_nat_find_lwp_pid (inferior_ptid);
+
+  if (!lp || !lp->stopped)
+    /* In linux, we can only read memory through a stopped lwp.  */
+    return;
 
+  /* Access an lwp we know is stopped.  */
+  proc_handle.pid = GET_LWP (inferior_ptid);
   /* Iterate over all user-space threads to discover new threads.  */
   err = td_ta_thr_iter_p (thread_agent, find_new_threads_callback, NULL,
 			  TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]