1# Copyright (C) 2014-2019 Free Software Foundation, Inc. 2 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 3 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16# Test that GDB in non-stop mode gives roughly equal priority to 17# events of all threads. 18 19standard_testfile 20set executable ${testfile} 21 22if [target_info exists gdb,nosignals] { 23 verbose "Skipping ${testfile}.exp because of nosignals." 24 return -1 25} 26 27set options { "additional_flags=-DTIMEOUT=$timeout" debug pthreads } 28if {[prepare_for_testing "failed to prepare" $testfile $srcfile $options] == -1} { 29 return -1 30} 31 32gdb_test_no_output "set non-stop on" 33 34if ![runto_main] { 35 return -1 36} 37 38# We want "handle print", to make sure the target backend reports the 39# signal to the run control core. 40gdb_test "handle SIGUSR1 print nostop pass" "" 41 42# Get current value of VAR from the inferior. TEST is used as test 43# message. 44 45proc get_value {var test} { 46 global expect_out 47 global gdb_prompt 48 global decimal 49 50 set value -1 51 gdb_test_multiple "print $var" "$test" { 52 -re ".*= ($decimal).*\r\n$gdb_prompt $" { 53 set value $expect_out(1,string) 54 pass "$test" 55 } 56 } 57 return ${value} 58} 59 60set NUM_THREADS [get_value "num_threads" "get num_threads"] 61 62# Account for the main thread. 63incr NUM_THREADS 64 65# Probe for displaced stepping support. We're stopped at the main 66# breakpoint. If displaced stepping is supported, we should see 67# related debug output. 68set displaced_stepping_enabled 0 69set msg "check displaced-stepping" 70gdb_test_no_output "set debug displaced 1" 71gdb_test_multiple "next" $msg { 72 -re "displaced pc to.*$gdb_prompt $" { 73 set displaced_stepping_enabled 1 74 } 75 -re ".*$gdb_prompt $" { 76 } 77} 78gdb_test_no_output "set debug displaced 0" 79 80# Run threads to their start positions. This prepares for a new test 81# sequence. 82 83proc restart {} { 84 global gdb_prompt 85 global NUM_THREADS 86 87 delete_breakpoints 88 89 gdb_test "print got_sig = 0" " = 0" 90 91 gdb_breakpoint [gdb_get_line_number "set thread breakpoint here"] 92 gdb_breakpoint [gdb_get_line_number "set kill breakpoint here"] 93 94 set test "continue -a&" 95 gdb_test_multiple $test $test { 96 -re "Continuing.\r\n$gdb_prompt " { 97 pass $test 98 } 99 } 100 101 for {set i 1} { $i <= $NUM_THREADS } { incr i } { 102 set test "thread $i restarted" 103 gdb_test_multiple "" $test { 104 -re "breakpoint here" { 105 # The prompt was already matched in the "continue &" 106 # test above. We're now consuming asynchronous output 107 # that comes after the prompt. 108 pass $test 109 } 110 } 111 } 112 113 delete_breakpoints 114} 115 116# Run command and wait for the prompt, without end anchor. 117 118proc gdb_test_no_anchor {cmd} { 119 global gdb_prompt 120 121 gdb_test_multiple $cmd $cmd { 122 -re "$gdb_prompt " { 123 pass $cmd 124 } 125 } 126} 127 128# Enable/disable debugging. 129 130proc enable_debug {enable} { 131 132 # Comment out to debug problems with the test. 133 return 134 135 gdb_test_no_anchor "set debug infrun $enable" 136 gdb_test_no_anchor "set debug displaced $enable" 137} 138 139# The test proper. SIGNAL_THREAD is the thread that has been elected 140# to receive the SIGUSR1 signal. 141 142proc test {signal_thread} { 143 global gdb_prompt 144 global NUM_THREADS 145 global timeout 146 global displaced_stepping_enabled 147 148 with_test_prefix "signal_thread=$signal_thread" { 149 restart 150 151 # Set all threads stepping the infinite loop line in parallel. 152 for {set i 2} { $i <= $NUM_THREADS } { incr i } { 153 gdb_test "thread $i" \ 154 "child_function.*set thread breakpoint here.*" \ 155 "switch to thread $i to step it" 156 157 if {$i == $signal_thread} { 158 gdb_test "print signal_thread = self" " = .*" 159 } 160 161 gdb_test "step&" "" "set $i thread stepping" 162 } 163 164 gdb_test "thread 1" "Switching to .*" \ 165 "switch to the main thread to queue signal" 166 167 # Let the main thread queue the signal. 168 gdb_breakpoint "loop_broke" 169 170 enable_debug 1 171 172 # On software single-step targets that don't support displaced 173 # stepping, threads keep hitting each others' single-step 174 # breakpoints, and then GDB needs to pause all threads to step 175 # past those. The end result is that progress in the main 176 # thread will be slower and it may take a bit longer for the 177 # signal to be queued; bump the timeout. 178 if {!$displaced_stepping_enabled && ![can_hardware_single_step]} { 179 # The more threads we have, the longer it takes. 180 set factor $NUM_THREADS 181 } else { 182 set factor 1 183 } 184 with_timeout_factor $factor { 185 gdb_test "print timeout = $timeout" " = $timeout" \ 186 "set timeout in the inferior" 187 188 set saw_continuing 0 189 set test "continue &" 190 gdb_test_multiple $test $test { 191 -re "Continuing.\r\n" { 192 set saw_continuing 1 193 exp_continue 194 } 195 -re "$gdb_prompt " { 196 gdb_assert $saw_continuing $test 197 } 198 -re "infrun:" { 199 exp_continue 200 } 201 } 202 203 set gotit 0 204 205 # Wait for all threads to finish their steps, and for the main 206 # thread to hit the breakpoint. 207 for {set i 1} { $i <= $NUM_THREADS } { incr i } { 208 set test "thread $i broke out of loop" 209 set gotit 0 210 gdb_test_multiple "" $test { 211 -re "loop_broke" { 212 # The prompt was already matched in the "continue 213 # &" test above. We're now consuming asynchronous 214 # output that comes after the prompt. 215 set gotit 1 216 pass $test 217 } 218 -re "infrun:" { 219 exp_continue 220 } 221 } 222 if {!$gotit} { 223 break 224 } 225 } 226 } 227 228 enable_debug 0 229 230 # It's helpful to have this in the log if the test ever 231 # happens to fail. 232 gdb_test "info threads" 233 234 return $gotit 235 } 236} 237 238# The kernel/debug API may always walk its thread list looking for the 239# first with an event, resulting in giving priority to e.g. the thread 240# with lowest kernel thread ID. So test once with the signal pending 241# in each thread, except the main thread. 242for {set i 2} { $i <= $NUM_THREADS } { incr i } { 243 if {![test $i]} { 244 # Avoid cascading timeouts, and bail out. 245 return 246 } 247} 248