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: don't assume the first signal new clone/fork/vfork children report is SIGSTOP.


I'm applying this.

If we had seen a new child stop before seeing the corresponding
extended wait status (PTRACE_EVENT_CLONE, etc.) in the parent, then
the current code that handles the extended status wrongly assumes the
child must have stopped for the SIGSTOP.  That's not always true.  The
new child may well dequeue some other pending signal, and so we may
see that other signal first (w/ the STOPSTOP remaining pending).
We're already handling that case when pull_pid_from_list returns
false, and we block in waitpid, and that waitpid returns something not
SIGSTOP:

      /* Normally we will get the pending SIGSTOP.  But in some cases
	 we might get another signal delivered to the group first.
	 If we do get another signal, be sure not to lose it.  */
      if (WSTOPSIG (status) == SIGSTOP)
	{
	  if (stopping_threads)
	    new_lwp->stop_pc = get_stop_pc (new_lwp);
	  else
	    linux_resume_one_lwp (new_lwp, 0, 0, NULL);
	}
      else
	{
	  new_lwp->stop_expected = 1;
	  ^^^^^^^^^^^^^^^^^^^^^^^^^^^

But we miss recording the status we saw the child stop with, when we
see the child stop before we see the parent's extended status.  GDB
handles this correctly.  This fixes it for GDBserver.

Tested on x86_64 Fedora 16, extended-remote board.

2012-03-01  Pedro Alves  <palves@redhat.com>

	* inferiors.c (add_pid_to_list, pull_pid_from_list): Delete.
	* linux-low.c (struct simple_pid_list): New.
	(stopped_pids): New a struct simple_pid_list pointer.
	(add_to_pid_list, pull_pid_from_list): New.
	(handle_extended_wait): Don't assume the first signal new children
	report is SIGSTOP.  Adjust call to pull_pid_from_list.
	(linux_wait_for_lwp): Adjust.
---
 0 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index ba5cb10..2b9169a 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -239,35 +239,6 @@ clear_inferiors (void)
   current_inferior = NULL;
 }
 
-/* Two utility functions for a truly degenerate inferior_list: a simple
-   PID listing.  */
-
-void
-add_pid_to_list (struct inferior_list *list, unsigned long pid)
-{
-  struct inferior_list_entry *new_entry;
-
-  new_entry = xmalloc (sizeof (struct inferior_list_entry));
-  new_entry->id = pid_to_ptid (pid);
-  add_inferior_to_list (list, new_entry);
-}
-
-int
-pull_pid_from_list (struct inferior_list *list, unsigned long pid)
-{
-  struct inferior_list_entry *new_entry;
-
-  new_entry = find_inferior_id (list, pid_to_ptid (pid));
-  if (new_entry == NULL)
-    return 0;
-  else
-    {
-      remove_inferior (list, new_entry);
-      free (new_entry);
-      return 1;
-    }
-}
-
 struct process_info *
 add_process (int pid, int attached)
 {
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 17d4694..fb41b68 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -92,11 +92,54 @@
 
 struct inferior_list all_lwps;
 
-/* A list of all unknown processes which receive stop signals.  Some other
-   process will presumably claim each of these as forked children
-   momentarily.  */
+/* A list of all unknown processes which receive stop signals.  Some
+   other process will presumably claim each of these as forked
+   children momentarily.  */
 
-struct inferior_list stopped_pids;
+struct simple_pid_list
+{
+  /* The process ID.  */
+  int pid;
+
+  /* The status as reported by waitpid.  */
+  int status;
+
+  /* Next in chain.  */
+  struct simple_pid_list *next;
+};
+struct simple_pid_list *stopped_pids;
+
+/* Trivial list manipulation functions to keep track of a list of new
+   stopped processes.  */
+
+static void
+add_to_pid_list (struct simple_pid_list **listp, int pid, int status)
+{
+  struct simple_pid_list *new_pid = xmalloc (sizeof (struct simple_pid_list));
+
+  new_pid->pid = pid;
+  new_pid->status = status;
+  new_pid->next = *listp;
+  *listp = new_pid;
+}
+
+static int
+pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
+{
+  struct simple_pid_list **p;
+
+  for (p = listp; *p != NULL; p = &(*p)->next)
+    if ((*p)->pid == pid)
+      {
+	struct simple_pid_list *next = (*p)->next;
+
+	*statusp = (*p)->status;
+	xfree (*p);
+	*p = next;
+	return 1;
+      }
+  return 0;
+}
 
 /* FIXME this is a bit of a hack, and could be removed.  */
 int stopping_threads;
@@ -353,12 +396,12 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
     {
       ptid_t ptid;
       unsigned long new_pid;
-      int ret, status = W_STOPCODE (SIGSTOP);
+      int ret, status;
 
       ptrace (PTRACE_GETEVENTMSG, lwpid_of (event_child), 0, &new_pid);
 
       /* If we haven't already seen the new PID stop, wait for it now.  */
-      if (! pull_pid_from_list (&stopped_pids, new_pid))
+      if (!pull_pid_from_list (&stopped_pids, new_pid, &status))
 	{
 	  /* The new child has a pending SIGSTOP.  We can't affect it until it
 	     hits the SIGSTOP, but we're already attached.  */
@@ -1170,7 +1213,7 @@ retry:
      was reported to us by the kernel.  Save its PID.  */
   if (child == NULL && WIFSTOPPED (*wstatp))
     {
-      add_pid_to_list (&stopped_pids, ret);
+      add_to_pid_list (&stopped_pids, ret, *wstatp);
       goto retry;
     }
   else if (child == NULL)
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 30d608c..22b3125 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -279,8 +279,6 @@ void *inferior_target_data (struct thread_info *);
 void set_inferior_target_data (struct thread_info *, void *);
 void *inferior_regcache_data (struct thread_info *);
 void set_inferior_regcache_data (struct thread_info *, void *);
-void add_pid_to_list (struct inferior_list *list, unsigned long pid);
-int pull_pid_from_list (struct inferior_list *list, unsigned long pid);
 
 void loaded_dll (const char *name, CORE_ADDR base_addr);
 void unloaded_dll (const char *name, CORE_ADDR base_addr);


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