--- /dev/null
+# Copyright (C) 2021 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/>.
+
+# Test that we handle well, in all-stop, a fork happening in a thread B while
+# doing a step-like command in a thread A.
+#
+# A buggy GDB / GDBserver combo would notice the thread of the child process
+# of the (still unprocessed) fork event, and erroneously create a new inferior
+# for it. Once fixed, the child process' thread is hidden by whoever holds the
+# pending fork event.
+
+standard_testfile
+
+proc do_test { target-non-stop who_forks fork_function } {
+
+ set opts [list debug "additional_flags=-DFORK_FUNCTION=$fork_function"]
+
+ # WHO_FORKS says which of the main or other thread calls (v)fork. The
+ # thread that does not call (v)fork is the one who tries to step.
+ if { $who_forks == "main" } {
+ lappend opts "additional_flags=-DMAIN_THREAD_FORKS"
+ set this_binfile ${::binfile}-main-${fork_function}
+ } elseif { $who_forks == "other" } {
+ lappend opts "additional_flags=-DOTHER_THREAD_FORKS"
+ set this_binfile ${::binfile}-other-${fork_function}
+ } else {
+ error "invalid who_forks value: $who_forks"
+ }
+
+ if { [gdb_compile_pthreads "$::srcdir/$::subdir/$::srcfile" $this_binfile executable $opts] != "" } {
+ return
+ }
+
+ save_vars { ::GDBFLAGS } {
+ append ::GDBFLAGS " -ex \"maintenance set target-non-stop ${target-non-stop}\""
+ clean_restart $this_binfile
+ }
+
+ if {![runto_main]} {
+ fail "could not run to main"
+ return
+ }
+
+ # Run until breakpoint in the second thread.
+ gdb_test "break break_here" "Breakpoint $::decimal.*"
+ gdb_continue_to_breakpoint "thread started"
+
+ # Delete the breakpoint so the thread doesn't do a step-over.
+ delete_breakpoints
+
+ # Let the forking thread make progress during the step.
+ gdb_test "p release_forking_thread = 1" " = 1"
+
+ # stepi the non-forking thread.
+ gdb_test "stepi"
+
+ # Make sure there's still a single inferior.
+ gdb_test "info inferior" {\* 1 [^\r\n]+}
+}
+
+foreach_with_prefix target-non-stop { auto on off } {
+ foreach_with_prefix who_forks { main other } {
+ foreach_with_prefix fork_function { fork vfork } {
+ do_test ${target-non-stop} $who_forks $fork_function
+ }
+ }
+}