# Copyright (C) 2016-2018 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 . # Regression test for PR threads/19461 (strange "info thread" behavior # in non-stop). GDB used to miss updating the parent/child running # states after a fork. standard_testfile # The test proper. proc do_test { detach_on_fork follow_fork non_stop schedule_multiple } { global GDBFLAGS global srcfile testfile global gdb_prompt save_vars { GDBFLAGS } { append GDBFLAGS " -ex \"set non-stop $non_stop\"" if {[prepare_for_testing "failed to prepare" \ $testfile $srcfile {debug}] == -1} { return -1 } } if ![runto_main] then { fail "can't run to main" return 0 } # If debugging with target remote, check whether the all-stop # variant of the RSP is being used. If so, we can't run the # all-stop tests. if { [target_info exists gdb_protocol] && ([target_info gdb_protocol] == "remote" || [target_info gdb_protocol] == "extended-remote")} { set test "maint show target-non-stop" gdb_test_multiple "maint show target-non-stop" $test { -re "(is|currently) on.*$gdb_prompt $" { } -re "(is|currently) off.*$gdb_prompt $" { unsupported "can't issue info threads while target is running" return 0 } } } # We want to catch "[New inferior ...]" below, to avoid sleeping. if {$detach_on_fork == "off" || $follow_fork == "child"} { gdb_test_no_output "set print inferior-events on" } gdb_test_no_output "set detach-on-fork $detach_on_fork" gdb_test_no_output "set follow-fork $follow_fork" if {$non_stop == "off"} { gdb_test_no_output "set schedule-multiple $schedule_multiple" } set test "continue &" gdb_test_multiple $test $test { -re "$gdb_prompt " { pass $test } } if {$detach_on_fork == "off" || $follow_fork == "child"} { set test "fork child appears" gdb_test_multiple "" $test { -re "\\\[New inferior " { pass $test } } } else { # All we can do is wait a little bit for the parent to fork. sleep 1 } set not_nl "\[^\r\n\]*" if {$detach_on_fork == "on" && $non_stop == "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")} { # 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 { -re "\\\(running\\\)${not_nl}\\\(running\\\)\r\n$gdb_prompt $" { fail $test } -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 $" { gdb_assert [string eq $follow_fork "child"] $test } } } # We don't want to see "Inferior exited" in reaction to the kills. gdb_test_no_output "set print inferior-events off" # Kill both parent and child. if {$detach_on_fork == "off" || $follow_fork == "parent"} { gdb_test_no_output "kill inferior 1" "kill parent" } if {$detach_on_fork == "off" || $follow_fork == "child"} { gdb_test_no_output "kill inferior 2" "kill child" } } # Exercise all permutations of: # # set detach-on-fork off|on # set follow-fork parent|child # set non-stop on|off # set schedule-multiple on|off foreach_with_prefix detach-on-fork {"off" "on"} { foreach_with_prefix follow-fork {"parent" "child"} { with_test_prefix "non-stop" { do_test ${detach-on-fork} ${follow-fork} "on" "-" } with_test_prefix "all-stop" { foreach_with_prefix schedule-multiple {"on" "off"} { do_test ${detach-on-fork} ${follow-fork} "off" ${schedule-multiple} } } } }