diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 370141e688..62b73fb83b 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -645,7 +645,13 @@ public:
 
   DISABLE_COPY_AND_ASSIGN (scoped_restore_current_thread);
 
+  /* Cancel restoring on scope exit.  */
+  void dont_restore () { m_dont_restore = true; }
+
 private:
+  void restore ();
+
+  bool m_dont_restore = false;
   /* Use the "class" keyword here, because of a clash with a "thread_info"
      function in the Darwin API.  */
   class thread_info *m_thread;
diff --git a/gdb/inferior.c b/gdb/inferior.c
index cf2175494d..fa1fd3fc10 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -255,6 +255,7 @@ inferior_appeared (struct inferior *inf, int pid)
 {
   /* If this is the first inferior with threads, reset the global
      thread id.  */
+  delete_exited_threads ();
   if (!any_thread_p ())
     init_thread_list ();
 
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 07aebfa678..6da95e0584 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3046,6 +3046,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
 
   finish_state.release ();
 
+  /* If we've switched threads above, switch back to the previously
+     current thread.  We don't want the user to see a different
+     selected thread.  */
+  switch_to_thread (cur_thr);
+
   /* Tell the event loop to wait for it to stop.  If the target
      supports asynchronous execution, it'll do this from within
      target_resume.  */
@@ -3700,14 +3705,11 @@ fetch_inferior_event (void *client_data)
 	set_current_traceframe (-1);
       }
 
-    gdb::optional<scoped_restore_current_thread> maybe_restore_thread;
-
-    if (non_stop)
-      /* In non-stop mode, the user/frontend should not notice a thread
-	 switch due to internal events.  Make sure we reverse to the
-	 user selected thread and frame after handling the event and
-	 running any breakpoint commands.  */
-      maybe_restore_thread.emplace ();
+    /* The user/frontend should not notice a thread switch due to
+       internal events.  Make sure we revert to the user selected
+       thread and frame after handling the event and running any
+       breakpoint commands.  */
+    scoped_restore_current_thread restore_thread;
 
     overlay_cache_invalid = 1;
     /* Flush target cache before starting to handle each event.  Target
@@ -3784,6 +3786,19 @@ fetch_inferior_event (void *client_data)
 		inferior_event_handler (INF_EXEC_COMPLETE, NULL);
 		cmd_done = 1;
 	      }
+
+	    /* If we got a TARGET_WAITKIND_NO_RESUMED event, then the
+	       previously selected thread is gone.  We have two
+	       choices - switch to no thread selected, or restore the
+	       previously selected thread (now exited).  We chose the
+	       later, just because that's what GDB used to do.  After
+	       this, "info threads" says "The current thread <Thread
+	       ID 2> has terminated." instead of "No thread
+	       selected.".  */
+	    if (!non_stop
+		&& cmd_done
+		&& ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED)
+	      restore_thread.dont_restore ();
 	  }
       }
 
diff --git a/gdb/testsuite/gdb.base/fork-running-state.exp b/gdb/testsuite/gdb.base/fork-running-state.exp
index 98733a6cc1..143b5ce714 100644
--- a/gdb/testsuite/gdb.base/fork-running-state.exp
+++ b/gdb/testsuite/gdb.base/fork-running-state.exp
@@ -98,30 +98,19 @@ proc do_test { detach_on_fork follow_fork non_stop schedule_multiple } {
 
     set not_nl "\[^\r\n\]*"
 
-    if {$detach_on_fork == "on" && $non_stop == "on" && $follow_fork == "child"} {
+    if {$detach_on_fork == "on" && $follow_fork == "child"} {
 	gdb_test "info threads" \
 	    "  2.1 ${not_nl}\\\(running\\\).*No selected thread.*"
-    } elseif {$detach_on_fork == "on" && $follow_fork == "child"} {
-	gdb_test "info threads" \
-	    "\\\* 2.1 ${not_nl}\\\(running\\\)"
     } elseif {$detach_on_fork == "on"} {
 	gdb_test "info threads" \
 	    "\\\* 1 ${not_nl}\\\(running\\\)"
-    } elseif {$non_stop == "on"
-	      || ($schedule_multiple == "on" && $follow_fork == "parent")} {
+    } elseif {$non_stop == "on" || $schedule_multiple == "on"} {
 	# Both parent and child should be marked running, and the
 	# parent should be selected.
 	gdb_test "info threads" \
 	    [multi_line \
 		 "\\\* 1.1 ${not_nl} \\\(running\\\)${not_nl}" \
 		 "  2.1 ${not_nl} \\\(running\\\)"]
-    } elseif {$schedule_multiple == "on" && $follow_fork == "child"} {
-	# Both parent and child should be marked running, and the
-	# child should be selected.
-	gdb_test "info threads" \
-	    [multi_line \
-		 "  1.1 ${not_nl} \\\(running\\\)${not_nl}" \
-		 "\\\* 2.1 ${not_nl} \\\(running\\\)"]
     } else {
 	set test "only $follow_fork marked running"
 	gdb_test_multiple "info threads" $test {
@@ -131,7 +120,7 @@ proc do_test { detach_on_fork follow_fork non_stop schedule_multiple } {
 	    -re "\\\* 1.1 ${not_nl}\\\(running\\\)\r\n  2.1 ${not_nl}\r\n$gdb_prompt $" {
 		gdb_assert [string eq $follow_fork "parent"] $test
 	    }
-	    -re "1.1 ${not_nl}\r\n\\\* 2.1 ${not_nl}\\\(running\\\)\r\n$gdb_prompt $" {
+	    -re "\\\* 1.1 ${not_nl}\r\n  2.1 ${not_nl}\\\(running\\\)\r\n$gdb_prompt $" {
 		gdb_assert [string eq $follow_fork "child"] $test
 	    }
 	}
diff --git a/gdb/testsuite/gdb.multi/tids-gid-reset.c b/gdb/testsuite/gdb.multi/tids-gid-reset.c
new file mode 100644
index 0000000000..4d3d67b8e4
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/tids-gid-reset.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2019 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.multi/tids-gid-reset.exp b/gdb/testsuite/gdb.multi/tids-gid-reset.exp
new file mode 100644
index 0000000000..e15049bfad
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/tids-gid-reset.exp
@@ -0,0 +1,96 @@
+# Copyright 2015-2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Check that letting the inferior exit and restarting it again resets
+# the global TID counter, and thus the new thread 1.1 should end up
+# with global TID == 1.
+#
+# Also, check the same but with another inferior still running, in
+# which case the new thread 1.1 should end up with global TID == 3.
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} {pthreads debug}] } {
+    return -1
+}
+
+with_test_prefix "single-inferior" {
+    with_test_prefix "before restart" {
+	clean_restart ${testfile}
+
+	if { ![runto_main] } then {
+	    return -1
+	}
+
+	gdb_test "info threads -gid" "\\* 1 +1 +.*"
+    }
+
+    with_test_prefix "restart" {
+	gdb_continue_to_end
+	if { ![runto_main] } then {
+	    return -1
+	}
+    }
+
+    with_test_prefix "after restart" {
+	gdb_test "info threads -gid" "\\* 1 +1 +.*"
+    }
+}
+
+# For the following tests, multiple inferiors are needed, therefore
+# non-extended gdbserver is not supported.
+if [use_gdb_stub] {
+    untested "using gdb stub"
+    return
+}
+
+# Test with multiple inferiors.  This time, since we restart inferior
+# 1 while inferior 2 still has threads, then the new thread 1.1 should
+# end up with GID == 3, since we won't be able to reset the global
+# thread ID counter.
+with_test_prefix "multi-inferior" {
+    gdb_test "add-inferior" "Added inferior 2.*" "add empty inferior 2"
+    gdb_test "inferior 2" "Switching to inferior 2 .*" "switch to inferior 2"
+    gdb_load ${binfile}
+
+    if ![runto_main] then {
+	fail "starting inferior 2"
+	return
+    }
+
+    gdb_test "inferior 1" "Switching to inferior 1 .*" \
+	"switch back to inferior 1"
+
+    with_test_prefix "before restart" {
+	gdb_test "info threads -gid" \
+	    [multi_line \
+		 "\\* 1\.1 +1 +.*" \
+		 "  2\.1 +2 +.*"]
+    }
+
+    with_test_prefix "restart" {
+	gdb_continue_to_end
+	if { ![runto_main] } then {
+	    return -1
+	}
+    }
+
+    with_test_prefix "after restart" {
+	gdb_test "info threads -gid" \
+	    [multi_line \
+		 "\\* 1\.1 +3 +.*" \
+		 "  2\.1 +2 +.*"]
+    }
+}
diff --git a/gdb/testsuite/gdb.threads/async.c b/gdb/testsuite/gdb.threads/async.c
new file mode 100644
index 0000000000..6bffca9c8d
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/async.c
@@ -0,0 +1,70 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2019 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#define NUM 2
+
+static pthread_barrier_t threads_started_barrier;
+
+static void *
+thread_function (void *arg)
+{
+  pthread_barrier_wait (&threads_started_barrier);
+
+  while (1)
+    {
+      /* Sleep a bit to give the other threads a chance to run.  */
+      usleep (1); /* set breakpoint here */
+    }
+
+  pthread_exit (NULL);
+}
+
+static void
+all_started (void)
+{
+}
+
+int
+main ()
+{
+  pthread_t threads[NUM];
+  long i;
+
+  pthread_barrier_init (&threads_started_barrier, NULL, NUM + 1);
+
+  for (i = 1; i <= NUM; i++)
+    {
+      int res;
+
+      res = pthread_create (&threads[i - 1],
+			    NULL,
+			    thread_function, NULL);
+    }
+
+  pthread_barrier_wait (&threads_started_barrier);
+
+  all_started ();
+
+  sleep (180);
+
+  exit (EXIT_SUCCESS);
+}
diff --git a/gdb/testsuite/gdb.threads/async.exp b/gdb/testsuite/gdb.threads/async.exp
new file mode 100644
index 0000000000..7047bef2bd
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/async.exp
@@ -0,0 +1,98 @@
+# Copyright (C) 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+standard_testfile
+
+if {[build_executable "failed to prepare" $testfile $srcfile {debug pthreads}] == -1} {
+    return -1
+}
+
+# At this point GDB will be busy handling the breakpoint hits and
+# re-resuming the program.  Even if GDB internally switches thread
+# context, the user should not notice it.  The following part of the
+# testcase ensures that.
+
+# Switch to thread EXPECTED_THR, and then confirm that the thread
+# stays selected.
+
+proc test_current_thread {expected_thr} {
+    global decimal
+    global gdb_prompt
+    global binfile
+
+    clean_restart $binfile
+
+    if {![runto "all_started"]} {
+	fail "could not run to all_started"
+	return
+    }
+
+    # Set a breakpoint that continuously fires but doeesn't cause a stop.
+    gdb_breakpoint [concat [gdb_get_line_number "set breakpoint here"] " if 0"]
+
+    gdb_test "thread $expected_thr" "Switching to thread $expected_thr .*" \
+	"switch to thread $expected_thr"
+
+    # Continue the program in the background.
+    set test "continue&"
+    gdb_test_multiple "continue&" $test {
+	-re "Continuing\\.\r\n$gdb_prompt " {
+	    pass $test
+	}
+    }
+
+    set test "current thread is $expected_thr"
+    set fails 0
+    for {set i 0} {$i < 10} {incr i} {
+	after 200
+
+	set cur_thread 0
+	gdb_test_multiple "thread" $test {
+	    -re "Current thread is ($decimal) .*$gdb_prompt " {
+		set cur_thread $expect_out(1,string)
+	    }
+	}
+
+	if {$cur_thread != $expected_thr} {
+	    incr fails
+	}
+    }
+
+    gdb_assert {$fails == 0} $test
+
+    # Explicitly interrupt the target, because in all-stop/remote,
+    # that's all we can do when the target is running.  If we don't do
+    # this, we'd time out trying to kill the target, while bringing
+    # down gdb & gdbserver.
+    set test "interrupt"
+    gdb_test_multiple $test $test {
+	-re "^interrupt\r\n$gdb_prompt " {
+	    gdb_test_multiple "" $test {
+		-re "Thread .* received signal SIGINT, Interrupt\\." {
+		    pass $test
+		}
+	    }
+	}
+    }
+}
+
+# Try once with each thread as current, to avoid missing a bug just
+# because some part of GDB manages to switch to the right thread by
+# chance.
+for {set thr 1} {$thr <= 3} {incr thr} {
+    with_test_prefix "thread $thr" {
+	test_current_thread $thr
+    }
+}
diff --git a/gdb/thread.c b/gdb/thread.c
index 17bc642b84..2f9cd87ac8 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1375,7 +1375,8 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
     }
 }
 
-scoped_restore_current_thread::~scoped_restore_current_thread ()
+void
+scoped_restore_current_thread::restore ()
 {
   /* If an entry of thread_info was previously selected, it won't be
      deleted because we've increased its refcount.  The thread represented
@@ -1402,6 +1403,22 @@ scoped_restore_current_thread::~scoped_restore_current_thread ()
       && target_has_stack
       && target_has_memory)
     restore_selected_frame (m_selected_frame_id, m_selected_frame_level);
+}
+
+scoped_restore_current_thread::~scoped_restore_current_thread ()
+{
+  if (!m_dont_restore)
+    {
+      try
+	{
+	  restore ();
+	}
+      catch (const gdb_exception &ex)
+	{
+	  /* We're in a dtor, there's really nothing else we can do
+	     but swallow the exception.  */
+	}
+    }
 
   if (m_thread != NULL)
     m_thread->decref ();
