PR gdb/2250
authorUlrich Weigand <uweigand@de.ibm.com>
Mon, 17 Nov 2008 18:50:22 +0000 (18:50 +0000)
committerUlrich Weigand <uweigand@de.ibm.com>
Mon, 17 Nov 2008 18:50:22 +0000 (18:50 +0000)
* infrun.c (clear_proceed_status_thread): New function.
(clear_proceed_status_callback): New function.
(clear_proceed_status): In all-stop mode, clear per-thread
proceed status of *all* threads, not only the current.
(handle_inferior_event): In all-stop mode, if we're stepping
one thread, but got some inferior event in another thread
that does not cause GDB to break to the user interface,
ensure the interrupted stepping operation continues in the
original thread.
(currently_stepping): Move thread-related tests to ...
(currently_stepping_thread): ... this new function.
(currently_stepping_callback): New function.

gdb/ChangeLog
gdb/infrun.c

index 2327ee17e901b4ad8532ff6b377f180c782e15e9..e70bea18ccbc9233ce3a15cd2479e86c0abc7cb1 100644 (file)
@@ -1,3 +1,19 @@
+2008-11-17  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       PR gdb/2250
+       * infrun.c (clear_proceed_status_thread): New function.
+       (clear_proceed_status_callback): New function.
+       (clear_proceed_status): In all-stop mode, clear per-thread
+       proceed status of *all* threads, not only the current.
+       (handle_inferior_event): In all-stop mode, if we're stepping
+       one thread, but got some inferior event in another thread
+       that does not cause GDB to break to the user interface,
+       ensure the interrupted stepping operation continues in the
+       original thread.
+       (currently_stepping): Move thread-related tests to ...
+       (currently_stepping_thread): ... this new function.
+       (currently_stepping_callback): New function.
+
 2008-11-17  Vladimir Prus  <vladimir@codesourcery.com>
 
        Implement =thread-selected notification.
index 292200f237f25a83f5c126074fde920c58aed5c7..fbe0af06c8f4eb2a507b952067a38e65909e87dd 100644 (file)
@@ -75,6 +75,8 @@ static void set_schedlock_func (char *args, int from_tty,
 
 static int currently_stepping (struct thread_info *tp);
 
+static int currently_stepping_callback (struct thread_info *tp, void *data);
+
 static void xdb_handle_command (char *args, int from_tty);
 
 static int prepare_to_proceed (int);
@@ -1161,31 +1163,59 @@ a command like `return' or `jump' to continue execution."));
 /* Clear out all variables saying what to do when inferior is continued.
    First do this, then set the ones you want, then call `proceed'.  */
 
-void
-clear_proceed_status (void)
+static void
+clear_proceed_status_thread (struct thread_info *tp)
 {
-  if (!ptid_equal (inferior_ptid, null_ptid))
-    {
-      struct thread_info *tp;
-      struct inferior *inferior;
+  if (debug_infrun)
+    fprintf_unfiltered (gdb_stdlog,
+                       "infrun: clear_proceed_status_thread (%s)\n",
+                       target_pid_to_str (tp->ptid));
 
-      tp = inferior_thread ();
+  tp->trap_expected = 0;
+  tp->step_range_start = 0;
+  tp->step_range_end = 0;
+  tp->step_frame_id = null_frame_id;
+  tp->step_over_calls = STEP_OVER_UNDEBUGGABLE;
+  tp->stop_requested = 0;
 
-      tp->trap_expected = 0;
-      tp->step_range_start = 0;
-      tp->step_range_end = 0;
-      tp->step_frame_id = null_frame_id;
-      tp->step_over_calls = STEP_OVER_UNDEBUGGABLE;
-      tp->stop_requested = 0;
+  tp->stop_step = 0;
 
-      tp->stop_step = 0;
+  tp->proceed_to_finish = 0;
 
-      tp->proceed_to_finish = 0;
+  /* Discard any remaining commands or status from previous stop.  */
+  bpstat_clear (&tp->stop_bpstat);
+}
 
-      /* Discard any remaining commands or status from previous
-        stop.  */
-      bpstat_clear (&tp->stop_bpstat);
+static int
+clear_proceed_status_callback (struct thread_info *tp, void *data)
+{
+  if (is_exited (tp->ptid))
+    return 0;
 
+  clear_proceed_status_thread (tp);
+  return 0;
+}
+
+void
+clear_proceed_status (void)
+{
+  if (!ptid_equal (inferior_ptid, null_ptid))
+    {
+      struct inferior *inferior;
+
+      if (non_stop)
+       {
+         /* If in non-stop mode, only delete the per-thread status
+            of the current thread.  */
+         clear_proceed_status_thread (inferior_thread ());
+       }
+      else
+       {
+         /* In all-stop mode, delete the per-thread status of
+            *all* threads.  */
+         iterate_over_threads (clear_proceed_status_callback, NULL);
+       }
+  
       inferior = current_inferior ();
       inferior->stop_soon = NO_STOP_QUIETLY;
     }
@@ -3185,6 +3215,43 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
      test for stepping.  But, if not stepping,
      do not stop.  */
 
+  /* In all-stop mode, if we're currently stepping but have stopped in
+     some other thread, we need to switch back to the stepped thread.  */
+  if (!non_stop)
+    {
+      struct thread_info *tp;
+      tp = iterate_over_threads (currently_stepping_callback,
+                                ecs->event_thread);
+      if (tp)
+       {
+         /* However, if the current thread is blocked on some internal
+            breakpoint, and we simply need to step over that breakpoint
+            to get it going again, do that first.  */
+         if ((ecs->event_thread->trap_expected
+              && ecs->event_thread->stop_signal != TARGET_SIGNAL_TRAP)
+             || ecs->event_thread->stepping_over_breakpoint)
+           {
+             keep_going (ecs);
+             return;
+           }
+
+         /* Otherwise, we no longer expect a trap in the current thread.
+            Clear the trap_expected flag before switching back -- this is
+            what keep_going would do as well, if we called it.  */
+         ecs->event_thread->trap_expected = 0;
+
+         if (debug_infrun)
+           fprintf_unfiltered (gdb_stdlog,
+                               "infrun: switching back to stepped thread\n");
+
+         ecs->event_thread = tp;
+         ecs->ptid = tp->ptid;
+         context_switch (ecs->ptid);
+         keep_going (ecs);
+         return;
+       }
+    }
+
   /* Are we stepping to get the inferior out of the dynamic linker's
      hook (and possibly the dld itself) after catching a shlib
      event?  */
@@ -3603,13 +3670,26 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
 
 /* Are we in the middle of stepping?  */
 
+static int
+currently_stepping_thread (struct thread_info *tp)
+{
+  return (tp->step_range_end && tp->step_resume_breakpoint == NULL)
+        || tp->trap_expected
+        || tp->stepping_through_solib_after_catch;
+}
+
+static int
+currently_stepping_callback (struct thread_info *tp, void *data)
+{
+  /* Return true if any thread *but* the one passed in "data" is
+     in the middle of stepping.  */
+  return tp != data && currently_stepping_thread (tp);
+}
+
 static int
 currently_stepping (struct thread_info *tp)
 {
-  return (((tp->step_range_end && tp->step_resume_breakpoint == NULL)
-          || tp->trap_expected)
-         || tp->stepping_through_solib_after_catch
-         || bpstat_should_step ());
+  return currently_stepping_thread (tp) || bpstat_should_step ();
 }
 
 /* Inferior has stepped into a subroutine call with source code that