]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Async mode fixes.
authorVladimir Prus <vladimir@codesourcery.com>
Fri, 14 Mar 2008 18:57:44 +0000 (18:57 +0000)
committerVladimir Prus <vladimir@codesourcery.com>
Fri, 14 Mar 2008 18:57:44 +0000 (18:57 +0000)
        * Makefile.in (infcmd.o, inf-loop.o): Update dependencies.
        * breakpoint.c (bpstat_do_actions): In async mode,
        don't jump to top expecting stop_bpstat to be already
        updated.
        * event-loop.c (start_event_loop): Call async_enable_stdin
        on exception.
        * event-top.c (async_enable_stdin): Do nothing if sync_execution
        is not set.
        (command_handler): Do not setup continuation here.
        (command_line_handler_continuation): Move to...
        * top.c (command_line_handler_continuation): ... here.
        (execute_command): In async mode, register continuation.
        Don't check frame's language in running in async mode.
        * exceptions.c (throw_exception): Don't do exec_error_cleanups.
        * inf-loop.c (complete_execution): Inline into...
        (inferior_event_handler): ... here.  Clear target_executing before
        doing any cleanups.  Don't try to show prompt if the target was
        resumed.
        * infcmd.c (signal_command): Add support for async mode.
        (finish_command): Only add continuation if the target was
        successfully resumed.
        * remote.c (init_async_opts): Register to_get_thread_local_address
        handler.
        * mi/mi-interp.c (mi_cmd_interpreter_exec): Don't mess
        with sync_execution.
        * tui/tui-interp.c (tui_command_loop): Call async_enable_stdin
        on exception.

12 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/breakpoint.c
gdb/event-loop.c
gdb/event-top.c
gdb/exceptions.c
gdb/inf-loop.c
gdb/infcmd.c
gdb/mi/mi-interp.c
gdb/remote.c
gdb/top.c
gdb/tui/tui-interp.c

index 082c44c2be69c7f5aafe6eab023086eb7af5fcd5..9526ba37485f6d785493dd68b67013b411e540a7 100644 (file)
@@ -1,3 +1,34 @@
+2008-03-14  Vladimir Prus  <vladimir@codesourcery.com>
+
+       Async mode fixes.
+        * Makefile.in (infcmd.o, inf-loop.o): Update dependencies.
+        * breakpoint.c (bpstat_do_actions): In async mode,
+        don't jump to top expecting stop_bpstat to be already
+        updated.
+        * event-loop.c (start_event_loop): Call async_enable_stdin
+        on exception.
+        * event-top.c (async_enable_stdin): Do nothing if sync_execution
+        is not set.
+        (command_handler): Do not setup continuation here.
+        (command_line_handler_continuation): Move to...
+        * top.c (command_line_handler_continuation): ... here.
+        (execute_command): In async mode, register continuation.
+        Don't check frame's language in running in async mode.
+        * exceptions.c (throw_exception): Don't do exec_error_cleanups.
+        * inf-loop.c (complete_execution): Inline into...
+        (inferior_event_handler): ... here.  Clear target_executing before
+        doing any cleanups.  Don't try to show prompt if the target was
+        resumed.
+        * infcmd.c (signal_command): Add support for async mode.
+        (finish_command): Only add continuation if the target was
+        successfully resumed.
+        * remote.c (init_async_opts): Register to_get_thread_local_address
+        handler.
+        * mi/mi-interp.c (mi_cmd_interpreter_exec): Don't mess
+        with sync_execution.
+        * tui/tui-interp.c (tui_command_loop): Call async_enable_stdin
+        on exception.
+
 2008-03-14  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * corefile.c (reopen_exec_file): Use exec_bfd_mtime.
index 04db23391acfaf31818b1b89e57add3579c9905c..a3e73b914feca4a1efd0f5135dd8a990be6aac58 100644 (file)
@@ -2291,9 +2291,10 @@ infcmd.o: infcmd.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
        $(objfiles_h) $(completer_h) $(ui_out_h) $(event_top_h) \
        $(parser_defs_h) $(regcache_h) $(reggroups_h) $(block_h) \
        $(solib_h) $(gdb_assert_h) $(observer_h) $(target_descriptions_h) \
-       $(user_regs_h)
+       $(user_regs_h) $(exceptions_h)
 inf-loop.o: inf-loop.c $(defs_h) $(inferior_h) $(target_h) $(event_loop_h) \
-       $(event_top_h) $(inf_loop_h) $(remote_h) $(exceptions_h)
+       $(event_top_h) $(inf_loop_h) $(remote_h) $(exceptions_h) \
+       $(language_h)
 inflow.o: inflow.c $(defs_h) $(frame_h) $(inferior_h) $(command_h) \
        $(serial_h) $(terminal_h) $(target_h) $(gdbthread_h) $(gdb_string_h) \
        $(inflow_h) $(gdb_select_h)
index 4fbda0b6e8e52da944b6810a68bacd5c0a3816a4..6830efef120ee6ab1c036429a0f796fcaa9d1d99 100644 (file)
@@ -2114,11 +2114,30 @@ top:
       do_cleanups (this_cmd_tree_chain);
 
       if (breakpoint_proceeded)
-       /* The inferior is proceeded by the command; bomb out now.
-          The bpstat chain has been blown away by wait_for_inferior.
-          But since execution has stopped again, there is a new bpstat
-          to look at, so start over.  */
-       goto top;
+       {
+         if (target_can_async_p ())
+         /* If we are in async mode, then the target might
+            be still running, not stopped at any breakpoint,
+            so nothing for us to do here -- just return to
+            the event loop.  */
+           break;
+         else
+           /* In sync mode, when execute_control_command returns
+              we're already standing on the next breakpoint.
+              Breakpoint commands for that stop were not run,
+              since execute_command does not run breakpoint
+              commands -- only command_line_handler does, but
+              that one is not involved in execution of breakpoint
+              commands.  So, we can now execute breakpoint commands.
+              There's an implicit assumption that we're called with
+              stop_bpstat, so our parameter is the new bpstat to
+              handle.  
+              It should be noted that making execute_command do
+              bpstat actions is not an option -- in this case we'll
+              have recursive invocation of bpstat for each breakpoint
+              with a command, and can easily blow up GDB stack.  */
+           goto top;
+       }
     }
   do_cleanups (old_chain);
 }
index 9a04e32a0a051361888a9a141fee06fd8a76137c..ceff6997ff41d6349af5ae21f643ecab4ecc9e42 100644 (file)
@@ -411,6 +411,10 @@ start_event_loop (void)
 
       if (gdb_result == 0)
        {
+         /* If any exception escaped to here, we better enable
+            stdin.  Otherwise, any command that calls async_disable_stdin,
+            and then throws, will leave stdin inoperable.  */
+         async_enable_stdin ((void *) 0);
          /* FIXME: this should really be a call to a hook that is
             interface specific, because interfaces can display the
             prompt in their own way. */
index f798eee87265a40aa75e56be078ed9195a623261..79dd4c32ae581f2d74e92a352a7690cf324263d9 100644 (file)
@@ -44,7 +44,6 @@
 
 static void rl_callback_read_char_wrapper (gdb_client_data client_data);
 static void command_line_handler (char *rl);
-static void command_line_handler_continuation (struct continuation_arg *arg);
 static void change_line_handler (void);
 static void change_annotation_level (void);
 static void command_handler (char *command);
@@ -438,13 +437,16 @@ stdin_event_handler (int error, gdb_client_data client_data)
 void
 async_enable_stdin (void *dummy)
 {
-  /* See NOTE in async_disable_stdin() */
-  /* FIXME: cagney/1999-09-27: Call this before clearing
-     sync_execution.  Current target_terminal_ours() implementations
-     check for sync_execution before switching the terminal. */
-  target_terminal_ours ();
-  pop_prompt ();
-  sync_execution = 0;
+  if (sync_execution)
+    {
+      /* See NOTE in async_disable_stdin() */
+      /* FIXME: cagney/1999-09-27: Call this before clearing
+        sync_execution.  Current target_terminal_ours() implementations
+        check for sync_execution before switching the terminal. */
+      target_terminal_ours ();
+      pop_prompt ();
+      sync_execution = 0;
+    }
 }
 
 /* Disable reads from stdin (the console) marking the command as
@@ -480,8 +482,6 @@ command_handler (char *command)
 {
   struct cleanup *old_chain;
   int stdin_is_tty = ISATTY (stdin);
-  struct continuation_arg *arg1;
-  struct continuation_arg *arg2;
   long time_at_cmd_start;
 #ifdef HAVE_SBRK
   long space_at_cmd_start = 0;
@@ -517,24 +517,6 @@ command_handler (char *command)
 
   execute_command (command, instream == stdin);
 
-  /* Set things up for this function to be compete later, once the
-     execution has completed, if we are doing an execution command,
-     otherwise, just go ahead and finish. */
-  if (target_can_async_p () && target_executing)
-    {
-      arg1 =
-       (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
-      arg2 =
-       (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
-      arg1->next = arg2;
-      arg2->next = NULL;
-      arg1->data.longint = time_at_cmd_start;
-#ifdef HAVE_SBRK
-      arg2->data.longint = space_at_cmd_start;
-#endif
-      add_continuation (command_line_handler_continuation, arg1);
-    }
-
   /* Do any commands attached to breakpoint we stopped at. Only if we
      are always running synchronously. Or if we have just executed a
      command that doesn't start the target. */
@@ -567,43 +549,6 @@ command_handler (char *command)
     }
 }
 
-/* Do any commands attached to breakpoint we stopped at. Only if we
-   are always running synchronously. Or if we have just executed a
-   command that doesn't start the target. */
-void
-command_line_handler_continuation (struct continuation_arg *arg)
-{
-  extern int display_time;
-  extern int display_space;
-
-  long time_at_cmd_start  = arg->data.longint;
-  long space_at_cmd_start = arg->next->data.longint;
-
-  bpstat_do_actions (&stop_bpstat);
-  /*do_cleanups (old_chain); *//*?????FIXME????? */
-
-  if (display_time)
-    {
-      long cmd_time = get_run_time () - time_at_cmd_start;
-
-      printf_unfiltered (_("Command execution time: %ld.%06ld\n"),
-                        cmd_time / 1000000, cmd_time % 1000000);
-    }
-  if (display_space)
-    {
-#ifdef HAVE_SBRK
-      char *lim = (char *) sbrk (0);
-      long space_now = lim - lim_at_start;
-      long space_diff = space_now - space_at_cmd_start;
-
-      printf_unfiltered (_("Space used: %ld (%c%ld for this command)\n"),
-                        space_now,
-                        (space_diff >= 0 ? '+' : '-'),
-                        space_diff);
-#endif
-    }
-}
-
 /* Handle a complete line of input. This is called by the callback
    mechanism within the readline library.  Deal with incomplete commands
    as well, by saving the partial input in a global buffer.  */
index ae30367f9bc36e15518fb69e37f5e7bb8235df92..89d14551a5709e61c28fde8a977ae9e894b1c767 100644 (file)
@@ -221,10 +221,12 @@ throw_exception (struct gdb_exception exception)
 
   disable_current_display ();
   do_cleanups (ALL_CLEANUPS);
+  /* When we implement non-stop mode, this should be redone.  If we get
+     exception in a command pertaining to one thread, or maybe even not
+     involving inferior at all, we should not do exec cleanups for all
+     threads.  */
   if (target_can_async_p () && !target_executing)
     do_exec_cleanups (ALL_CLEANUPS);
-  if (sync_execution)
-    do_exec_error_cleanups (ALL_CLEANUPS);
 
   /* Jump to the containing catch_errors() call, communicating REASON
      to that call via setjmp's return value.  Note that REASON can't
index b6f8bb8d728556fb96b170b76003357d3a53b09c..c4fb111199418150b1f92e65c58b035ffa88c346 100644 (file)
@@ -25,9 +25,9 @@
 #include "inf-loop.h"
 #include "remote.h"
 #include "exceptions.h"
+#include "language.h"
 
 static int fetch_inferior_event_wrapper (gdb_client_data client_data);
-static void complete_execution (void);
 
 void
 inferior_event_handler_wrapper (gdb_client_data client_data)
@@ -43,6 +43,7 @@ void
 inferior_event_handler (enum inferior_event_type event_type, 
                        gdb_client_data client_data)
 {
+  int was_sync = 0;
   switch (event_type)
     {
     case INF_ERROR:
@@ -70,11 +71,52 @@ inferior_event_handler (enum inferior_event_type event_type,
       break;
 
     case INF_EXEC_COMPLETE:
-      /* Is there anything left to do for the command issued to
-         complete? */
+
+      /* This is the first thing to do -- so that continuations know that
+        the target is stopped.  For example, command_line_handler_continuation
+        will run breakpoint commands, and if we think that the target is
+        running, we'll refuse to execute most commands.  MI continuation
+        presently uses target_executing to either print or not print *stopped.  */
+      target_executing = 0;
+
+      /* Unregister the inferior from the event loop. This is done so that
+        when the inferior is not running we don't get distracted by
+        spurious inferior output.  */
+      if (target_has_execution)
+       target_async (NULL, 0);
+
+      /* Calls to do_exec_error_cleanup below will call async_enable_stdin,
+        and that resets 'sync_execution'.  However, if we were running
+        in sync execution mode, we also need to display the prompt.  */
+      was_sync = sync_execution;
+
+      if (was_sync)
+       do_exec_error_cleanups (ALL_CLEANUPS);
+
       do_all_continuations ();
-      /* Reset things after target has stopped for the async commands. */
-      complete_execution ();
+
+      if (current_language != expected_language)
+       {
+         if (language_mode == language_mode_auto)
+           {
+             language_info (1);        /* Print what changed.  */
+           }
+       }
+
+      /* If the continuation did not start the target again,
+        prepare for interation with the user.  */
+      if (!target_executing)
+       {              
+         if (was_sync)
+           {
+             display_gdb_prompt (0);
+           }
+         else
+           {
+             if (exec_done_display_p)
+               printf_unfiltered (_("completed.\n"));
+           }
+       }
       break;
 
     case INF_EXEC_CONTINUE:
@@ -103,29 +145,3 @@ fetch_inferior_event_wrapper (gdb_client_data client_data)
   fetch_inferior_event (client_data);
   return 1;
 }
-
-/* Reset proper settings after an asynchronous command has finished.
-   If the execution command was in synchronous mode, register stdin
-   with the event loop, and reset the prompt. */
-
-static void
-complete_execution (void)
-{
-  target_executing = 0;
-  
-  /* Unregister the inferior from the event loop. This is done so that
-     when the inferior is not running we don't get distracted by
-     spurious inferior output. */
-  target_async (NULL, 0);
-
-  if (sync_execution)
-    {
-      do_exec_error_cleanups (ALL_CLEANUPS);
-      display_gdb_prompt (0);
-    }
-  else
-    {
-      if (exec_done_display_p)
-       printf_unfiltered (_("completed.\n"));
-    }
-}
index 70bf69536fcf21aaea1d381b49c87811980d62d7..3a22c1c25b1995692b55b57cd4d732bf4cea168b 100644 (file)
@@ -48,6 +48,7 @@
 #include "observer.h"
 #include "target-descriptions.h"
 #include "user-regs.h"
+#include "exceptions.h"
 
 /* Functions exported for general use, in inferior.h: */
 
@@ -1005,10 +1006,28 @@ static void
 signal_command (char *signum_exp, int from_tty)
 {
   enum target_signal oursig;
+  int async_exec = 0;
 
   dont_repeat ();              /* Too dangerous.  */
   ERROR_NO_INFERIOR;
 
+  /* Find out whether we must run in the background.  */
+  if (signum_exp != NULL)
+    async_exec = strip_bg_char (&signum_exp);
+
+  /* If we must run in the background, but the target can't do it,
+     error out.  */
+  if (async_exec && !target_can_async_p ())
+    error (_("Asynchronous execution not supported on this target."));
+
+  /* If we are not asked to run in the bg, then prepare to run in the
+     foreground, synchronously.  */
+  if (!async_exec && target_can_async_p ())
+    {
+      /* Simulate synchronous execution.  */
+      async_disable_stdin ();
+    }
+
   if (!signum_exp)
     error_no_arg (_("signal number"));
 
@@ -1321,10 +1340,15 @@ finish_command (char *arg, int from_tty)
       print_stack_frame (get_selected_frame (NULL), 1, LOCATION);
     }
 
+  proceed_to_finish = 1;       /* We want stop_registers, please...  */
+  proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+
   /* If running asynchronously and the target support asynchronous
      execution, set things up for the rest of the finish command to be
      completed later on, when gdb has detected that the target has
-     stopped, in fetch_inferior_event.  */
+     stopped, in fetch_inferior_event.  
+     Setup it only after proceed, so that if proceed throws, we don't
+     set continuation.  */
   if (target_can_async_p ())
     {
       arg1 =
@@ -1342,9 +1366,6 @@ finish_command (char *arg, int from_tty)
       add_continuation (finish_command_continuation, arg1);
     }
 
-  proceed_to_finish = 1;       /* We want stop_registers, please...  */
-  proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
-
   /* Do this only if not running asynchronously or if the target
      cannot do async execution.  Otherwise, complete this command when
      the target actually stops, in fetch_inferior_event.  */
index 96229a01d29a804d250a1751c3395f5459d3d075..05a64d811bb5a99a66d2241f9c2e52e732b161b5 100644 (file)
@@ -224,23 +224,13 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc)
 
   for (i = 1; i < argc; i++)
     {
-      /* We had to set sync_execution = 0 for the mi (well really for Project
-         Builder's use of the mi - particularly so interrupting would work.
-         But for console commands to work, we need to initialize it to 1 -
-         since that is what the cli expects - before running the command,
-         and then set it back to 0 when we are done. */
-      sync_execution = 1;
-      {
-       struct gdb_exception e = interp_exec (interp_to_use, argv[i]);
-       if (e.reason < 0)
-         {
-           mi_error_message = xstrdup (e.message);
-           result = MI_CMD_ERROR;
-           break;
-         }
-      }
-      do_exec_error_cleanups (ALL_CLEANUPS);
-      sync_execution = 0;
+      struct gdb_exception e = interp_exec (interp_to_use, argv[i]);
+      if (e.reason < 0)
+       {
+         mi_error_message = xstrdup (e.message);
+         result = MI_CMD_ERROR;
+         break;
+       }
     }
 
   mi_remove_notify_hooks ();
index 88cde580bb2574b4845ae514d82bc6b52cdc3dad..73fcc2a60e97d0e0217266abae49a47b1ca09030 100644 (file)
@@ -7348,6 +7348,8 @@ Specify the serial device it is connected to (e.g. /dev/ttya).";
   remote_async_ops.to_stop = remote_stop;
   remote_async_ops.to_xfer_partial = remote_xfer_partial;
   remote_async_ops.to_rcmd = remote_rcmd;
+  remote_async_ops.to_get_thread_local_address 
+    = remote_get_thread_local_address;
   remote_async_ops.to_stratum = process_stratum;
   remote_async_ops.to_has_all_memory = 1;
   remote_async_ops.to_has_memory = 1;
index c205ec33e91611330c543a308d1809dedeb9c35f..3b9aaab7ffe59a20b2a0d95b507ab69a355cc305 100644 (file)
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -364,6 +364,42 @@ do_chdir_cleanup (void *old_dir)
 }
 #endif
 
+/* Do any commands attached to breakpoint we stopped at. Only if we
+   are always running synchronously. Or if we have just executed a
+   command that doesn't start the target.  */
+static void
+command_line_handler_continuation (struct continuation_arg *arg)
+{
+  extern int display_time;
+  extern int display_space;
+
+  long time_at_cmd_start  = arg->data.longint;
+  long space_at_cmd_start = arg->next->data.longint;
+
+  bpstat_do_actions (&stop_bpstat);
+
+  if (display_time)
+    {
+      long cmd_time = get_run_time () - time_at_cmd_start;
+
+      printf_unfiltered (_("Command execution time: %ld.%06ld\n"),
+                        cmd_time / 1000000, cmd_time % 1000000);
+    }
+  if (display_space)
+    {
+#ifdef HAVE_SBRK
+      char *lim = (char *) sbrk (0);
+      long space_now = lim - lim_at_start;
+      long space_diff = space_now - space_at_cmd_start;
+
+      printf_unfiltered (_("Space used: %ld (%c%ld for this command)\n"),
+                        space_now,
+                        (space_diff >= 0 ? '+' : '-'),
+                        space_diff);
+#endif
+    }
+}
+
 /* Execute the line P as a command.
    Pass FROM_TTY as second argument to the defining function.  */
 
@@ -374,6 +410,27 @@ execute_command (char *p, int from_tty)
   enum language flang;
   static int warned = 0;
   char *line;
+  struct continuation_arg *arg1;
+  struct continuation_arg *arg2;
+  long time_at_cmd_start;
+#ifdef HAVE_SBRK
+  long space_at_cmd_start = 0;
+#endif
+  extern int display_time;
+  extern int display_space;
+
+  if (target_can_async_p ())
+    {
+      time_at_cmd_start = get_run_time ();
+
+      if (display_space)
+       {
+#ifdef HAVE_SBRK
+         char *lim = (char *) sbrk (0);
+         space_at_cmd_start = lim - lim_at_start;
+#endif
+       }
+    }
   
   free_all_values ();
 
@@ -470,7 +527,7 @@ execute_command (char *p, int from_tty)
   /* FIXME:  This should be cacheing the frame and only running when
      the frame changes.  */
 
-  if (target_has_stack)
+  if (!target_executing && target_has_stack)
     {
       flang = get_frame_language ();
       if (!warned
@@ -481,6 +538,24 @@ execute_command (char *p, int from_tty)
          warned = 1;
        }
     }
+
+  /* Set things up for this function to be compete later, once the
+     execution has completed, if we are doing an execution command,
+     otherwise, just go ahead and finish. */
+  if (target_can_async_p () && target_executing)
+    {
+      arg1 =
+       (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+      arg2 =
+       (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+      arg1->next = arg2;
+      arg2->next = NULL;     
+      arg1->data.longint = time_at_cmd_start;
+#ifdef HAVE_SBRK
+      arg2->data.longint = space_at_cmd_start;
+#endif
+      add_continuation (command_line_handler_continuation, arg1);
+    }
 }
 
 /* Read commands from `instream' and execute them
index ca2e7436beaf1ddd55123893f903edc3c871d8ec..8a166785272722224ab8684e718c60e4048bfdf0 100644 (file)
@@ -164,6 +164,10 @@ tui_command_loop (void *data)
       
       if (result == 0)
        {
+         /* If any exception escaped to here, we better enable
+            stdin.  Otherwise, any command that calls async_disable_stdin,
+            and then throws, will leave stdin inoperable.  */
+         async_enable_stdin ((void *) 0);
          /* FIXME: this should really be a call to a hook that is
             interface specific, because interfaces can display the
             prompt in their own way.  */