gdb: Don't ignore all SIGSTOP when the signal handler is set to pass
[deliverable/binutils-gdb.git] / gdb / testsuite / gdb.threads / watchthreads-reorder.c
CommitLineData
ebec9a0f
PA
1/* This testcase is part of GDB, the GNU debugger.
2
42a4f53d 3 Copyright 2009-2019 Free Software Foundation, Inc.
ebec9a0f
PA
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18#define _GNU_SOURCE
19#include <pthread.h>
20#include <stdio.h>
21#include <limits.h>
22#include <errno.h>
23#include <stdlib.h>
24#include <string.h>
25#include <assert.h>
26#include <sys/types.h>
27#include <signal.h>
28#include <unistd.h>
29#include <asm/unistd.h>
30
31#define gettid() syscall (__NR_gettid)
32
33/* Terminate always in the main task, it can lock up with SIGSTOPped GDB
34 otherwise. */
35#define TIMEOUT (gettid () == getpid() ? 10 : 15)
36
ebec9a0f
PA
37static pid_t thread1_tid;
38static pthread_cond_t thread1_tid_cond = PTHREAD_COND_INITIALIZER;
39static pthread_mutex_t thread1_tid_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
40
41static pid_t thread2_tid;
42static pthread_cond_t thread2_tid_cond = PTHREAD_COND_INITIALIZER;
43static pthread_mutex_t thread2_tid_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
44
45static pthread_mutex_t terminate_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
46
9665ffdd
PA
47static pthread_barrier_t threads_started_barrier;
48
ebec9a0f
PA
49/* These variables must have lower in-memory addresses than thread1_rwatch and
50 thread2_rwatch so that they take their watchpoint slots. */
51
52static int unused1_rwatch;
53static int unused2_rwatch;
54
55static volatile int thread1_rwatch;
56static volatile int thread2_rwatch;
57
58/* Do not use alarm as it would create a ptrace event which would hang up us if
59 we are being traced by GDB which we stopped ourselves. */
60
61static void timed_mutex_lock (pthread_mutex_t *mutex)
62{
63 int i;
64 struct timespec start, now;
65
66 i = clock_gettime (CLOCK_MONOTONIC, &start);
67 assert (i == 0);
68
69 do
70 {
71 i = pthread_mutex_trylock (mutex);
72 if (i == 0)
73 return;
74 assert (i == EBUSY);
75
76 i = clock_gettime (CLOCK_MONOTONIC, &now);
77 assert (i == 0);
78 assert (now.tv_sec >= start.tv_sec);
79 }
80 while (now.tv_sec - start.tv_sec < TIMEOUT);
81
82 fprintf (stderr, "Timed out waiting for internal lock!\n");
83 exit (EXIT_FAILURE);
84}
85
86static void *
87thread1_func (void *unused)
88{
89 int i;
90 volatile int rwatch_store;
91
9665ffdd
PA
92 pthread_barrier_wait (&threads_started_barrier);
93
23787403
JK
94 timed_mutex_lock (&thread1_tid_mutex);
95
96 /* THREAD1_TID_MUTEX must be already locked to avoid race. */
ebec9a0f 97 thread1_tid = gettid ();
23787403 98
ebec9a0f
PA
99 i = pthread_cond_signal (&thread1_tid_cond);
100 assert (i == 0);
23787403 101 i = pthread_mutex_unlock (&thread1_tid_mutex);
ebec9a0f
PA
102 assert (i == 0);
103
104 rwatch_store = thread1_rwatch;
105
09eef106 106 /* Be sure the "t (tracing stop)" test can proceed for both threads. */
ebec9a0f
PA
107 timed_mutex_lock (&terminate_mutex);
108 i = pthread_mutex_unlock (&terminate_mutex);
109 assert (i == 0);
110
111 return NULL;
112}
113
114static void *
115thread2_func (void *unused)
116{
117 int i;
118 volatile int rwatch_store;
119
9665ffdd
PA
120 pthread_barrier_wait (&threads_started_barrier);
121
23787403
JK
122 timed_mutex_lock (&thread2_tid_mutex);
123
124 /* THREAD2_TID_MUTEX must be already locked to avoid race. */
ebec9a0f 125 thread2_tid = gettid ();
23787403 126
ebec9a0f
PA
127 i = pthread_cond_signal (&thread2_tid_cond);
128 assert (i == 0);
23787403 129 i = pthread_mutex_unlock (&thread2_tid_mutex);
ebec9a0f
PA
130 assert (i == 0);
131
132 rwatch_store = thread2_rwatch;
133
09eef106 134 /* Be sure the "t (tracing stop)" test can proceed for both threads. */
ebec9a0f
PA
135 timed_mutex_lock (&terminate_mutex);
136 i = pthread_mutex_unlock (&terminate_mutex);
137 assert (i == 0);
138
139 return NULL;
140}
141
142static const char *
143proc_string (const char *filename, const char *line)
144{
145 FILE *f;
146 static char buf[LINE_MAX];
147 size_t line_len = strlen (line);
148
149 f = fopen (filename, "r");
150 if (f == NULL)
151 {
152 fprintf (stderr, "fopen (\"%s\") for \"%s\": %s\n", filename, line,
153 strerror (errno));
154 exit (EXIT_FAILURE);
155 }
156 while (errno = 0, fgets (buf, sizeof (buf), f))
157 {
158 char *s;
159
160 s = strchr (buf, '\n');
161 assert (s != NULL);
162 *s = 0;
163
164 if (strncmp (buf, line, line_len) != 0)
165 continue;
166
167 if (fclose (f))
168 {
169 fprintf (stderr, "fclose (\"%s\") for \"%s\": %s\n", filename, line,
170 strerror (errno));
171 exit (EXIT_FAILURE);
172 }
173
174 return &buf[line_len];
175 }
176 if (errno != 0)
177 {
178 fprintf (stderr, "fgets (\"%s\": %s\n", filename, strerror (errno));
179 exit (EXIT_FAILURE);
180 }
181 fprintf (stderr, "\"%s\": No line \"%s\" found.\n", filename, line);
182 exit (EXIT_FAILURE);
183}
184
185static unsigned long
186proc_ulong (const char *filename, const char *line)
187{
188 const char *s = proc_string (filename, line);
189 long retval;
190 char *end;
191
192 errno = 0;
193 retval = strtol (s, &end, 10);
194 if (retval < 0 || retval >= LONG_MAX || (end && *end))
195 {
196 fprintf (stderr, "\"%s\":\"%s\": %ld, %s\n", filename, line, retval,
197 strerror (errno));
198 exit (EXIT_FAILURE);
199 }
200 return retval;
201}
202
203static void
204state_wait (pid_t process, const char *wanted)
205{
206 char *filename;
207 int i;
208 struct timespec start, now;
209 const char *state;
210
211 i = asprintf (&filename, "/proc/%lu/status", (unsigned long) process);
212 assert (i > 0);
213
214 i = clock_gettime (CLOCK_MONOTONIC, &start);
215 assert (i == 0);
216
217 do
218 {
219 state = proc_string (filename, "State:\t");
09eef106
JK
220
221 /* torvalds/linux-2.6.git 464763cf1c6df632dccc8f2f4c7e50163154a2c0
222 has changed "T (tracing stop)" to "t (tracing stop)". Make the GDB
223 testcase backward compatible with older Linux kernels. */
224 if (strcmp (state, "T (tracing stop)") == 0)
225 state = "t (tracing stop)";
226
ebec9a0f
PA
227 if (strcmp (state, wanted) == 0)
228 {
229 free (filename);
230 return;
231 }
232
233 if (sched_yield ())
234 {
235 perror ("sched_yield()");
236 exit (EXIT_FAILURE);
237 }
238
239 i = clock_gettime (CLOCK_MONOTONIC, &now);
240 assert (i == 0);
241 assert (now.tv_sec >= start.tv_sec);
242 }
243 while (now.tv_sec - start.tv_sec < TIMEOUT);
244
245 fprintf (stderr, "Timed out waiting for PID %lu \"%s\" (now it is \"%s\")!\n",
246 (unsigned long) process, wanted, state);
247 exit (EXIT_FAILURE);
248}
249
250static volatile pid_t tracer = 0;
251static pthread_t thread1, thread2;
252
253static void
254cleanup (void)
255{
256 printf ("Resuming GDB PID %lu.\n", (unsigned long) tracer);
257
258 if (tracer)
259 {
260 int i;
261 int tracer_save = tracer;
262
263 tracer = 0;
264
265 i = kill (tracer_save, SIGCONT);
266 assert (i == 0);
267 }
268}
269
270int
271main (int argc, char **argv)
272{
273 int i;
274 int standalone = 0;
275
276 if (argc == 2 && strcmp (argv[1], "-s") == 0)
277 standalone = 1;
278 else
279 assert (argc == 1);
280
281 setbuf (stdout, NULL);
282
23787403
JK
283 timed_mutex_lock (&thread1_tid_mutex);
284 timed_mutex_lock (&thread2_tid_mutex);
ebec9a0f
PA
285
286 timed_mutex_lock (&terminate_mutex);
287
9665ffdd
PA
288 pthread_barrier_init (&threads_started_barrier, NULL, 3);
289
ebec9a0f
PA
290 i = pthread_create (&thread1, NULL, thread1_func, NULL);
291 assert (i == 0);
292
293 i = pthread_create (&thread2, NULL, thread2_func, NULL);
294 assert (i == 0);
295
296 if (!standalone)
297 {
298 tracer = proc_ulong ("/proc/self/status", "TracerPid:\t");
299 if (tracer == 0)
300 {
301 fprintf (stderr, "The testcase must be run by GDB!\n");
302 exit (EXIT_FAILURE);
303 }
304 if (tracer != getppid ())
305 {
306 fprintf (stderr, "The testcase parent must be our GDB tracer!\n");
307 exit (EXIT_FAILURE);
308 }
309 }
310
311 /* SIGCONT our debugger in the case of our crash as we would deadlock
312 otherwise. */
313
314 atexit (cleanup);
315
9665ffdd
PA
316 /* Wait until all threads are seen running. On Linux (at least),
317 new threads start stopped, and the debugger must resume them.
318 Need to wait for that before stopping GDB. */
319 pthread_barrier_wait (&threads_started_barrier);
320
ebec9a0f
PA
321 printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer);
322
323 if (tracer)
324 {
325 i = kill (tracer, SIGSTOP);
326 assert (i == 0);
327 state_wait (tracer, "T (stopped)");
328 }
329
23787403
JK
330 /* Threads are now waiting at timed_mutex_lock (thread1_tid_mutex) and so
331 they could not trigger the watchpoints before GDB gets unstopped later.
332 Threads get resumed at pthread_cond_wait below. Use `while' loops for
333 protection against spurious pthread_cond_wait wakeups. */
ebec9a0f
PA
334
335 printf ("Waiting till the threads initialize their TIDs.\n");
336
23787403 337 while (thread1_tid == 0)
ebec9a0f
PA
338 {
339 i = pthread_cond_wait (&thread1_tid_cond, &thread1_tid_mutex);
340 assert (i == 0);
ebec9a0f
PA
341 }
342
23787403 343 while (thread2_tid == 0)
ebec9a0f
PA
344 {
345 i = pthread_cond_wait (&thread2_tid_cond, &thread2_tid_mutex);
346 assert (i == 0);
ebec9a0f
PA
347 }
348
349 printf ("Thread 1 TID = %lu, thread 2 TID = %lu, PID = %lu.\n",
350 (unsigned long) thread1_tid, (unsigned long) thread2_tid,
351 (unsigned long) getpid ());
352
353 printf ("Waiting till the threads get trapped by the watchpoints.\n");
354
355 if (tracer)
356 {
357 /* s390x-unknown-linux-gnu will fail with "R (running)". */
358
09eef106 359 state_wait (thread1_tid, "t (tracing stop)");
ebec9a0f 360
09eef106 361 state_wait (thread2_tid, "t (tracing stop)");
ebec9a0f
PA
362 }
363
364 cleanup ();
365
366 printf ("Joining the threads.\n");
367
368 i = pthread_mutex_unlock (&terminate_mutex);
369 assert (i == 0);
370
371 i = pthread_join (thread1, NULL);
372 assert (i == 0);
373
374 i = pthread_join (thread2, NULL);
375 assert (i == 0);
376
377 printf ("Exiting.\n"); /* break-at-exit */
378
379 /* Just prevent compiler `warning: unusedX_rwatch defined but not used'. */
380 unused1_rwatch = 1;
381 unused2_rwatch = 2;
382
383 return EXIT_SUCCESS;
384}
This page took 1.195339 seconds and 4 git commands to generate.