PR gdb/9747:
authorPedro Alves <palves@redhat.com>
Sun, 18 Jan 2009 17:42:16 +0000 (17:42 +0000)
committerPedro Alves <palves@redhat.com>
Sun, 18 Jan 2009 17:42:16 +0000 (17:42 +0000)
* gdbthread.h (finish_thread_state, finish_thread_state_cleanup):
Declare.
* thread.c (finish_thread_state, finish_thread_state_cleanup): New.
* infrun.c (wait_for_inferior, fetch_inferior_event): If an error
is thrown while handling an event, finish the thread state.
(normal_stop): Use finish_thread_state cleanup.
* infcmd.c (run_command_1): If an error is thrown while starting
the inferior, finish the thread state.

gdb/ChangeLog
gdb/gdbthread.h
gdb/infcmd.c
gdb/infrun.c
gdb/thread.c

index 93d72b0213cbf45d4747b9df6e4b181d33d5a334..79d3ed707d5830244867e21c270a7f73aad92307 100644 (file)
@@ -1,3 +1,15 @@
+2009-01-18  Pedro Alves  <pedro@codesourcery.com>
+
+       PR gdb/9747:
+       * gdbthread.h (finish_thread_state, finish_thread_state_cleanup):
+       Declare.
+       * thread.c (finish_thread_state, finish_thread_state_cleanup): New.
+       * infrun.c (wait_for_inferior, fetch_inferior_event): If an error
+       is thrown while handling an event, finish the thread state.
+       (normal_stop): Use finish_thread_state cleanup.
+       * infcmd.c (run_command_1): If an error is thrown while starting
+       the inferior, finish the thread state.
+
 2009-01-18  Pedro Alves  <pedro@codesourcery.com>
 
        * tui/tui-winsource.c (tui_update_breakpoint_info): In asm layout,
index ab95247171dfa60fb47564ad910fc2d6e45d7a0c..3a405a86eebb13e330c79913c630c6c980e93d26 100644 (file)
@@ -288,6 +288,23 @@ extern void set_executing (ptid_t ptid, int executing);
 /* Reports if thread PTID is executing.  */
 extern int is_executing (ptid_t ptid);
 
+/* Merge the executing property of thread PTID over to its thread
+   state property (frontend running/stopped view).
+
+   "not executing" -> "stopped"
+   "executing"     -> "running"
+   "exited"        -> "exited"
+
+   If PIDGET (PTID) is -1, go over all threads.
+
+   Notifications are only emitted if the thread state did change.  */
+extern void finish_thread_state (ptid_t ptid);
+
+/* Same as FINISH_THREAD_STATE, but with an interface suitable to be
+   registered as a cleanup.  PTID_P points to the ptid_t that is
+   passed to FINISH_THREAD_STATE.  */
+extern void finish_thread_state_cleanup (void *ptid_p);
+
 /* Commands with a prefix of `thread'.  */
 extern struct cmd_list_element *thread_cmd_list;
 
index 3ed654590fca57f50da31f646984392065671a74..2cd583cdb8744151a58ac782b9859afb877f4760 100644 (file)
@@ -456,6 +456,8 @@ static void
 run_command_1 (char *args, int from_tty, int tbreak_at_main)
 {
   char *exec_file;
+  struct cleanup *old_chain;
+  ptid_t ptid;
 
   dont_repeat ();
 
@@ -544,14 +546,29 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main)
   target_create_inferior (exec_file, get_inferior_args (),
                          environ_vector (inferior_environ), from_tty);
 
+  /* We're starting off a new process.  When we get out of here, in
+     non-stop mode, finish the state of all threads of that process,
+     but leave other threads alone, as they may be stopped in internal
+     events --- the frontend shouldn't see them as stopped.  In
+     all-stop, always finish the state of all threads, as we may be
+     resuming more than just the new process.  */
+  if (non_stop)
+    ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+  else
+    ptid = minus_one_ptid;
+  old_chain = make_cleanup (finish_thread_state_cleanup, &ptid);
+
   /* Pass zero for FROM_TTY, because at this point the "run" command
      has done its thing; now we are setting up the running program.  */
   post_create_inferior (&current_target, 0);
 
   /* Start the target running.  */
   proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
-}
 
+  /* Since there was no error, there's no need to finish the thread
+     states here.  */
+  discard_cleanups (old_chain);
+}
 
 static void
 run_command (char *args, int from_tty)
index 09869394511c883af801988380bba86f2c7acbda..228e7434c11583f7c388a3fabcc5816e4b9b882f 100644 (file)
@@ -1783,6 +1783,8 @@ wait_for_inferior (int treat_exec_as_sigtrap)
 
   while (1)
     {
+      struct cleanup *old_chain;
+
       if (deprecated_target_wait_hook)
        ecs->ptid = deprecated_target_wait_hook (waiton_ptid, &ecs->ws);
       else
@@ -1795,9 +1797,17 @@ wait_for_inferior (int treat_exec_as_sigtrap)
           ecs->ws.value.sig = TARGET_SIGNAL_TRAP;
         }
 
+      /* If an error happens while handling the event, propagate GDB's
+        knowledge of the executing state to the frontend/user running
+        state.  */
+      old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+
       /* Now figure out what to do with the result of the result.  */
       handle_inferior_event (ecs);
 
+      /* No error, don't finish the state yet.  */
+      discard_cleanups (old_chain);
+
       if (!ecs->wait_some_more)
        break;
     }
@@ -1820,6 +1830,7 @@ fetch_inferior_event (void *client_data)
   struct execution_control_state ecss;
   struct execution_control_state *ecs = &ecss;
   struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+  struct cleanup *ts_old_chain;
   int was_sync = sync_execution;
 
   memset (ecs, 0, sizeof (*ecs));
@@ -1863,6 +1874,14 @@ fetch_inferior_event (void *client_data)
        thread.  */
     context_switch (ecs->ptid);
 
+  /* If an error happens while handling the event, propagate GDB's
+     knowledge of the executing state to the frontend/user running
+     state.  */
+  if (!non_stop)
+    ts_old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+  else
+    ts_old_chain = make_cleanup (finish_thread_state_cleanup, &ecs->ptid);
+
   /* Now figure out what to do with the result of the result.  */
   handle_inferior_event (ecs);
 
@@ -1886,6 +1905,9 @@ fetch_inferior_event (void *client_data)
        inferior_event_handler (INF_EXEC_COMPLETE, NULL);
     }
 
+  /* No error, don't finish the thread states yet.  */
+  discard_cleanups (ts_old_chain);
+
   /* Revert thread and frame.  */
   do_cleanups (old_chain);
 
@@ -4161,9 +4183,23 @@ normal_stop (void)
 {
   struct target_waitstatus last;
   ptid_t last_ptid;
+  struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
 
   get_last_target_status (&last_ptid, &last);
 
+  /* If an exception is thrown from this point on, make sure to
+     propagate GDB's knowledge of the executing state to the
+     frontend/user running state.  A QUIT is an easy exception to see
+     here, so do this before any filtered output.  */
+  if (target_has_execution)
+    {
+      if (!non_stop)
+       old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+      else if (last.kind != TARGET_WAITKIND_SIGNALLED
+              && last.kind != TARGET_WAITKIND_EXITED)
+       old_chain = make_cleanup (finish_thread_state_cleanup, &inferior_ptid);
+    }
+
   /* In non-stop mode, we don't want GDB to switch threads behind the
      user's back, to avoid races where the user is typing a command to
      apply to thread x, but GDB switches to thread y before the user
@@ -4383,20 +4419,11 @@ done:
        /* Delete the breakpoint we stopped at, if it wants to be deleted.
           Delete any breakpoint that is to be deleted at the next stop.  */
        breakpoint_auto_delete (inferior_thread ()->stop_bpstat);
-
-      /* Mark the stopped threads accordingly.  In all-stop, all
-        threads of all processes are stopped when we get any event
-        reported.  In non-stop mode, only the event thread stops.  If
-        we're handling a process exit in non-stop mode, there's
-        nothing to do, as threads of the dead process are gone, and
-        threads of any other process were left running.  */
-      if (!non_stop)
-       set_running (minus_one_ptid, 0);
-      else if (last.kind != TARGET_WAITKIND_SIGNALLED
-              && last.kind != TARGET_WAITKIND_EXITED)
-       set_running (inferior_ptid, 0);
     }
 
+  /* Tell the frontend about the new thread states.  */
+  do_cleanups (old_chain);
+
   /* Look up the hook_stop and run it (CLI internally handles problem
      of stop_command's pre-hook not existing).  */
   if (stop_command)
index 44e4ba2dc496d09cc9cda9ca9c0b28bca8a93b07..8a98b8ec4b6af57b6f57cd55c4ba94ccf6a7babc 100644 (file)
@@ -632,6 +632,55 @@ set_stop_requested (ptid_t ptid, int stop)
     observer_notify_thread_stop_requested (ptid);
 }
 
+void
+finish_thread_state (ptid_t ptid)
+{
+  struct thread_info *tp;
+  int all;
+  int any_started = 0;
+
+  all = ptid_equal (ptid, minus_one_ptid);
+
+  if (all || ptid_is_pid (ptid))
+    {
+      for (tp = thread_list; tp; tp = tp->next)
+       {
+         if (tp->state_ == THREAD_EXITED)
+           continue;
+         if (all || ptid_get_pid (ptid) == ptid_get_pid (tp->ptid))
+           {
+             if (tp->executing_ && tp->state_ == THREAD_STOPPED)
+               any_started = 1;
+             tp->state_ = tp->executing_ ? THREAD_RUNNING : THREAD_STOPPED;
+           }
+       }
+    }
+  else
+    {
+      tp = find_thread_pid (ptid);
+      gdb_assert (tp);
+      if (tp->state_ != THREAD_EXITED)
+       {
+         if (tp->executing_ && tp->state_ == THREAD_STOPPED)
+           any_started = 1;
+         tp->state_ = tp->executing_ ? THREAD_RUNNING : THREAD_STOPPED;
+       }
+    }
+
+  if (any_started)
+    observer_notify_target_resumed (ptid);
+}
+
+void
+finish_thread_state_cleanup (void *arg)
+{
+  ptid_t *ptid_p = arg;
+
+  gdb_assert (arg);
+
+  finish_thread_state (*ptid_p);
+}
+
 /* Prints the list of threads and their details on UIOUT.
    This is a version of 'info_thread_command' suitable for
    use from MI.