diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index d80ee58..d3badcd 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -25,21 +25,80 @@
 #include "top.h"		/* for "execute_command" */
 #include <string.h>
 #include "exceptions.h"
-
-struct ui_out *cli_uiout;
+#include "infrun.h"
+#include "observer.h"
 
 /* These are the ui_out and the interpreter for the console
    interpreter.  */
+struct ui_out *cli_uiout;
+static struct interp *cli_interp;
 
 /* Longjmp-safe wrapper for "execute_command".  */
 static struct gdb_exception safe_execute_command (struct ui_out *uiout,
 						  char *command, 
 						  int from_tty);
+
+/* Observers for several run control events.  If the interpreter is
+   quiet (i.e., another interpreter is being run with
+   interpreter-exec), print nothing.  */
+
+/* Observer for the signal_received notification.  */
+
+static void
+cli_on_signal_received (enum gdb_signal siggnal)
+{
+  if (!interp_quiet_p (cli_interp))
+    print_signal_received_reason (cli_uiout, siggnal);
+}
+
+/* Observer for the end_stepping_range notification.  */
+
+static void
+cli_on_end_stepping_range (void)
+{
+  if (!interp_quiet_p (cli_interp))
+    print_end_stepping_range_reason (cli_uiout);
+}
+
+/* Observer for the signalled notification.  */
+
+static void
+cli_on_signal_exited (enum gdb_signal siggnal)
+{
+  if (!interp_quiet_p (cli_interp))
+    print_signal_exited_reason (cli_uiout, siggnal);
+}
+
+/* Observer for the exited notification.  */
+
+static void
+cli_on_exited (int exitstatus)
+{
+  if (!interp_quiet_p (cli_interp))
+    print_exited_reason (cli_uiout, exitstatus);
+}
+
+/* Observer for the no_history notification.  */
+
+static void
+cli_on_no_history (void)
+{
+  if (!interp_quiet_p (cli_interp))
+    print_no_history_reason (cli_uiout);
+}
+
 /* These implement the cli out interpreter: */
 
 static void *
 cli_interpreter_init (struct interp *self, int top_level)
 {
+  /* If changing this, remember to update tui-interp.c as well.  */
+  observer_attach_end_stepping_range (cli_on_end_stepping_range);
+  observer_attach_signal_received (cli_on_signal_received);
+  observer_attach_signal_exited (cli_on_signal_exited);
+  observer_attach_exited (cli_on_exited);
+  observer_attach_no_history (cli_on_no_history);
+
   return NULL;
 }
 
@@ -155,7 +214,6 @@ _initialize_cli_interp (void)
     NULL,                       /* set_logging_proc */
     cli_command_loop            /* command_loop_proc */
   };
-  struct interp *cli_interp;
 
   /* Create a default uiout builder for the CLI.  */
   cli_uiout = cli_out_new (gdb_stdout);
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index 61acbb2..ee43fc5 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -94,6 +94,26 @@ the breakpoints were are stopped at, if any.  Second argument
 inferior has stopped.
 @end deftypefun
 
+@deftypefun void signal_received (enum gdb_signal @var{siggnal})
+The inferior was stopped by a signal.
+@end deftypefun
+
+@deftypefun void end_stepping_range (void)
+We are done with a step/next/si/ni command.
+@end deftypefun
+
+@deftypefun void signal_exited (enum gdb_signal @var{siggnal})
+The inferior was terminated by a signal.
+@end deftypefun
+
+@deftypefun void exited (int @var{exitstatus})
+The inferior program is finished.
+@end deftypefun
+
+@deftypefun void no_history (void)
+Reverse execution: target ran out of history info.
+@end deftypefun
+
 @deftypefun void target_changed (struct target_ops *@var{target})
 The target's register contents have changed.
 @end deftypefun
diff --git a/gdb/infrun.c b/gdb/infrun.c
index ec78148..56846d8 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -88,15 +88,7 @@ static int currently_stepping (struct thread_info *tp);
 
 static void xdb_handle_command (char *args, int from_tty);
 
-static void print_exited_reason (int exitstatus);
-
-static void print_signal_exited_reason (enum gdb_signal siggnal);
-
-static void print_no_history_reason (void);
-
-static void print_signal_received_reason (enum gdb_signal siggnal);
-
-static void print_end_stepping_range_reason (void);
+static void end_stepping_range (void);
 
 void _initialize_infrun (void);
 
@@ -3528,7 +3520,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 	  /* Support the --return-child-result option.  */
 	  return_child_result_value = ecs->ws.value.integer;
 
-	  print_exited_reason (ecs->ws.value.integer);
+	  observer_notify_exited (ecs->ws.value.integer);
 	}
       else
 	{
@@ -3557,7 +3549,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 Cannot fill $_exitsignal with the correct signal number.\n"));
 	    }
 
-	  print_signal_exited_reason (ecs->ws.value.sig);
+	  observer_notify_signal_exited (ecs->ws.value.sig);
 	}
 
       gdb_flush (gdb_stdout);
@@ -3825,7 +3817,7 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
 	  singlestep_breakpoints_inserted_p = 0;
 	}
       stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
-      print_no_history_reason ();
+      observer_notify_no_history ();
       stop_stepping (ecs);
       return;
     }
@@ -4213,10 +4205,10 @@ handle_signal_stop (struct execution_control_state *ecs)
 
       if (signal_print[ecs->event_thread->suspend.stop_signal])
 	{
+	  /* The signal table tells us to print about this signal.  */
 	  printed = 1;
 	  target_terminal_ours_for_output ();
-	  print_signal_received_reason
-				     (ecs->event_thread->suspend.stop_signal);
+	  observer_notify_signal_received (ecs->event_thread->suspend.stop_signal);
 	}
       /* Always stop on signals if we're either just gaining control
 	 of the program, or the user explicitly requested this thread
@@ -4460,7 +4452,7 @@ process_event_stop_test (struct execution_control_state *ecs)
 	delete_step_resume_breakpoint (ecs->event_thread);
 
 	ecs->event_thread->control.stop_step = 1;
-	print_end_stepping_range_reason ();
+	end_stepping_range ();
 	stop_stepping (ecs);
       }
       return;
@@ -4625,7 +4617,7 @@ process_event_stop_test (struct execution_control_state *ecs)
 	  && execution_direction == EXEC_REVERSE)
 	{
 	  ecs->event_thread->control.stop_step = 1;
-	  print_end_stepping_range_reason ();
+	  end_stepping_range ();
 	  stop_stepping (ecs);
 	}
       else
@@ -4779,7 +4771,7 @@ process_event_stop_test (struct execution_control_state *ecs)
 	     well.  FENN */
 	  /* And this works the same backward as frontward.  MVS */
 	  ecs->event_thread->control.stop_step = 1;
-	  print_end_stepping_range_reason ();
+	  end_stepping_range ();
 	  stop_stepping (ecs);
 	  return;
 	}
@@ -4895,7 +4887,7 @@ process_event_stop_test (struct execution_control_state *ecs)
 	  && step_stop_if_no_debug)
 	{
 	  ecs->event_thread->control.stop_step = 1;
-	  print_end_stepping_range_reason ();
+	  end_stepping_range ();
 	  stop_stepping (ecs);
 	  return;
 	}
@@ -4991,7 +4983,7 @@ process_event_stop_test (struct execution_control_state *ecs)
 	     is set, we stop the step so that the user has a chance to
 	     switch in assembly mode.  */
 	  ecs->event_thread->control.stop_step = 1;
-	  print_end_stepping_range_reason ();
+	  end_stepping_range ();
 	  stop_stepping (ecs);
 	  return;
 	}
@@ -5012,7 +5004,7 @@ process_event_stop_test (struct execution_control_state *ecs)
       if (debug_infrun)
 	 fprintf_unfiltered (gdb_stdlog, "infrun: stepi/nexti\n");
       ecs->event_thread->control.stop_step = 1;
-      print_end_stepping_range_reason ();
+      end_stepping_range ();
       stop_stepping (ecs);
       return;
     }
@@ -5026,7 +5018,7 @@ process_event_stop_test (struct execution_control_state *ecs)
       if (debug_infrun)
 	 fprintf_unfiltered (gdb_stdlog, "infrun: no line number info\n");
       ecs->event_thread->control.stop_step = 1;
-      print_end_stepping_range_reason ();
+      end_stepping_range ();
       stop_stepping (ecs);
       return;
     }
@@ -5059,7 +5051,7 @@ process_event_stop_test (struct execution_control_state *ecs)
 	    step_into_inline_frame (ecs->ptid);
 
 	  ecs->event_thread->control.stop_step = 1;
-	  print_end_stepping_range_reason ();
+	  end_stepping_range ();
 	  stop_stepping (ecs);
 	  return;
 	}
@@ -5074,7 +5066,7 @@ process_event_stop_test (struct execution_control_state *ecs)
 	  else
 	    {
 	      ecs->event_thread->control.stop_step = 1;
-	      print_end_stepping_range_reason ();
+	      end_stepping_range ();
 	      stop_stepping (ecs);
 	    }
 	  return;
@@ -5101,7 +5093,7 @@ process_event_stop_test (struct execution_control_state *ecs)
       else
 	{
 	  ecs->event_thread->control.stop_step = 1;
-	  print_end_stepping_range_reason ();
+	  end_stepping_range ();
 	  stop_stepping (ecs);
 	}
       return;
@@ -5119,7 +5111,7 @@ process_event_stop_test (struct execution_control_state *ecs)
 	 fprintf_unfiltered (gdb_stdlog,
 			     "infrun: stepped to a different line\n");
       ecs->event_thread->control.stop_step = 1;
-      print_end_stepping_range_reason ();
+      end_stepping_range ();
       stop_stepping (ecs);
       return;
     }
@@ -5445,7 +5437,7 @@ handle_step_into_function (struct gdbarch *gdbarch,
     {
       /* We are already there: stop now.  */
       ecs->event_thread->control.stop_step = 1;
-      print_end_stepping_range_reason ();
+      end_stepping_range ();
       stop_stepping (ecs);
       return;
     }
@@ -5494,7 +5486,7 @@ handle_step_into_function_backward (struct gdbarch *gdbarch,
     {
       /* We're there already.  Just stop stepping now.  */
       ecs->event_thread->control.stop_step = 1;
-      print_end_stepping_range_reason ();
+      end_stepping_range ();
       stop_stepping (ecs);
     }
   else
@@ -5894,6 +5886,20 @@ prepare_to_wait (struct execution_control_state *ecs)
   ecs->wait_some_more = 1;
 }
 
+/* We are done with the step range of a step/next/si/ni command.
+   Called once for each n of a "step n" operation.  Notify observers
+   if not in the middle of doing a "step N" operation for N > 1.  */
+
+static void
+end_stepping_range (void)
+{
+  if (inferior_thread ()->step_multi
+      && inferior_thread ()->control.stop_step)
+    return;
+
+  observer_notify_end_stepping_range ();
+}
+
 /* Several print_*_reason functions to print why the inferior has stopped.
    We always print something when the inferior exits, or receives a signal.
    The rest of the cases are dealt with later on in normal_stop and
@@ -5901,28 +5907,21 @@ prepare_to_wait (struct execution_control_state *ecs)
    print_*_reason functions functions from handle_inferior_event each time
    stop_stepping is called.  */
 
-/* Print why the inferior has stopped.  
-   We are done with a step/next/si/ni command, print why the inferior has
-   stopped.  For now print nothing.  Print a message only if not in the middle
-   of doing a "step n" operation for n > 1.  */
-
-static void
-print_end_stepping_range_reason (void)
+void
+print_end_stepping_range_reason (struct ui_out *uiout)
 {
-  if ((!inferior_thread ()->step_multi
-       || !inferior_thread ()->control.stop_step)
-      && ui_out_is_mi_like_p (current_uiout))
-    ui_out_field_string (current_uiout, "reason",
-                         async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE));
-}
+  /* For CLI-like interpreters, print nothing.  */
 
-/* The inferior was terminated by a signal, print why it stopped.  */
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_string (uiout, "reason",
+			   async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE));
+    }
+}
 
-static void
-print_signal_exited_reason (enum gdb_signal siggnal)
+void
+print_signal_exited_reason (struct ui_out *uiout, enum gdb_signal siggnal)
 {
-  struct ui_out *uiout = current_uiout;
-
   annotate_signalled ();
   if (ui_out_is_mi_like_p (uiout))
     ui_out_field_string
@@ -5941,14 +5940,11 @@ print_signal_exited_reason (enum gdb_signal siggnal)
   ui_out_text (uiout, "The program no longer exists.\n");
 }
 
-/* The inferior program is finished, print why it stopped.  */
-
-static void
-print_exited_reason (int exitstatus)
+void
+print_exited_reason (struct ui_out *uiout, int exitstatus)
 {
   struct inferior *inf = current_inferior ();
   const char *pidstr = target_pid_to_str (pid_to_ptid (inf->pid));
-  struct ui_out *uiout = current_uiout;
 
   annotate_exited (exitstatus);
   if (exitstatus)
@@ -5977,14 +5973,9 @@ print_exited_reason (int exitstatus)
     }
 }
 
-/* Signal received, print why the inferior has stopped.  The signal table
-   tells us to print about it.  */
-
-static void
-print_signal_received_reason (enum gdb_signal siggnal)
+void
+print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
 {
-  struct ui_out *uiout = current_uiout;
-
   annotate_signal ();
 
   if (siggnal == GDB_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))
@@ -6016,13 +6007,10 @@ print_signal_received_reason (enum gdb_signal siggnal)
   ui_out_text (uiout, ".\n");
 }
 
-/* Reverse execution: target ran out of history info, print why the inferior
-   has stopped.  */
-
-static void
-print_no_history_reason (void)
+void
+print_no_history_reason (struct ui_out *uiout)
 {
-  ui_out_text (current_uiout, "\nNo more reverse-execution history.\n");
+  ui_out_text (uiout, "\nNo more reverse-execution history.\n");
 }
 
 /* Print current location without a level number, if we have changed
diff --git a/gdb/infrun.h b/gdb/infrun.h
index f0649f3..47509d9 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -120,6 +120,29 @@ extern int stepping_past_instruction_at (struct address_space *aspace,
 extern void set_step_info (struct frame_info *frame,
 			   struct symtab_and_line sal);
 
+/* Several print_*_reason helper functions to print why the inferior
+   has stopped to the passed in UIOUT.  The interpreters call
+   these.  */
+
+/* Signal received, print why the inferior has stopped.  */
+extern void print_signal_received_reason (struct ui_out *uiout,
+					  enum gdb_signal siggnal);
+
+/* Print why the inferior has stopped.  We are done with a
+   step/next/si/ni command, print why the inferior has stopped.  */
+extern void print_end_stepping_range_reason (struct ui_out *uiout);
+
+/* The inferior was terminated by a signal, print why it stopped.  */
+extern void print_signal_exited_reason (struct ui_out *uiout,
+					enum gdb_signal siggnal);
+
+/* The inferior program is finished, print why it stopped.  */
+extern void print_exited_reason (struct ui_out *uiout, int exitstatus);
+
+/* Reverse execution: target ran out of history info, print why the
+   inferior has stopped.  */
+extern void print_no_history_reason (struct ui_out *uiout);
+
 extern void print_stop_event (struct target_waitstatus *ws);
 
 extern int signal_stop_state (int);
diff --git a/gdb/mi/mi-common.h b/gdb/mi/mi-common.h
index a6b0103..71e5d78 100644
--- a/gdb/mi/mi-common.h
+++ b/gdb/mi/mi-common.h
@@ -58,7 +58,10 @@ struct mi_interp
   struct ui_file *event_channel;
 
   /* MI's builder.  */
-  struct ui_out *uiout;
+  struct ui_out *mi_uiout;
+
+  /* MI's CLI builder (wraps OUT).  */
+  struct ui_out *cli_uiout;
 
   /* This is the interpreter for the mi... */
   struct interp *mi2_interp;
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 99479cc..e8e30e2 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -56,7 +56,13 @@ static int mi_interp_query_hook (const char *ctlstr, va_list ap)
 
 static void mi_insert_notify_hooks (void);
 static void mi_remove_notify_hooks (void);
+
+static void mi_on_signal_received (enum gdb_signal siggnal);
+static void mi_on_end_stepping_range (void);
+static void mi_on_signal_exited (enum gdb_signal siggnal);
+static void mi_on_exited (int exitstatus);
 static void mi_on_normal_stop (struct bpstats *bs, int print_frame);
+static void mi_on_no_history (void);
 
 static void mi_new_thread (struct thread_info *t);
 static void mi_thread_exit (struct thread_info *t, int silent);
@@ -118,7 +124,16 @@ mi_interpreter_init (struct interp *interp, int top_level)
   else
     gdb_assert_not_reached ("unhandled MI version");
 
-  mi->uiout = mi_out_new (mi_version);
+  mi->mi_uiout = mi_out_new (mi_version);
+  mi->cli_uiout = cli_out_new (mi->out);
+
+  /* There are installed even if MI is not the top level interpreter.
+     The callbacks themselves decide whether to be skipped.  */
+  observer_attach_signal_received (mi_on_signal_received);
+  observer_attach_end_stepping_range (mi_on_end_stepping_range);
+  observer_attach_signal_exited (mi_on_signal_exited);
+  observer_attach_exited (mi_on_exited);
+  observer_attach_no_history (mi_on_no_history);
 
   if (top_level)
     {
@@ -431,14 +446,111 @@ restore_current_uiout_cleanup (void *arg)
   current_uiout = saved_uiout;
 }
 
-/* Cleanup that destroys the a ui_out object.  */
+/* Return the MI interpreter, if it is active -- either because it's
+   the top-level interpreter or the interpreter executing the current
+   command.  Returns NULL if the MI interpreter is not being used.  */
+
+static struct interp *
+find_mi_interpreter (void)
+{
+  struct interp *interp;
+
+  interp = top_level_interpreter ();
+  if (ui_out_is_mi_like_p (interp_ui_out (interp)))
+    return interp;
+
+  interp = command_interp ();
+  if (ui_out_is_mi_like_p (interp_ui_out (interp)))
+    return interp;
+
+  return NULL;
+}
+
+/* Return the MI_INTERP structure of the active MI interpreter.
+   Returns NULL if MI is not active.  */
+
+static struct mi_interp *
+mi_interp_data (void)
+{
+  struct interp *interp = find_mi_interpreter ();
+
+  if (interp != NULL)
+    return interp_data (interp);
+  return NULL;
+}
+
+/* Observers for several run control events that print why the
+   inferior has stopped to both the the MI event channel and to the MI
+   console.  If the MI interpreter is not active, print nothing.  */
+
+/* Observer for the signal_received notification.  */
+
+static void
+mi_on_signal_received (enum gdb_signal siggnal)
+{
+  struct mi_interp *mi = mi_interp_data ();
+
+  if (mi == NULL)
+    return;
+
+  print_signal_received_reason (mi->mi_uiout, siggnal);
+  print_signal_received_reason (mi->cli_uiout, siggnal);
+}
+
+/* Observer for the end_stepping_range notification.  */
+
+static void
+mi_on_end_stepping_range (void)
+{
+  struct mi_interp *mi = mi_interp_data ();
+
+  if (mi == NULL)
+    return;
+
+  print_end_stepping_range_reason (mi->mi_uiout);
+  print_end_stepping_range_reason (mi->cli_uiout);
+}
+
+/* Observer for the signal_exited notification.  */
 
 static void
-ui_out_free_cleanup (void *arg)
+mi_on_signal_exited (enum gdb_signal siggnal)
 {
-  struct ui_out *uiout = arg;
+  struct mi_interp *mi = mi_interp_data ();
 
-  ui_out_destroy (uiout);
+  if (mi == NULL)
+    return;
+
+  print_signal_exited_reason (mi->mi_uiout, siggnal);
+  print_signal_exited_reason (mi->cli_uiout, siggnal);
+}
+
+/* Observer for the exited notification.  */
+
+static void
+mi_on_exited (int exitstatus)
+{
+  struct mi_interp *mi = mi_interp_data ();
+
+  if (mi == NULL)
+    return;
+
+  print_exited_reason (mi->mi_uiout, exitstatus);
+  print_exited_reason (mi->cli_uiout, exitstatus);
+}
+
+/* Observer for the no_history notification.  */
+
+static void
+mi_on_no_history (void)
+{
+  struct mi_interp *mi = mi_interp_data ();
+
+  if (mi == NULL)
+    return;
+
+  print_no_history_reason (mi->mi_uiout);
+  print_no_history_reason (mi->cli_uiout);
 }
 
 static void
@@ -506,16 +618,12 @@ mi_on_normal_stop (struct bpstats *bs, int print_frame)
 	      struct mi_interp *mi = top_level_interpreter_data ();
 	      struct target_waitstatus last;
 	      ptid_t last_ptid;
-	      struct ui_out *cli_uiout;
 	      struct cleanup *old_chain;
 
-	      /* Sets the current uiout to a new temporary CLI uiout
-		 assigned to STREAM.  */
-	      cli_uiout = cli_out_new (mi->out);
-	      old_chain = make_cleanup (ui_out_free_cleanup, cli_uiout);
-
-	      make_cleanup (restore_current_uiout_cleanup, current_uiout);
-	      current_uiout = cli_uiout;
+	      /* Set the current uiout to CLI uiout temporarily.  */
+	      old_chain = make_cleanup (restore_current_uiout_cleanup,
+					current_uiout);
+	      current_uiout = mi->cli_uiout;
 
 	      get_last_target_status (&last_ptid, &last);
 	      print_stop_event (&last);
@@ -972,7 +1080,7 @@ mi_ui_out (struct interp *interp)
 {
   struct mi_interp *mi = interp_data (interp);
 
-  return mi->uiout;
+  return mi->mi_uiout;
 }
 
 /* Save the original value of raw_stdout here when logging, so we can
diff --git a/gdb/testsuite/gdb.mi/mi-cli.exp b/gdb/testsuite/gdb.mi/mi-cli.exp
index 81f8898..107a579 100644
--- a/gdb/testsuite/gdb.mi/mi-cli.exp
+++ b/gdb/testsuite/gdb.mi/mi-cli.exp
@@ -136,22 +136,7 @@ mi_gdb_test "500-stack-select-frame 0" \
   {500\^done} \
   "-stack-select-frame 0"
 
-# When a CLI command is entered in MI session, the respose is different in
-# sync and async modes. In sync mode normal_stop is called when current
-# interpreter is CLI. So:
-#   - print_stop_reason prints stop reason in CLI uiout, and we don't show it
-#     in MI
-#   - The stop position is printed, and appears in MI 'console' channel.
-#
-# In async mode the stop event is processed when we're back to MI interpreter,
-# so the stop reason is printed into MI uiout an.
-if {$async} {
-    set reason "end-stepping-range"
-} else {
-    set reason ""
-}
-
-mi_execute_to "interpreter-exec console step" $reason "callee4" "" ".*basics.c" $line_callee4_next \
+mi_execute_to "interpreter-exec console step" "end-stepping-range" "callee4" "" ".*basics.c" $line_callee4_next \
     "" "check *stopped from CLI command"
 
 mi_send_resuming_command "exec-step" "-exec-step to line \$line_callee4_next_step"
@@ -212,11 +197,7 @@ gdb_expect {
     }
 }
 
-# Note that the output does not include stop reason. This is fine.
-# The purpose of *stopped notification for CLI command is to make
-# sure that frontend knows that inferior is stopped, and knows where.
-# Supplementary information is not necessary.
-mi_expect_stop "$reason" "main" "" ".*basics.c" $line_main_return "" \
+mi_expect_stop "end-stepping-range" "main" "" ".*basics.c" $line_main_return "" \
     "34 next: stop"
 
 mi_gdb_test "-interpreter-exec console \"list\"" \
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index 2958972..cd11148 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -30,11 +30,18 @@
 #include "tui/tui.h"
 #include "tui/tui-io.h"
 #include "exceptions.h"
+#include "infrun.h"
+#include "observer.h"
+
+static struct ui_out *tui_ui_out (struct interp *self);
 
 /* Set to 1 when the TUI mode must be activated when we first start
    gdb.  */
 static int tui_start_enabled = 0;
 
+/* The TUI interpreter.  */
+static struct interp *tui_interp;
+
 /* Cleanup the tui before exiting.  */
 
 static void
@@ -48,6 +55,55 @@ tui_exit (void)
 /* True if TUI is the top-level interpreter.  */
 static int tui_is_toplevel = 0;
 
+/* Observers for several run control events.  If the interpreter is
+   quiet (i.e., another interpreter is being run with
+   interpreter-exec), print nothing.  */
+
+/* Observer for the signal_received notification.  */
+
+static void
+tui_on_signal_received (enum gdb_signal siggnal)
+{
+  if (!interp_quiet_p (tui_interp))
+    print_signal_received_reason (tui_ui_out (tui_interp), siggnal);
+}
+
+/* Observer for the end_stepping_range notification.  */
+
+static void
+tui_on_end_stepping_range (void)
+{
+  if (!interp_quiet_p (tui_interp))
+    print_end_stepping_range_reason (tui_ui_out (tui_interp));
+}
+
+/* Observer for the signal_exited notification.  */
+
+static void
+tui_on_signal_exited (enum gdb_signal siggnal)
+{
+  if (!interp_quiet_p (tui_interp))
+    print_signal_exited_reason (tui_ui_out (tui_interp), siggnal);
+}
+
+/* Observer for the exited notification.  */
+
+static void
+tui_on_exited (int exitstatus)
+{
+  if (!interp_quiet_p (tui_interp))
+    print_exited_reason (tui_ui_out (tui_interp), exitstatus);
+}
+
+/* Observer for the no_history notification.  */
+
+static void
+tui_on_no_history (void)
+{
+  if (!interp_quiet_p (tui_interp))
+    print_no_history_reason (tui_ui_out (tui_interp));
+}
+
 /* These implement the TUI interpreter.  */
 
 static void *
@@ -65,6 +121,13 @@ tui_init (struct interp *self, int top_level)
   if (ui_file_isatty (gdb_stdout))
     tui_initialize_readline ();
 
+  /* If changing this, remember to update cli-interp.c as well.  */
+  observer_attach_signal_received (tui_on_signal_received);
+  observer_attach_end_stepping_range (tui_on_end_stepping_range);
+  observer_attach_signal_exited (tui_on_signal_exited);
+  observer_attach_exited (tui_on_exited);
+  observer_attach_no_history (tui_on_no_history);
+
   return NULL;
 }
 
@@ -156,7 +219,6 @@ _initialize_tui_interp (void)
     NULL,
     cli_command_loop
   };
-  struct interp *tui_interp;
 
   /* Create a default uiout builder for the TUI.  */
   tui_interp = interp_new (INTERP_TUI, &procs);
