summaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.threads/access-mem-running-thread-exit.exp
blob: 4c2e2b776e416ac90018b9f2f5741339c263694d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# Copyright (C) 2021 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 <http://www.gnu.org/licenses/>.

# Test that we can access memory while all the threads of the inferior
# are running, and even if:
#
# - the leader thread exits
# - the selected thread exits
#
# This test constantly spawns short lived threads to make sure that on
# systems with debug APIs that require passing down a specific thread
# to work with (e.g., GNU/Linux ptrace and /proc filesystem), GDB
# copes with accessing memory just while the thread it is accessing
# memory through exits.
#
# The test spawns two processes and alternates memory accesses between
# them to force flushing per-process caches.  At the time of writing,
# the Linux backend accesses inferior memory via /proc/<pid>/mem, and
# keeps one such file open, as a cache.  Alternating inferiors forces
# opening such file for a different process, which fails if GDB tries
# to open the file for a thread that exited.  The test does ensures
# those reopen/fail code paths are exercised.

standard_testfile

if {[build_executable "failed to prepare" $testfile $srcfile {debug pthreads}] == -1} {
    return -1
}

# The test proper.  NON_STOP indicates whether we're testing in
# non-stop, or all-stop mode.

proc test { non_stop } {
    global binfile
    global gdb_prompt
    global GDBFLAGS

    save_vars { GDBFLAGS } {
      append GDBFLAGS " -ex \"set non-stop $non_stop\""
      clean_restart ${binfile}
    }

    if ![runto_main] {
	return -1
    }

    # If debugging with target remote, check whether the all-stop variant
    # of the RSP is being used.  If so, we can't run the background tests.
    if {!$non_stop
	&& [target_info exists gdb_protocol]
	&& ([target_info gdb_protocol] == "remote"
	    || [target_info gdb_protocol] == "extended-remote")} {

	gdb_test_multiple "maint show target-non-stop" "" {
	    -wrap -re "(is|currently) on.*" {
	    }
	    -wrap -re "(is|currently) off.*" {
		unsupported "can't issue commands while target is running"
		return 0
	    }
	}
    }

    delete_breakpoints

    # Start the second inferior.
    with_test_prefix "second inferior" {
	gdb_test "add-inferior -no-connection" "New inferior 2.*"
	gdb_test "inferior 2" "Switching to inferior 2 .*"

	gdb_load $binfile

	if ![runto_main] {
	    return -1
	}
    }

    delete_breakpoints

    # These put too much noise in the logs.
    gdb_test_no_output "set print thread-events off"

    # Continue all threads of both processes.
    gdb_test_no_output "set schedule-multiple on"
    if {$non_stop == "off"} {
	set cmd "continue &"
    } else {
	set cmd "continue -a &"
    }
    gdb_test_multiple $cmd "continuing" {
	-re "Continuing\.\r\n$gdb_prompt " {
	    pass $gdb_test_name
	}
    }

    # Like gdb_test, but:
    # - don't issue a pass on success.
    # - on failure, clear the ok variable in the calling context, and
    #   break it.
    proc my_gdb_test {cmd pattern message} {
	upvar inf inf
	upvar iter iter
	if {[gdb_test_multiple $cmd "access mem ($message, inf=$inf, iter=$iter)" {
	    -wrap -re $pattern {
	    }
	}] != 0} {
	    uplevel 1 {set ok 0}
	    return -code break
	}
    }

    # Hammer away for 5 seconds, alternating between inferiors.
    set ::done 0
    after 5000 { set ::done 1 }

    set inf 1
    set ok 1
    set iter 0
    while {!$::done && $ok} {
	incr iter
	verbose -log "xxxxx: iteration $iter"
	gdb_test "info threads" ".*" ""

	if {$inf == 1} {
	    set inf 2
	} else {
	    set inf 1
	}

	my_gdb_test "inferior $inf" ".*" "inferior $inf"

	my_gdb_test "print global_var = 555" " = 555" \
	    "write to global_var"
	my_gdb_test "print global_var" " = 555" \
	    "print global_var after writing"
	my_gdb_test "print global_var = 333" " = 333" \
	    "write to global_var again"
	my_gdb_test "print global_var" " = 333" \
	    "print global_var after writing again"
    }

   if {$ok} {
       pass "access mem"
   }
}

foreach non_stop { "off" "on" } {
    set stop_mode [expr ($non_stop=="off")?"all-stop":"non-stop"]
    with_test_prefix "$stop_mode" {
	test $non_stop
    }
}