]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/testsuite/gdb.threads/inf-thr-count.exp
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.threads / inf-thr-count.exp
CommitLineData
1d506c26 1# Copyright 2023-2024 Free Software Foundation, Inc.
75b2eb97
AB
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# Check that the $_inferior_thread_count convenience variable will
17# correctly update its value without passing through a normal stop
18# event.
19#
20# When GDB is using a remote (or extended-remote) target, GDB only
21# learns about changes to the thread list be explicitly querying the
22# target. This is done as part of a normal stop, but there are some
23# situations where the thread list can change, but GDB doesn't pass
24# through a normal stop.
25#
26# For example, when the target is running asynchronously in non-stop
27# mode; in this case GDB can query the thread list without the target
28# ever stopping.
29#
30# Or after an inferior function call.
31#
32# The solution is to ensure that $_inferior_thread_count explicitly
33# queries the target to update the thread list. This test checks that
34# this is done.
35
36standard_testfile
37
38if {[build_executable "failed to prepare" $testfile $srcfile \
39 {debug pthreads}] == -1} {
40 return -1
41}
42
43# Start GDB. Ensure we are in non-stop mode as we need to read from
44# the inferior while it is running.
45save_vars {GDBFLAGS} {
46 append GDBFLAGS " -ex \"set non-stop on\""
47 clean_restart $binfile
48}
49
50if ![runto_main] {
51 return -1
52}
53
54gdb_breakpoint breakpt
55gdb_continue_to_breakpoint "first breakpt call"
56
57# Check we can see a single thread to begin with.
58gdb_test "p \$_inferior_thread_count" \
59 "^\\\$$::decimal = 1" \
60 "only one thread in \$_inferior_thread_count"
61
62# We don't want thread events, it makes it harder to match GDB's
63# output.
64gdb_test_no_output "set print thread-events off"
65
66# Continue the program in the background.
67set test "continue&"
68gdb_test_multiple "continue&" $test {
69 -re "Continuing\\.\r\n$gdb_prompt " {
70 pass $test
71 }
72}
73
74# Read the 'stage' flag from the inferior. This is initially 0, but
75# will be set to 1 once the extra thread has been created, and then 2
76# once the extra thread has exited.
77#
78# We catch the case where we can't read from the inferior while the
79# inferior is running, this happens if the target hasn't entered
80# non-stop mode like we asked. In this case we interrupt the inferior
81# and bail.
82#
83# Otherwise, if we can read from the inferior we try at most 10 times
84# to read the flag (with a 1 second delay after each read). If the
85# flag isn't set after this then we bail. The inferior is either very
86# slow, or the thread hasn't started for some reason.
87proc wait_for_stage { num } {
88 set failure_count 0
89 set cmd "print /d stage"
90 set stage_flag 0
91 gdb_test_multiple "$cmd" "wait for 'stage' flag to be $num" {
92 -re -wrap "^Cannot execute this command while the target is running\\.\r\nUse the \"interrupt\" command to stop the target\r\nand then try again\\." {
93 fail "$gdb_test_name (can't read asynchronously)"
94 gdb_test_no_output "interrupt"
95
96 gdb_test_multiple "" "wait for thread to stop" {
97 -re "Thread .* received signal .*" {
98 pass $gdb_test_name
99 gdb_test "p 1 + 2" " = 3"
100 }
101 }
102 }
103
104 -re -wrap "^\\$\[0-9\]* = (\[-\]*\[0-9\]*).*" {
105 set stage_flag $expect_out(1,string)
106 if {$stage_flag != $num} {
107 set stage_flag 0
108 incr failure_count
109 if { $failure_count < 10 } {
110 sleep 1
111 send_gdb "$cmd\n"
112 exp_continue
113 }
114 fail $gdb_test_name
115 } else {
116 pass $gdb_test_name
117 }
118 }
119 }
120
121 return $stage_flag
122}
123
124# Wait until we can see that the extra thread has been created.
125if {![wait_for_stage 1]} {
126 unresolved "failed to see thread start"
127 return -1
128}
129
130
131if {[target_info exists gdb_protocol]
132 && ([target_info gdb_protocol] == "remote"
133 || [target_info gdb_protocol] == "extended-remote")} {
134 set new_thread_re "\\\[New Thread \[^\r\n\]+\\\]\r\n"
135 set exit_thread_re "\\\[Thread \[^\r\n\]+ exited\\\]\r\n"
136} else {
137 set new_thread_re ""
138 set exit_thread_re ""
139}
140
141# This is the test we actually care about. Check that the
142# $_inferior_thread_count convenience variable shows the correct
143# thread count; the new thread should be visible.
144gdb_test "with print thread-events on -- p \$_inferior_thread_count" \
145 "^${new_thread_re}\\\$$::decimal = 2" \
146 "second thread visible in \$_inferior_thread_count"
147
148# Set a variable in the inferior, this will cause the second thread to
149# exit.
150gdb_test_no_output "set variable spin = 0" \
151 "set 'spin' flag to allow worker thread to exit"
152
153# Wait until the extra thread has exited.
154if {![wait_for_stage 2]} {
155 unresolved "failed to see thread start"
156 return -1
157}
158
159# Check that the second thread has gone away.
160gdb_test "with print thread-events on -- p \$_inferior_thread_count" \
161 "^${exit_thread_re}\\\$$::decimal = 1" \
162 "back to one thread visible in \$_inferior_thread_count"
163
164# Set a variable in the inferior, this will cause the second thread to
165# exit.
166gdb_test_no_output "set variable spin = 0" \
167 "set 'spin' flag to allow main thread to exit"
168
169# When the second thread exits, the main thread joins with it, and
170# then proceeds to hit the breakpt function again.
171gdb_test_multiple "" "wait for main thread to stop" {
172 -re "Thread 1 \[^\r\n\]+ hit Breakpoint $decimal, breakpt \\(\\)\[^\r\n\]+\r\n\[^\r\n\]+\r\n" {
173 pass $gdb_test_name
174 }
175}