2011-10-12 Pedro Alves <pedro@codesourcery.com>
authorPedro Alves <palves@redhat.com>
Wed, 12 Oct 2011 12:11:26 +0000 (12:11 +0000)
committerPedro Alves <palves@redhat.com>
Wed, 12 Oct 2011 12:11:26 +0000 (12:11 +0000)
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.

gdb/ChangeLog
gdb/linux-nat.c

index 3ce02ced84a207f9762f96346f52110b0953b145..fb5aded778f50b620c48591e19014a096cda3825 100644 (file)
@@ -1,3 +1,9 @@
+2011-10-12  Pedro Alves  <pedro@codesourcery.com>
+
+       * 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.
+
 2011-10-11  Sterling Augustine  <saugustine@google.com>
 
        * dwarf2read.c: Undo inadvertent changes in previous commit.
index 9a0d9e6512a1e9d89c3ed94352a4a9ff41c8dcab..f8a15c91213223e694e14a10651e153ed867c8b7 100644 (file)
@@ -3109,14 +3109,17 @@ resumed_callback (struct lwp_info *lp, void *data)
   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_info *lp, void *data)
 
       /* 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 status, int options)
        {
          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.  */