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]

[RFA] Async mode fixes.


Presently, gdb's async mode is not very healthy, as follows:

	# of expected passes            10129
	# of unexpected failures        537
	# of unexpected successes       2
	# of expected failures          40
	# of known failures             48
	# of unresolved testcases       301
	# of untested testcases         10
	# of unsupported tests          63

The attached patch improves that, bringing the results to:

	# of expected passes            10722
	# of unexpected failures        39
	# of unexpected successes       2
	# of expected failures          41
	# of known failures             51
	# of untested testcases         11
	# of unsupported tests          64

where only few failures are actually specific to async mode. There
are no regressions in non-async mode, on x86.

The patch has comments whenever appropriate, but some points need explicit
clarification.

To recap, current gdb, when operating with async-enabled target, allows
two modes for all commands that run target. The fully async mode, requested
by adding "&" to the command (say, "next &"), makes the target run, gives
you a prompt and allows you to type further commands. If no "&" is added,
then a sync execution is simulated -- whereby the prompt is suppressed
and GDB does not handle any events on stdin. It is my understanding that
we cannot kill this simulated sync mode because for console GDB,
simulated sync mode is the only way we can allow the debugged program to
read from stdin. (I haven't checked if the interaction with debugged program
indeed works, with Nick's linux async patch). This simulated sync mode 
is implemented by the sync_execution variable, and the 
async_enable_stdin and async_enable_stdout functions.

This issue of simulate sync is not relevant to MI -- for MI, gdb stdin
is generally a pipe, not a terminal, used only for reading 
commands from frontend and gdb has no way to route input to the application.

Another important detail of async mode are continuations -- when we resume
the target, we setup a function to be called when the target eventually
stops. The relevant functions are add_continuation and do_all_continuations.

The important problems with the current code are:

1. For MI mode, when we call a CLI command, in mi_cmd_interpreter_exec,
we set sync_execution to 1 and then set it back to 0.  This is just bogus --
setting that variable without also disabling stdin bring the entire
system in half-consistent state. Further, if the CLI command throws
an exception, we fail to restore sync_execution. I just removed that code.

2. If we ever throw an exception, throw_exception calls do_exec_error_cleanup,
which might call async_enable_stdin -- even though we're not yet done with
an operation that executes a target. I fixed that by moving async_enable_stdin
calls into event loop -- if no exception escapes to the event loop, when
async_enable_stdin is called normally, and otherwise we'll call it when we
get back to event loop.

3. When running breakpoints commands that includes 'continue' we have all
host of issues:
	- execute_command, which is directly used, does not set 
	continuation, and as result, the next event from inferior is not
	handled in a proper way. I've moved continuation setting to
	'execute_command'.
	- bpstat_do_action, after it sees that target has resumed,
	jumps to the top of itself. For sync mode, this works because
	at this point inferior is stopped again. For async mode,
	this obviously does not work -- I've made the function
	to just return.
	- inferior_event_handler tries to print the prompt even
	if the target has resumed

There are some remaining issues:
1. throw_exception calls do_exec_cleanups, and unlike ordinary
cleanup, the exec cleanup chain is not saved by TRY_CATCH. As
result, any exception does all cleanups from main to the current
point -- not from last TRY_CATCH to the current point. This
causes mi-pending.exp to fail.

2. When we execute a user-defined command that includes 'continue'
in the middle, we try to send the next command immediately -- and
in async mode the target is still running. This breaks define.exp

I'm also not 100% happy with the resulting code. In particular,
having exec_cleanup, exec_error_cleanup and continuations, which
all are used to implement calling code when something is done,
just screams for a unified callback-after-command-is-done-or-has-thrown
solution. However, before any big refactoring, we should bring
the number of failures down, and this patch does exactly that.

OK?

- Volodya


	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.
---
 gdb/Makefile.in      |    5 ++-
 gdb/breakpoint.c     |   29 +++++++++++++++---
 gdb/event-loop.c     |    4 ++
 gdb/event-top.c      |   75 ++++++-----------------------------------------
 gdb/exceptions.c     |    6 ++-
 gdb/inf-loop.c       |   78 ++++++++++++++++++++++++++++++--------------------
 gdb/infcmd.c         |   29 ++++++++++++++++--
 gdb/mi/mi-interp.c   |   24 ++++-----------
 gdb/remote.c         |    2 +
 gdb/top.c            |   78 +++++++++++++++++++++++++++++++++++++++++++++++++-
 gdb/tui/tui-interp.c |    4 ++
 11 files changed, 207 insertions(+), 127 deletions(-)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5b6f0d5..fcc8cb1 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -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)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a689e3a..78c01ff 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -2094,11 +2094,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);
 }
diff --git a/gdb/event-loop.c b/gdb/event-loop.c
index 94f07e9..348ffef 100644
--- a/gdb/event-loop.c
+++ b/gdb/event-loop.c
@@ -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 the can throw, 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. */
diff --git a/gdb/event-top.c b/gdb/event-top.c
index a3cc15c..9bd64f8 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -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.  */
diff --git a/gdb/exceptions.c b/gdb/exceptions.c
index ae30367..89d1455 100644
--- a/gdb/exceptions.c
+++ b/gdb/exceptions.c
@@ -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
diff --git a/gdb/inf-loop.c b/gdb/inf-loop.c
index b6f8bb8..f789868 100644
--- a/gdb/inf-loop.c
+++ b/gdb/inf-loop.c
@@ -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 thing that the target is
+	 running, we'll refuse to execute most command.  MI continuation
+	 presently is 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"));
-    }
-}
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 70bf695..2ece41b 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -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.  */
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 143a29c..8a3a0a8 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -217,23 +217,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 ();
diff --git a/gdb/remote.c b/gdb/remote.c
index a5349b4..a0703e2 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7385,6 +7385,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;
diff --git a/gdb/top.c b/gdb/top.c
index 9ad2f54..7f31f6b 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -364,6 +364,43 @@ 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);
+  /*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
+    }
+}
+
 /* Execute the line P as a command.
    Pass FROM_TTY as second argument to the defining function.  */
 
@@ -374,6 +411,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 ();
 
@@ -469,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
@@ -480,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
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index 9abecd4..dcee46f 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -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 the can throw, 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.  */
-- 
1.5.3.5


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