# Copyright (C) 2014-2015 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 . # Test that GDB in non-stop mode gives roughly equal priority to # events of all threads. standard_testfile set executable ${testfile} if [target_info exists gdb,nosignals] { verbose "Skipping ${testfile}.exp because of nosignals." return -1 } set options { "additional_flags=-DTIMEOUT=$timeout" debug pthreads } if {[prepare_for_testing "failed to prepare" $testfile $srcfile $options] == -1} { return -1 } gdb_test_no_output "set non-stop on" if ![runto_main] { return -1 } # We want "handle print", to make sure the target backend reports the # signal to the run control core. gdb_test "handle SIGUSR1 print nostop pass" "" # Get current value of VAR from the inferior. TEST is used as test # message. proc get_value {var test} { global expect_out global gdb_prompt global decimal set value -1 gdb_test_multiple "print $var" "$test" { -re ".*= ($decimal).*\r\n$gdb_prompt $" { set value $expect_out(1,string) pass "$test" } } return ${value} } set NUM_THREADS [get_value "num_threads" "get num_threads"] # Account for the main thread. incr NUM_THREADS # Run threads to their start positions. This prepares for a new test # sequence. proc restart {} { global gdb_prompt global NUM_THREADS delete_breakpoints gdb_test "print got_sig = 0" " = 0" gdb_breakpoint [gdb_get_line_number "set thread breakpoint here"] gdb_breakpoint [gdb_get_line_number "set kill breakpoint here"] set test "continue -a&" gdb_test_multiple $test $test { -re "Continuing.\r\n$gdb_prompt " { pass $test } } for {set i 1} { $i <= $NUM_THREADS } { incr i } { set test "thread $i restarted" gdb_test_multiple "" $test { -re "breakpoint here" { # The prompt was already matched in the "continue &" # test above. We're now consuming asynchronous output # that comes after the prompt. pass $test } } } delete_breakpoints } # The test proper. SIGNAL_THREAD is the thread that has been elected # to receive the SIGUSR1 signal. proc test {signal_thread} { global gdb_prompt global NUM_THREADS with_test_prefix "signal_thread=$signal_thread" { restart # Set all threads stepping the infinite loop line in parallel. for {set i 2} { $i <= $NUM_THREADS } { incr i } { gdb_test "thread $i" \ "child_function.*set thread breakpoint here.*" \ "switch to thread $i to step it" if {$i == $signal_thread} { gdb_test "print signal_thread = self" " = .*" } gdb_test "step&" "" "set $i thread stepping" } gdb_test "thread 1" "Switching to .*" \ "switch to the main thread to queue signal" # Let the main thread queue the signal. gdb_breakpoint "loop_broke" set test "continue &" gdb_test_multiple $test $test { -re "Continuing.\r\n$gdb_prompt " { pass $test } } # Wait for all threads to finish their steps, and for the main # thread to hit the breakpoint. for {set i 1} { $i <= $NUM_THREADS } { incr i } { set test "thread $i broke out of loop" gdb_test_multiple "" $test { -re "loop_broke" { # The prompt was already matched in the "continue # &" test above. We're now consuming asynchronous # output that comes after the prompt. pass $test } } } # It's helpful to have this in the log if the test ever # happens to fail. gdb_test "info threads" } } # The kernel/debug API may always walk its thread list looking for the # first with an event, resulting in giving priority to e.g. the thread # with lowest kernel thread ID. So test once with the signal pending # in each thread, except the main thread. for {set i 2} { $i <= $NUM_THREADS } { incr i } { test $i }