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]

linux-nat.c:stop_and_resume_callback - handle ending up with pending events


stop_and_resume_callback is resuming the lwp even if after
stopping it momentarily the lwp ended up with a pending event, which
is obviously bad.  This stops it doing so.  A little extra cared if
needed -- if we do have new pending events to handle after
linux_nat_filter_event, then we need to break from the loop and restart
over (as pending events aren't handled within the loop, but before.

Tested on x86_64-linux and applied.

-- 
Pedro Alves

2011-10-12  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* linux-nat.c (stop_and_resume_callback): Don't re-resume LWPs if
	the core wanted them stopped, or if they now have a pending event
	to report.
	(linux_nat_filter_event): New parameter `new_pending_p'.  Pass it
	down to stop_and_resume_callback.
	(linux_nat_wait_1): Always clear `options' when retrying.  Handle
	having new pending events after calling linux_nat_filter_event.

---
 gdb/linux-nat.c |   74 ++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 61 insertions(+), 13 deletions(-)

Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c	2011-10-12 12:53:26.238592563 +0100
+++ src/gdb/linux-nat.c	2011-10-12 12:57:11.058592522 +0100
@@ -3109,14 +3109,17 @@ resumed_callback (struct lwp_info *lp, v
   return lp->resumed;
 }
 
-/* Stop an active thread, verify it still exists, then resume it.  */
+/* Stop an active thread, verify it still exists, then resume it.  If
+   the thread ends up with a pending status, then it is not resumed,
+   and *DATA (really a pointer to int), is set.  */
 
 static int
 stop_and_resume_callback (struct lwp_info *lp, void *data)
 {
+  int *new_pending_p = data;
+
   if (!lp->stopped)
     {
-      enum resume_kind last_resume_kind = lp->last_resume_kind;
       ptid_t ptid = lp->ptid;
 
       stop_callback (lp, NULL);
@@ -3124,23 +3127,57 @@ stop_and_resume_callback (struct lwp_inf
 
       /* Resume if the lwp still exists, and the core wanted it
 	 running.  */
-      if (last_resume_kind != resume_stop)
+      lp = find_lwp_pid (ptid);
+      if (lp != NULL)
 	{
-	  lp = find_lwp_pid (ptid);
-	  if (lp)
-	    resume_lwp (lp, lp->step);
+	  if (lp->last_resume_kind == resume_stop
+	      && lp->status == 0)
+	    {
+	      /* The core wanted the LWP to stop.  Even if it stopped
+		 cleanly (with SIGSTOP), leave the event pending.  */
+	      if (debug_linux_nat)
+		fprintf_unfiltered (gdb_stdlog,
+				    "SARC: core wanted LWP %ld stopped "
+				    "(leaving SIGSTOP pending)\n",
+				    GET_LWP (lp->ptid));
+	      lp->status = W_STOPCODE (SIGSTOP);
+	    }
+
+	  if (lp->status == 0)
+	    {
+	      if (debug_linux_nat)
+		fprintf_unfiltered (gdb_stdlog,
+				    "SARC: re-resuming LWP %ld\n",
+				    GET_LWP (lp->ptid));
+	      resume_lwp (lp, lp->step);
+	    }
+	  else
+	    {
+	      if (debug_linux_nat)
+		fprintf_unfiltered (gdb_stdlog,
+				    "SARC: not re-resuming LWP %ld "
+				    "(has pending)\n",
+				    GET_LWP (lp->ptid));
+	      if (new_pending_p)
+		*new_pending_p = 1;
+	    }
 	}
     }
   return 0;
 }
 
 /* Check if we should go on and pass this event to common code.
-   Return the affected lwp if we are, or NULL otherwise.  */
+   Return the affected lwp if we are, or NULL otherwise.  If we stop
+   all lwps temporarily, we may end up with new pending events in some
+   other lwp.  In that case set *NEW_PENDING_P to true.  */
+
 static struct lwp_info *
-linux_nat_filter_event (int lwpid, int status, int options)
+linux_nat_filter_event (int lwpid, int status, int options, int *new_pending_p)
 {
   struct lwp_info *lp;
 
+  *new_pending_p = 0;
+
   lp = find_lwp_pid (pid_to_ptid (lwpid));
 
   /* Check for stop events reported by a process we didn't already
@@ -3240,7 +3277,7 @@ linux_nat_filter_event (int lwpid, int s
 	{
 	  lp->stopped = 1;
 	  iterate_over_lwps (pid_to_ptid (GET_PID (lp->ptid)),
-			     stop_and_resume_callback, NULL);
+			     stop_and_resume_callback, new_pending_p);
 	}
 
       if (debug_linux_nat)
@@ -3358,9 +3395,9 @@ linux_nat_wait_1 (struct target_ops *ops
 {
   static sigset_t prev_mask;
   enum resume_kind last_resume_kind;
-  struct lwp_info *lp = NULL;
-  int options = 0;
-  int status = 0;
+  struct lwp_info *lp;
+  int options;
+  int status;
   pid_t pid;
 
   if (debug_linux_nat)
@@ -3397,6 +3434,7 @@ linux_nat_wait_1 (struct target_ops *ops
 retry:
   lp = NULL;
   status = 0;
+  options = 0;
 
   /* Make sure that of those LWPs we want to get an event from, there
      is at least one LWP that has been resumed.  If there's none, just
@@ -3527,6 +3565,10 @@ retry:
 
       if (lwpid > 0)
 	{
+	  /* If this is true, then we paused LWPs momentarily, and may
+	     now have pending events to handle.  */
+	  int new_pending;
+
 	  gdb_assert (pid == -1 || lwpid == pid);
 
 	  if (debug_linux_nat)
@@ -3536,7 +3578,7 @@ retry:
 				  (long) lwpid, status_to_str (status));
 	    }
 
-	  lp = linux_nat_filter_event (lwpid, status, options);
+	  lp = linux_nat_filter_event (lwpid, status, options, &new_pending);
 
 	  /* STATUS is now no longer valid, use LP->STATUS instead.  */
 	  status = 0;
@@ -3616,6 +3658,9 @@ retry:
 		  store_waitstatus (&lp->waitstatus, lp->status);
 		}
 
+	      if (new_pending)
+		goto retry;
+
 	      /* Keep looking.  */
 	      lp = NULL;
 	      continue;
@@ -3625,6 +3670,9 @@ retry:
 	    break;
 	  else
 	    {
+	      if (new_pending)
+		goto retry;
+
 	      if (pid == -1)
 		{
 		  /* waitpid did return something.  Restart over.  */


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