diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index c14bb49..e805c11 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -473,6 +473,8 @@ show_always_inserted_mode (struct ui_file *file, int from_tty,
 		    value);
 }
 
+/* See breakpoint.h.  */
+
 int
 breakpoints_should_be_inserted_now (void)
 {
@@ -485,8 +487,6 @@ breakpoints_should_be_inserted_now (void)
     }
   else if (target_has_execution)
     {
-      struct thread_info *tp;
-
       if (always_inserted_mode)
 	{
 	  /* The user wants breakpoints inserted even if all threads
@@ -494,11 +494,8 @@ breakpoints_should_be_inserted_now (void)
 	  return 1;
 	}
 
-      ALL_NON_EXITED_THREADS (tp)
-        {
-	  if (tp->executing)
-	    return 1;
-	}
+      if (threads_are_executing ())
+	return 1;
     }
   return 0;
 }
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index e191c10..d65405f 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1491,6 +1491,16 @@ extern void breakpoint_xfer_memory (gdb_byte *readbuf, gdb_byte *writebuf,
 				    const gdb_byte *writebuf_org,
 				    ULONGEST memaddr, LONGEST len);
 
+/* Return true if breakpoints should be inserted now.  That'll be the
+   case if either:
+
+    - the target has global breakpoints.
+
+    - "breakpoint always-inserted" is on, and the target has
+      execution.
+
+    - threads are executing.
+*/
 extern int breakpoints_should_be_inserted_now (void);
 
 /* Called each time new event from target is processed.
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 6768491..26ca925 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -381,6 +381,9 @@ extern void set_executing (ptid_t ptid, int executing);
 /* Reports if thread PTID is executing.  */
 extern int is_executing (ptid_t ptid);
 
+/* True if any (known or unknown) thread is or may be executing.  */
+extern int threads_are_executing (void);
+
 /* Merge the executing property of thread PTID over to its thread
    state property (frontend running/stopped view).
 
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 3725f2d..52997f1 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -4196,13 +4196,6 @@ handle_signal_stop (struct execution_control_state *ecs)
 
       stopped_by_random_signal = 1;
 
-      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 ();
-	  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
 	 to remain stopped.  */
@@ -4214,10 +4207,17 @@ handle_signal_stop (struct execution_control_state *ecs)
 	  stop_waiting (ecs);
 	  return;
 	}
-      /* If not going to stop, give terminal back
-         if we took it away.  */
-      else if (printed)
-	target_terminal_inferior ();
+
+      /* Notify observers the signal has "handle print" set.  Note we
+	 returned early above if stopping; normal_stop handles the
+	 printing in that case.  */
+      if (signal_print[ecs->event_thread->suspend.stop_signal])
+	{
+	  /* The signal table tells us to print about this signal.  */
+	  target_terminal_ours_for_output ();
+	  observer_notify_signal_received (ecs->event_thread->suspend.stop_signal);
+	  target_terminal_inferior ();
+	}
 
       /* Clear the signal if it should not be passed.  */
       if (signal_program[ecs->event_thread->suspend.stop_signal] == 0)
@@ -5852,15 +5852,12 @@ prepare_to_wait (struct execution_control_state *ecs)
 }
 
 /* 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.  */
+   Called once for each n of a "step n" operation.  */
 
 static void
 end_stepping_range (struct execution_control_state *ecs)
 {
   ecs->event_thread->control.stop_step = 1;
-  if (!ecs->event_thread->step_multi)
-    observer_notify_end_stepping_range ();
   stop_waiting (ecs);
 }
 
@@ -6071,6 +6068,19 @@ normal_stop (void)
 	   && last.kind != TARGET_WAITKIND_NO_RESUMED)
     make_cleanup (finish_thread_state_cleanup, &inferior_ptid);
 
+  /* As we're presenting a stop, and potentially removing breakpoints,
+     update the thread list so we can tell whether there are threads
+     running on the target.  With target remote, for example, we can
+     only learn about new threads when we explicitly update the thread
+     list.  Do this before notifying the interpreters about signal
+     stops, end of stepping ranges, etc., so that the "new thread"
+     output is emitted before e.g., "Program received signal FOO",
+     instead of after.  */
+  update_thread_list ();
+
+  if (last.kind == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
+    observer_notify_signal_received (inferior_thread ()->suspend.stop_signal);
+
   /* As with the notification of thread events, we want to delay
      notifying the user that we've switched thread context until
      the inferior actually stops.
@@ -6109,6 +6119,7 @@ normal_stop (void)
       printf_filtered (_("No unwaited-for children left.\n"));
     }
 
+  /* Note: this depends on the update_thread_list call above.  */
   if (!breakpoints_should_be_inserted_now () && target_has_execution)
     {
       if (remove_breakpoints ())
@@ -6126,14 +6137,19 @@ normal_stop (void)
   if (stopped_by_random_signal)
     disable_current_display ();
 
-  /* Don't print a message if in the middle of doing a "step n"
-     operation for n > 1 */
+  /* Notify observers if we finished a "step"-like command, etc.  */
   if (target_has_execution
       && last.kind != TARGET_WAITKIND_SIGNALLED
       && last.kind != TARGET_WAITKIND_EXITED
-      && inferior_thread ()->step_multi
       && inferior_thread ()->control.stop_step)
-    goto done;
+    {
+      /* But not if if in the middle of doing a "step n" operation for
+	 n > 1 */
+      if (inferior_thread ()->step_multi)
+	goto done;
+
+      observer_notify_end_stepping_range ();
+    }
 
   target_terminal_ours ();
   async_enable_stdin ();
diff --git a/gdb/testsuite/gdb.threads/break-while-running.exp b/gdb/testsuite/gdb.threads/break-while-running.exp
index 690d6ab..ea28bf0 100644
--- a/gdb/testsuite/gdb.threads/break-while-running.exp
+++ b/gdb/testsuite/gdb.threads/break-while-running.exp
@@ -28,11 +28,13 @@ if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug pthreads}
     return -1
 }
 
-# The test proper.  NON_STOP indicates whether we're testing in
-# non-stop, or all-stop mode.  ALWAYS_INSERTED indicates whether
-# testing in "breakpoint always-inserted" mode.
+# The test proper.  UPDATE_THREAD_LIST indicates whether we should do
+# an "info threads" to sync the thread list after the first stop.
+# ALWAYS_INSERTED indicates whether testing in "breakpoint
+# always-inserted" mode.  NON_STOP indicates whether we're testing in
+# non-stop, or all-stop mode.
 
-proc test { always_inserted non_stop } {
+proc test { update_thread_list always_inserted non_stop } {
     global srcfile binfile
     global gdb_prompt
     global decimal
@@ -70,9 +72,15 @@ proc test { always_inserted non_stop } {
 	gdb_test "thread 1" "Switching to .*" "switch back to main thread"
     }
 
-    gdb_test "info threads" \
-	"\\\(running\\\).*\\\(running\\\).* main .*" \
-	"only main stopped"
+    # Test with and without pulling the thread list explicitly with
+    # "info threads".  GDB should be able to figure out itself whether
+    # the target is running and thus breakpoints should be inserted,
+    # without the user explicitly fetching the thread list.
+    if {$update_thread_list} {
+	gdb_test "info threads" \
+	    "\\\(running\\\).*\\\(running\\\).* main .*" \
+	    "only main stopped"
+    }
 
     # Don't use gdb_test as it's racy in this case -- gdb_test matches
     # the prompt with an end anchor.  Sometimes expect will manage to
@@ -141,11 +149,14 @@ proc test { always_inserted non_stop } {
     }
 }
 
-foreach always_inserted { "off" "on" } {
-    foreach non_stop { "off" "on" } {
-	set stop_mode [expr ($non_stop=="off")?"all-stop":"non-stop"]
-	with_test_prefix "always-inserted $always_inserted: $stop_mode" {
-	    test $always_inserted $non_stop
+foreach update_thread_list { true false } {
+    foreach always_inserted { "off" "on" } {
+	foreach non_stop { "off" "on" } {
+	    set stop_mode [expr ($non_stop=="off")?"all-stop":"non-stop"]
+	    set update_list_mode [expr ($update_thread_list)?"w/ithr":"wo/ithr"]
+	    with_test_prefix "$update_list_mode: always-inserted $always_inserted: $stop_mode" {
+		test $update_thread_list $always_inserted $non_stop
+	    }
 	}
     }
 }
diff --git a/gdb/thread.c b/gdb/thread.c
index bceaf49..ac1d8a1 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -56,6 +56,13 @@ void _initialize_thread (void);
 struct thread_info *thread_list = NULL;
 static int highest_thread_num;
 
+/* True if any thread is, or may be executing.  We need to track this
+   separately because until we fully sync the thread list, we won't
+   know whether the target is fully stopped, even if we see stop
+   events for all known threads, because any of those threads may have
+   spawned new threads we haven't heard of yet.  */
+static int threads_executing;
+
 static void thread_command (char *tidstr, int from_tty);
 static void thread_apply_all_command (char *, int);
 static int thread_alive (struct thread_info *);
@@ -167,6 +174,7 @@ init_thread_list (void)
     }
 
   thread_list = NULL;
+  threads_executing = 0;
 }
 
 /* Allocate a new thread with target id PTID and add it to the thread
@@ -702,6 +710,22 @@ set_executing (ptid_t ptid, int executing)
       gdb_assert (tp);
       tp->executing = executing;
     }
+
+  /* It only takes one running thread to spawn more threads.*/
+  if (executing)
+    threads_executing = 1;
+  /* Only clear the flag if the caller is telling us everything is
+     stopped.  */
+  else if (ptid_equal (minus_one_ptid, ptid))
+    threads_executing = 0;
+}
+
+/* See gdbthread.h.  */
+
+int
+threads_are_executing (void)
+{
+  return threads_executing;
 }
 
 void
@@ -1501,11 +1525,31 @@ gdb_thread_select (struct ui_out *uiout, char *tidstr, char **error_message)
   return GDB_RC_OK;
 }
 
+/* Update the 'threads_executing' global based on the threads we know
+   about right now.  */
+
+static void
+update_threads_executing (void)
+{
+  struct thread_info *tp;
+
+  threads_executing = 0;
+  ALL_NON_EXITED_THREADS (tp)
+    {
+      if (tp->executing)
+	{
+	  threads_executing = 1;
+	  break;
+	}
+    }
+}
+
 void
 update_thread_list (void)
 {
   prune_threads ();
   target_find_new_threads ();
+  update_threads_executing ();
 }
 
 /* Return a new value for the selected thread's id.  Return a value of 0 if
