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]

"info threads" -> thread_db listing -> new thread -> PTRACE_ATTACH -> error, because we're already auto attached to clone lwps.


With a program like:

volatile int count;
static int threads = 1000;

static void *
thread_function0 (void *arg)
{
  pthread_t thread;

  count++;
  if (count < threads)
    pthread_create (&thread,
                    NULL,
                    thread_function0,
                    NULL);

  pthread_exit (NULL);  << break here
}

int
main (int argc, char **argv)
{
  pthread_t thread;

  pthread_create (&thread,
                  NULL,
                  thread_function0,
                  NULL);

  while (1)
    {
      usleep (1);
    }
}

Run under gdb in non-stop mode, with a breakpoint at
the "break here" line, that just lists all threads,
and immediately re-resumes the thread, like:

(gdb) b <at break here>
(gdb) commands
> info threads
> c&
> end
(gdb) c -a&

Results in a bunch of:

Breakpoint 1, thread_function0 (arg=0x0) at threads_spawner.c:44
44        pthread_exit (NULL);
[New Thread 0x7fff9dd60700 (LWP 7554)]

and:

[Thread 0x7fffcc5bd700 (LWP 10504) exited]

as expected, but every so often, we see:

warning: Can't attach LWP 7341: Operation not permitted
Cannot find new threads: debugger service failed

This is an error thrown from "info threads".  This error
cancels the breakpoint command list, so c& is not executed
and the thread remains stopped.  After a bit, we end up
with something like:

(gdb) info threads
  Id   Target Id         Frame 
  99   Thread 0x7fffc6db2700 (LWP 10515) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  98   Thread 0x7fffc75b3700 (LWP 10514) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  97   Thread 0x7fffc7db4700 (LWP 10513) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  96   Thread 0x7fffc85b5700 (LWP 10512) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  95   Thread 0x7fffc8db6700 (LWP 10511) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  94   Thread 0x7fffc95b7700 (LWP 10510) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  93   Thread 0x7fffc9db8700 (LWP 10509) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  82   Thread 0x7fffcf5c3700 (LWP 10498) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  81   Thread 0x7fffcfdc4700 (LWP 10497) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  80   Thread 0x7fffd05c5700 (LWP 10496) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  79   Thread 0x7fffd0dc6700 (LWP 10495) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  78   Thread 0x7fffd15c7700 (LWP 10494) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  75   Thread 0x7fffd2dca700 (LWP 10491) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  70   Thread 0x7fffd55cf700 (LWP 10486) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  69   Thread 0x7fffd5dd0700 (LWP 10485) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  68   Thread 0x7fffd65d1700 (LWP 10484) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  67   Thread 0x7fffd6dd2700 (LWP 10483) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  66   Thread 0x7fffd75d3700 (LWP 10482) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  47   Thread 0x7fffe0de6700 (LWP 10463) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  46   Thread 0x7fffe15e7700 (LWP 10462) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  44   Thread 0x7fffe25e9700 (LWP 10460) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  43   Thread 0x7fffe2dea700 (LWP 10459) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  41   Thread 0x7fffe3dec700 (LWP 10457) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  40   Thread 0x7fffe45ed700 (LWP 10456) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  37   Thread 0x7fffe5df0700 (LWP 10453) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  36   Thread 0x7fffe65f1700 (LWP 10452) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  23   Thread 0x7fffecdfe700 (LWP 10439) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  22   Thread 0x7fffed5ff700 (LWP 10438) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  20   Thread 0x7fffee601700 (LWP 10436) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  17   Thread 0x7fffefe04700 (LWP 10433) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  16   Thread 0x7ffff0605700 (LWP 10432) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  14   Thread 0x7ffff1607700 (LWP 10430) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  13   Thread 0x7ffff1e08700 (LWP 10429) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  11   Thread 0x7ffff2e0a700 (LWP 10427) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  10   Thread 0x7ffff360b700 (LWP 10426) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  9    Thread 0x7ffff3e0c700 (LWP 10425) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  8    Thread 0x7ffff460d700 (LWP 10424) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  7    Thread 0x7ffff4e0e700 (LWP 10423) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  6    Thread 0x7ffff560f700 (LWP 10422) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  4    Thread 0x7ffff6827700 (LWP 10420) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
  3    Thread 0x7ffff7028700 (LWP 10419) "threads_spawner" thread_function0 (arg=0x0) at threads_spawner.c:44
* 1    Thread 0x7ffff7fcd720 (LWP 10409) "threads_spawner" (running)
(gdb)

Instead of all 1000 threads spawning and exiting (except the main thread).


Let's look again at the warning:

> warning: Can't attach LWP 7341: Operation not permitted
> Cannot find new threads: debugger service failed

On linux/ptrace, we need to attach to every thread
in the inferior individually, _except_ that with nptl,
clones/forks/vforks are already ptraced/auto-attached if the parent
was ptraced.

What is happening here, is that at "info threads" time, the new
thread (LWP 7341) is already listed in pthread/thread_db's internal
thread list, but linux-nat.c hasn't yet had a chance of processing
the PTRACE_EVENT_CLONE on the thread that gave birth to 7341.

Since LWP 7341 is found in the pthread/thread_db thread list,
but it is not in GDB's own thread list, linux-thread-db.c thinks this
must be a thread we haven't attached to yet, so proceeds to attach
to it (linux-thread-db.c:attach_thread -> lin_lwp_attach_lwp -> PTRACE_ATTACH).
Since we are already auto-attached to the LWP (it's a clone), PTRACE_ATTACH
fails.

This patch deals with the issue, by having lin_lwp_attach_lwp
check for this scenario when PTRACE_ATTACH fails.

Tested on x86_64-linux and applied.

-- 
Pedro Alves

2011-09-02  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* linux-nat.c (in_pid_list_p): New.
	(linux_record_stopped_pid): Delete.
	(lin_lwp_attach_lwp): Check if PTRACE_ATTACH failed because we're
	already attached to the LWP.  Return an indication if so.
	(linux_nat_filter_event): Adjust.
	* linux-thread-db.c (attach_thread): Handle lin_lwp_attach_lwp
	returning an indication to ignore this thread.

---
 gdb/linux-nat.c       |   68 +++++++++++++++++++++++++++++++++++++++++---------
 gdb/linux-thread-db.c |   22 +++++++++++++---
 2 files changed, 76 insertions(+), 14 deletions(-)

Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c	2011-09-02 20:56:04.379457441 +0100
+++ src/gdb/linux-nat.c	2011-09-02 21:55:16.469458062 +0100
@@ -331,6 +331,17 @@ add_to_pid_list (struct simple_pid_list
 }
 
 static int
+in_pid_list_p (struct simple_pid_list *list, int pid)
+{
+  struct simple_pid_list *p;
+
+  for (p = list; p != NULL; p = p->next)
+    if (p->pid == pid)
+      return 1;
+  return 0;
+}
+
+static int
 pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
 {
   struct simple_pid_list **p;
@@ -348,12 +359,6 @@ pull_pid_from_list (struct simple_pid_li
   return 0;
 }
 
-static void
-linux_record_stopped_pid (int pid, int status)
-{
-  add_to_pid_list (&stopped_pids, pid, status);
-}
-
 
 /* A helper function for linux_test_for_tracefork, called after fork ().  */
 
@@ -1386,20 +1391,25 @@ linux_nat_post_attach_wait (ptid_t ptid,
   return status;
 }
 
-/* Attach to the LWP specified by PID.  Return 0 if successful or -1
-   if the new LWP could not be attached.  */
+/* Attach to the LWP specified by PID.  Return 0 if successful, -1 if
+   the new LWP could not be attached, or 1 if we're already auto
+   attached to this thread, but haven't processed the
+   PTRACE_EVENT_CLONE event of its parent thread, so we just ignore
+   its existance, without considering it an error.  */
 
 int
 lin_lwp_attach_lwp (ptid_t ptid)
 {
   struct lwp_info *lp;
   sigset_t prev_mask;
+  int lwpid;
 
   gdb_assert (is_lwp (ptid));
 
   block_child_signals (&prev_mask);
 
   lp = find_lwp_pid (ptid);
+  lwpid = GET_LWP (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
@@ -1407,12 +1417,48 @@ lin_lwp_attach_lwp (ptid_t ptid)
      and we've had PID wraparound since we last tried to stop all threads,
      this assumption might be wrong; fortunately, this is very unlikely
      to happen.  */
-  if (GET_LWP (ptid) != GET_PID (ptid) && lp == NULL)
+  if (lwpid != GET_PID (ptid) && lp == NULL)
     {
       int status, cloned = 0, signalled = 0;
 
-      if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
+      if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) < 0)
 	{
+	  if (linux_supports_tracefork_flag)
+	    {
+	      /* If we haven't stopped all threads when we get here,
+		 we may have seen a thread listed in thread_db's list,
+		 but not processed the PTRACE_EVENT_CLONE yet.  If
+		 that's the case, ignore this new thread, and let
+		 normal event handling discover it later.  */
+	      if (in_pid_list_p (stopped_pids, lwpid))
+		{
+		  /* We've already seen this thread stop, but we
+		     haven't seen the PTRACE_EVENT_CLONE extended
+		     event yet.  */
+		  restore_child_signals_mask (&prev_mask);
+		  return 0;
+		}
+	      else
+		{
+		  int new_pid;
+		  int status;
+
+		  /* See if we've got a stop for this new child
+		     pending.  If so, we're already attached.  */
+		  new_pid = my_waitpid (lwpid, &status, WNOHANG);
+		  if (new_pid == -1 && errno == ECHILD)
+		    new_pid = my_waitpid (lwpid, &status, __WCLONE | WNOHANG);
+		  if (new_pid != -1)
+		    {
+		      if (WIFSTOPPED (status))
+			add_to_pid_list (&stopped_pids, lwpid, status);
+
+		      restore_child_signals_mask (&prev_mask);
+		      return 1;
+		    }
+		}
+	    }
+
 	  /* If we fail to attach to the thread, issue a warning,
 	     but continue.  One way this can happen is if thread
 	     creation is interrupted; as of Linux kernel 2.6.19, a
@@ -3084,7 +3130,7 @@ linux_nat_filter_event (int lwpid, int s
      from waitpid before or after the event is.  */
   if (WIFSTOPPED (status) && !lp)
     {
-      linux_record_stopped_pid (lwpid, status);
+      add_to_pid_list (&stopped_pids, lwpid, status);
       return NULL;
     }
 
Index: src/gdb/linux-thread-db.c
===================================================================
--- src.orig/gdb/linux-thread-db.c	2011-09-02 20:56:04.379457441 +0100
+++ src/gdb/linux-thread-db.c	2011-09-02 21:35:10.289457851 +0100
@@ -1140,9 +1140,25 @@ attach_thread (ptid_t ptid, const td_thr
 
   /* Under GNU/Linux, we have to attach to each and every thread.  */
   if (target_has_execution
-      && tp == NULL
-      && lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid))) < 0)
-    return 0;
+      && tp == NULL)
+    {
+      int res;
+
+      res = lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)));
+      if (res < 0)
+	{
+	  /* Error, stop iterating.  */
+	  return 0;
+	}
+      else if (res > 0)
+	{
+	  /* Pretend this thread doesn't exist yet, and keep
+	     iterating.  */
+	  return 1;
+	}
+
+      /* Otherwise, we sucessfully attached to the thread.  */
+    }
 
   /* Construct the thread's private data.  */
   private = xmalloc (sizeof (struct private_thread_info));


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