xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/testsuite/gdb.threads/attach-many-short-lived-threads.exp (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1# Copyright 2008-2023 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 attaching to a program that is constantly spawning short-lived
17# threads.  The stresses the edge cases of attaching to threads that
18# have just been created or are in process of dying.  In addition, the
19# test attaches, debugs, detaches, reattaches in a loop a few times,
20# to stress the behavior of the debug API around detach (some systems
21# end up leaving stale state behind that confuse the following
22# attach).
23
24# Return true if the running version of DejaGnu is known to not be
25# able to run this test.
26proc bad_dejagnu {} {
27    set dj_ver [dejagnu_version]
28    set dj_ver_major [lindex $dj_ver 0]
29    set dj_ver_minor [lindex $dj_ver 1]
30
31    # DejaGnu versions prior to 1.6 manage to kill the wrong process
32    # due to PID-reuse races.  Since this test spawns many threads, it
33    # widens the race window a whole lot, enough that the inferior is
34    # often killed, and thus the test randomly fails.  See:
35    # http://lists.gnu.org/archive/html/dejagnu/2015-07/msg00005.html
36    # The fix added a close_wait_program procedure.  If that procedure
37    # is defined, and DejaGnu is older than 1.6, assume that means the
38    # fix was backported.
39    if {$dj_ver_major == 1
40	&& ($dj_ver_minor < 6 && [info procs close_wait_program] == "")} {
41	return 1
42    }
43
44    return 0
45}
46
47if {[bad_dejagnu]} {
48    unsupported "broken DejaGnu"
49    return 0
50}
51
52if {![can_spawn_for_attach]} {
53    return 0
54}
55
56standard_testfile
57
58# The test proper.  See description above.
59
60proc test {} {
61    global binfile
62    global gdb_prompt
63    global decimal
64
65    set test_spawn_id [spawn_wait_for_attach $binfile]
66    set testpid [spawn_id_get_pid $test_spawn_id]
67
68    set attempts 10
69    for {set attempt 1} { $attempt <= $attempts } { incr attempt } {
70	with_test_prefix "iter $attempt" {
71	    set attached 0
72	    set eperm 0
73	    set test "attach"
74	    gdb_test_multiple "attach $testpid" $test {
75		-re "new threads in iteration" {
76		    # Seen when "set debug libthread_db" is on.
77		    exp_continue
78		}
79		-re "warning: Cannot attach to lwp $decimal: Operation not permitted" {
80		    # On Linux, PTRACE_ATTACH sometimes fails with
81		    # EPERM, even though /proc/PID/status indicates
82		    # the thread is running.
83		    set eperm 1
84		    exp_continue
85		}
86		-re "debugger service failed.*$gdb_prompt $" {
87		    fail $test
88		}
89		-re "$gdb_prompt $" {
90		    if {$eperm} {
91			xfail "$test (EPERM)"
92		    } else {
93			pass $test
94		    }
95		}
96		-re "Attaching to program.*process $testpid.*$gdb_prompt $" {
97		    pass $test
98		}
99	    }
100
101	    # Sleep a bit and try updating the thread list.  We should
102	    # know about all threads already at this point.  If we see
103	    # "New Thread" or similar being output, then "attach" is
104	    # failing to actually attach to all threads in the process,
105	    # which would be a bug.
106	    sleep 1
107
108	    set test "no new threads"
109	    set status 1
110	    gdb_test_multiple "info threads" $test -lbl {
111		-re "\r\n\[^\r\n\]*New " {
112		    set status 0
113		    exp_continue
114		}
115		-re -wrap "" {
116		    if { $status == 1 } {
117			pass $gdb_test_name
118		    } else {
119			fail $gdb_test_name
120		    }
121		}
122	    }
123
124	    # Force breakpoints always inserted, so that threads we might
125	    # have failed to attach to hit them even when threads we do
126	    # know about are stopped.
127	    gdb_test_no_output "set breakpoint always-inserted on"
128
129	    # Run to a breakpoint a few times.  A few threads should spawn
130	    # and die meanwhile.  This checks that thread creation/death
131	    # events carry on correctly after attaching.  Also, be
132	    # detaching from the program and reattaching, we check that
133	    # the program doesn't die due to gdb leaving a pending
134	    # breakpoint hit on a new thread unprocessed.
135	    gdb_test "break break_fn" "Breakpoint.*"
136
137	    # Wait a bit, to give time for most threads to hit the
138	    # breakpoint, including threads we might have failed to
139	    # attach.
140	    sleep 2
141
142	    set bps 3
143	    for {set bp 1} { $bp <= $bps } { incr bp } {
144		gdb_test "continue" "Breakpoint.*" "break at break_fn: $bp"
145	    }
146
147	    if {$attempt < $attempts} {
148		# Kick the time out timer for another round.
149		gdb_test "print again = 1" " = 1" "reset timer in the inferior"
150		# Show the time we had left in the logs, in case
151		# something goes wrong.
152		gdb_test "print seconds_left" " = .*"
153
154		gdb_test "detach" "Detaching from.*"
155	    } else {
156		gdb_test "kill" "" "kill process" "Kill the program being debugged.*y or n. $" "y"
157	    }
158
159	    gdb_test_no_output "set breakpoint always-inserted off"
160	    delete_breakpoints
161	}
162    }
163    kill_wait_spawned_process $test_spawn_id
164}
165
166# The test program exits after a while, in case GDB crashes.  Make it
167# wait at least as long as we may wait before declaring a time out
168# failure.
169set options { "additional_flags=-DTIMEOUT=$timeout" debug pthreads }
170
171if {[prepare_for_testing "failed to prepare" $testfile $srcfile \
172	 $options] == -1} {
173    return -1
174}
175
176test
177