[gdb/symtab] Fix gdb.base/fission-macro.exp with unix/-m32
[binutils-gdb.git] / gdb / testsuite / gdb.threads / inf-thr-count.exp
blob1c85c95538443132a383617847a9041b1827efa2
1 # Copyright 2023-2024 Free Software Foundation, Inc.
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.
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.
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/>.
16 # Check that the $_inferior_thread_count convenience variable will
17 # correctly update its value without passing through a normal stop
18 # event.
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.
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.
30 # Or after an inferior function call.
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.
36 standard_testfile
38 if {[build_executable "failed to prepare" $testfile $srcfile \
39          {debug pthreads}] == -1} {
40     return -1
43 # Start GDB.  Ensure we are in non-stop mode as we need to read from
44 # the inferior while it is running.
45 save_vars {GDBFLAGS} {
46     append GDBFLAGS " -ex \"set non-stop on\""
47     clean_restart $binfile
50 if ![runto_main] {
51     return -1
54 gdb_breakpoint breakpt
55 gdb_continue_to_breakpoint "first breakpt call"
57 # Check we can see a single thread to begin with.
58 gdb_test "p \$_inferior_thread_count" \
59     "^\\\$$::decimal = 1" \
60     "only one thread in \$_inferior_thread_count"
62 # We don't want thread events, it makes it harder to match GDB's
63 # output.
64 gdb_test_no_output "set print thread-events off"
66 # Continue the program in the background.
67 set test "continue&"
68 gdb_test_multiple "continue&" $test {
69     -re "Continuing\\.\r\n$gdb_prompt " {
70         pass $test
71     }
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.
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.
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.
87 proc 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"
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         }
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     }
121     return $stage_flag
124 # Wait until we can see that the extra thread has been created.
125 if {![wait_for_stage 1]} {
126     unresolved "failed to see thread start"
127     return -1
131 if {[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 ""
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.
144 gdb_test "with print thread-events on -- p \$_inferior_thread_count" \
145     "^${new_thread_re}\\\$$::decimal = 2" \
146     "second thread visible in \$_inferior_thread_count"
148 # Set a variable in the inferior, this will cause the second thread to
149 # exit.
150 gdb_test_no_output "set variable spin = 0" \
151     "set 'spin' flag to allow worker thread to exit"
153 # Wait until the extra thread has exited.
154 if {![wait_for_stage 2]} {
155     unresolved "failed to see thread start"
156     return -1
159 # Check that the second thread has gone away.
160 gdb_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"
164 # Set a variable in the inferior, this will cause the second thread to
165 # exit.
166 gdb_test_no_output "set variable spin = 0" \
167     "set 'spin' flag to allow main thread to exit"
169 # When the second thread exits, the main thread joins with it, and
170 # then proceeds to hit the breakpt function again.
171 gdb_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     }