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]

[PATCH, gdbserver] Scan for existing threads during attachment on Linux


Hi,

This patch deals with GDBServer's behavior on Linux only.

Currently, when told to attach to a PID, GDBServer does so without checking for other threads that may already exist in the thread group of which that PID is part of. As a result, it leaves threads running in the background until GDB connects to it and allows the use of thread_db to list/attach to the threads.

if GDB takes too long to connect to GDBServer, those existing threads that were not detected by GDBServer may end, and the user loses the opportunity to inspect them.

The patch changes the behavior of the linux_attach (...) function so it checks if the PID that we should attach to is the thread group leader. If so, we scan /proc/<pid>/task for existing threads and attach to them as well.

In that case, when GDB connects to GDBServer, the process will still hold all of its threads.

If the user asks GDBServer to attach to a PID that is not the thread group leader, that means we will attach to a single thread. The patch doesn't change this case, but is this really a useful use case? Or should GDBServer look for the PID's thread group leader and attach to all the threads that are part of that group?

If attaching to a single thread is useful, this patch should be OK. If not, i can change the patch to change that scenario.

Ok?

Regards,
Luis
2011-05-20  Luis Machado  <lgustavo@codesourcery.com>

	* linux-low.c (set_resume_kind_stop): New function.
	(linux_attach): Scan for existing threads when attaching to a
	process.

--- .pc/stop_threads.diff/gdb/gdbserver/linux-low.c	2011-05-20 10:37:41.915272001 -0300
+++ gdb/gdbserver/linux-low.c	2011-05-20 14:25:59.019272001 -0300
@@ -561,6 +561,16 @@ linux_create_inferior (char *program, ch
   return pid;
 }
 
+/* Set a threads's last_resume_kind to RESUME_STOP.  */
+
+static void
+set_resume_kind_stop (struct inferior_list_entry *entry)
+{
+  struct thread_info *thread= (struct thread_info *) entry;
+
+  thread->last_resume_kind = resume_stop;
+}
+
 /* Attach to an inferior process.  */
 
 static void
@@ -646,22 +656,100 @@ linux_attach_lwp (unsigned long lwpid)
   linux_attach_lwp_1 (lwpid, 0);
 }
 
+/* Attach to PID.  If PID is the tgdi, attach to it and stop
+   all of its threads.  */
+
 int
 linux_attach (unsigned long pid)
 {
+  DIR *dir;
+  char pathname[128];
+  int is_tgid = 0;
+  FILE *fd;
+
+  /* Attach to PID.  We will check for other threads
+     soon.  */
   linux_attach_lwp_1 (pid, 1);
-  linux_add_process (pid, 1);
 
-  if (!non_stop)
+  /* Find out what is the tgid of this lwp.  */
+  sprintf (pathname, "/proc/%ld/stat", pid);
+
+  fd = fopen (pathname, "r");
+
+  if (fd != NULL)
     {
-      struct thread_info *thread;
+      int proc_id, ppid, pgrp;
+      char comm[NAME_MAX + 1], state;
 
-     /* Don't ignore the initial SIGSTOP if we just attached to this
-	process.  It will be collected by wait shortly.  */
-      thread = find_thread_ptid (ptid_build (pid, pid, 0));
-      thread->last_resume_kind = resume_stop;
+      fscanf (fd, "%d %s %c %d %d", &proc_id, comm, &state, &ppid, &pgrp);
+      fclose (fd);
+
+      if (pgrp == pid)
+	is_tgid = 1;
+    }
+  else
+    {
+      fprintf (stderr, "Could not open /proc/%ld/stat.\n", pid);
+      fflush (stderr);
     }
 
+  sprintf (pathname, "/proc/%ld/task", pid);
+
+  dir = opendir (pathname);
+
+  if (!dir)
+    {
+      fprintf (stderr, "Could not open /proc/%ld/task.\n", pid);
+      fflush (stderr);
+    }
+  else if (is_tgid)
+    {
+      /* At this point we attached to the tgid.  Scan the task for
+	 existing threads.  */
+      unsigned long lwp;
+      int new_threads_found;
+      int iterations = 0;
+      struct dirent *dp;
+
+      while (iterations < 2)
+	{
+	  new_threads_found = 0;
+	  /* Add all the other threads.  While we go through the
+	     threads, new threads may be spawned.  Cycle through
+	     the list of threads until we have done two iterations without
+	     finding new threads.  */
+	  while ((dp = readdir (dir)) != NULL)
+	    {
+	      /* Fetch one lwp.  */
+	      lwp = strtoul (dp->d_name, NULL, 10);
+
+	      /* Is this a new thread?  */
+	      if (lwp && find_thread_ptid (ptid_build (pid, lwp, 0)) == NULL)
+		{
+		  linux_attach_lwp_1 (lwp, 0);
+		  new_threads_found++;
+
+		  if (debug_threads)
+		    fprintf (stderr, "Found and attached to new lwp %ld\n", lwp);
+		}
+	    }
+
+	  if (!new_threads_found)
+	    iterations++;
+	  else
+	    iterations = 0;
+
+	  rewinddir (dir);
+	}
+      closedir (dir);
+    }
+
+  linux_add_process (pid, 1);
+
+  /* Mark the threads as stopped.  */
+  if (!non_stop)
+    for_each_inferior (&all_threads, set_resume_kind_stop);
+
   return 0;
 }
 

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