]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/testsuite/gdb.threads/watchthreads-reorder.c
Update Copyright year range in all files maintained by GDB.
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.threads / watchthreads-reorder.c
CommitLineData
ebec9a0f
PA
1/* This testcase is part of GDB, the GNU debugger.
2
ecd75fc8 3 Copyright 2009-2014 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
47/* These variables must have lower in-memory addresses than thread1_rwatch and
48 thread2_rwatch so that they take their watchpoint slots. */
49
50static int unused1_rwatch;
51static int unused2_rwatch;
52
53static volatile int thread1_rwatch;
54static volatile int thread2_rwatch;
55
56/* Do not use alarm as it would create a ptrace event which would hang up us if
57 we are being traced by GDB which we stopped ourselves. */
58
59static void timed_mutex_lock (pthread_mutex_t *mutex)
60{
61 int i;
62 struct timespec start, now;
63
64 i = clock_gettime (CLOCK_MONOTONIC, &start);
65 assert (i == 0);
66
67 do
68 {
69 i = pthread_mutex_trylock (mutex);
70 if (i == 0)
71 return;
72 assert (i == EBUSY);
73
74 i = clock_gettime (CLOCK_MONOTONIC, &now);
75 assert (i == 0);
76 assert (now.tv_sec >= start.tv_sec);
77 }
78 while (now.tv_sec - start.tv_sec < TIMEOUT);
79
80 fprintf (stderr, "Timed out waiting for internal lock!\n");
81 exit (EXIT_FAILURE);
82}
83
84static void *
85thread1_func (void *unused)
86{
87 int i;
88 volatile int rwatch_store;
89
23787403
JK
90 timed_mutex_lock (&thread1_tid_mutex);
91
92 /* THREAD1_TID_MUTEX must be already locked to avoid race. */
ebec9a0f 93 thread1_tid = gettid ();
23787403 94
ebec9a0f
PA
95 i = pthread_cond_signal (&thread1_tid_cond);
96 assert (i == 0);
23787403 97 i = pthread_mutex_unlock (&thread1_tid_mutex);
ebec9a0f
PA
98 assert (i == 0);
99
100 rwatch_store = thread1_rwatch;
101
09eef106 102 /* Be sure the "t (tracing stop)" test can proceed for both threads. */
ebec9a0f
PA
103 timed_mutex_lock (&terminate_mutex);
104 i = pthread_mutex_unlock (&terminate_mutex);
105 assert (i == 0);
106
107 return NULL;
108}
109
110static void *
111thread2_func (void *unused)
112{
113 int i;
114 volatile int rwatch_store;
115
23787403
JK
116 timed_mutex_lock (&thread2_tid_mutex);
117
118 /* THREAD2_TID_MUTEX must be already locked to avoid race. */
ebec9a0f 119 thread2_tid = gettid ();
23787403 120
ebec9a0f
PA
121 i = pthread_cond_signal (&thread2_tid_cond);
122 assert (i == 0);
23787403 123 i = pthread_mutex_unlock (&thread2_tid_mutex);
ebec9a0f
PA
124 assert (i == 0);
125
126 rwatch_store = thread2_rwatch;
127
09eef106 128 /* Be sure the "t (tracing stop)" test can proceed for both threads. */
ebec9a0f
PA
129 timed_mutex_lock (&terminate_mutex);
130 i = pthread_mutex_unlock (&terminate_mutex);
131 assert (i == 0);
132
133 return NULL;
134}
135
136static const char *
137proc_string (const char *filename, const char *line)
138{
139 FILE *f;
140 static char buf[LINE_MAX];
141 size_t line_len = strlen (line);
142
143 f = fopen (filename, "r");
144 if (f == NULL)
145 {
146 fprintf (stderr, "fopen (\"%s\") for \"%s\": %s\n", filename, line,
147 strerror (errno));
148 exit (EXIT_FAILURE);
149 }
150 while (errno = 0, fgets (buf, sizeof (buf), f))
151 {
152 char *s;
153
154 s = strchr (buf, '\n');
155 assert (s != NULL);
156 *s = 0;
157
158 if (strncmp (buf, line, line_len) != 0)
159 continue;
160
161 if (fclose (f))
162 {
163 fprintf (stderr, "fclose (\"%s\") for \"%s\": %s\n", filename, line,
164 strerror (errno));
165 exit (EXIT_FAILURE);
166 }
167
168 return &buf[line_len];
169 }
170 if (errno != 0)
171 {
172 fprintf (stderr, "fgets (\"%s\": %s\n", filename, strerror (errno));
173 exit (EXIT_FAILURE);
174 }
175 fprintf (stderr, "\"%s\": No line \"%s\" found.\n", filename, line);
176 exit (EXIT_FAILURE);
177}
178
179static unsigned long
180proc_ulong (const char *filename, const char *line)
181{
182 const char *s = proc_string (filename, line);
183 long retval;
184 char *end;
185
186 errno = 0;
187 retval = strtol (s, &end, 10);
188 if (retval < 0 || retval >= LONG_MAX || (end && *end))
189 {
190 fprintf (stderr, "\"%s\":\"%s\": %ld, %s\n", filename, line, retval,
191 strerror (errno));
192 exit (EXIT_FAILURE);
193 }
194 return retval;
195}
196
197static void
198state_wait (pid_t process, const char *wanted)
199{
200 char *filename;
201 int i;
202 struct timespec start, now;
203 const char *state;
204
205 i = asprintf (&filename, "/proc/%lu/status", (unsigned long) process);
206 assert (i > 0);
207
208 i = clock_gettime (CLOCK_MONOTONIC, &start);
209 assert (i == 0);
210
211 do
212 {
213 state = proc_string (filename, "State:\t");
09eef106
JK
214
215 /* torvalds/linux-2.6.git 464763cf1c6df632dccc8f2f4c7e50163154a2c0
216 has changed "T (tracing stop)" to "t (tracing stop)". Make the GDB
217 testcase backward compatible with older Linux kernels. */
218 if (strcmp (state, "T (tracing stop)") == 0)
219 state = "t (tracing stop)";
220
ebec9a0f
PA
221 if (strcmp (state, wanted) == 0)
222 {
223 free (filename);
224 return;
225 }
226
227 if (sched_yield ())
228 {
229 perror ("sched_yield()");
230 exit (EXIT_FAILURE);
231 }
232
233 i = clock_gettime (CLOCK_MONOTONIC, &now);
234 assert (i == 0);
235 assert (now.tv_sec >= start.tv_sec);
236 }
237 while (now.tv_sec - start.tv_sec < TIMEOUT);
238
239 fprintf (stderr, "Timed out waiting for PID %lu \"%s\" (now it is \"%s\")!\n",
240 (unsigned long) process, wanted, state);
241 exit (EXIT_FAILURE);
242}
243
244static volatile pid_t tracer = 0;
245static pthread_t thread1, thread2;
246
247static void
248cleanup (void)
249{
250 printf ("Resuming GDB PID %lu.\n", (unsigned long) tracer);
251
252 if (tracer)
253 {
254 int i;
255 int tracer_save = tracer;
256
257 tracer = 0;
258
259 i = kill (tracer_save, SIGCONT);
260 assert (i == 0);
261 }
262}
263
264int
265main (int argc, char **argv)
266{
267 int i;
268 int standalone = 0;
269
270 if (argc == 2 && strcmp (argv[1], "-s") == 0)
271 standalone = 1;
272 else
273 assert (argc == 1);
274
275 setbuf (stdout, NULL);
276
23787403
JK
277 timed_mutex_lock (&thread1_tid_mutex);
278 timed_mutex_lock (&thread2_tid_mutex);
ebec9a0f
PA
279
280 timed_mutex_lock (&terminate_mutex);
281
282 i = pthread_create (&thread1, NULL, thread1_func, NULL);
283 assert (i == 0);
284
285 i = pthread_create (&thread2, NULL, thread2_func, NULL);
286 assert (i == 0);
287
288 if (!standalone)
289 {
290 tracer = proc_ulong ("/proc/self/status", "TracerPid:\t");
291 if (tracer == 0)
292 {
293 fprintf (stderr, "The testcase must be run by GDB!\n");
294 exit (EXIT_FAILURE);
295 }
296 if (tracer != getppid ())
297 {
298 fprintf (stderr, "The testcase parent must be our GDB tracer!\n");
299 exit (EXIT_FAILURE);
300 }
301 }
302
303 /* SIGCONT our debugger in the case of our crash as we would deadlock
304 otherwise. */
305
306 atexit (cleanup);
307
308 printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer);
309
310 if (tracer)
311 {
312 i = kill (tracer, SIGSTOP);
313 assert (i == 0);
314 state_wait (tracer, "T (stopped)");
315 }
316
23787403
JK
317 /* Threads are now waiting at timed_mutex_lock (thread1_tid_mutex) and so
318 they could not trigger the watchpoints before GDB gets unstopped later.
319 Threads get resumed at pthread_cond_wait below. Use `while' loops for
320 protection against spurious pthread_cond_wait wakeups. */
ebec9a0f
PA
321
322 printf ("Waiting till the threads initialize their TIDs.\n");
323
23787403 324 while (thread1_tid == 0)
ebec9a0f
PA
325 {
326 i = pthread_cond_wait (&thread1_tid_cond, &thread1_tid_mutex);
327 assert (i == 0);
ebec9a0f
PA
328 }
329
23787403 330 while (thread2_tid == 0)
ebec9a0f
PA
331 {
332 i = pthread_cond_wait (&thread2_tid_cond, &thread2_tid_mutex);
333 assert (i == 0);
ebec9a0f
PA
334 }
335
336 printf ("Thread 1 TID = %lu, thread 2 TID = %lu, PID = %lu.\n",
337 (unsigned long) thread1_tid, (unsigned long) thread2_tid,
338 (unsigned long) getpid ());
339
340 printf ("Waiting till the threads get trapped by the watchpoints.\n");
341
342 if (tracer)
343 {
344 /* s390x-unknown-linux-gnu will fail with "R (running)". */
345
09eef106 346 state_wait (thread1_tid, "t (tracing stop)");
ebec9a0f 347
09eef106 348 state_wait (thread2_tid, "t (tracing stop)");
ebec9a0f
PA
349 }
350
351 cleanup ();
352
353 printf ("Joining the threads.\n");
354
355 i = pthread_mutex_unlock (&terminate_mutex);
356 assert (i == 0);
357
358 i = pthread_join (thread1, NULL);
359 assert (i == 0);
360
361 i = pthread_join (thread2, NULL);
362 assert (i == 0);
363
364 printf ("Exiting.\n"); /* break-at-exit */
365
366 /* Just prevent compiler `warning: unusedX_rwatch defined but not used'. */
367 unused1_rwatch = 1;
368 unused2_rwatch = 2;
369
370 return EXIT_SUCCESS;
371}