gdb/
[deliverable/binutils-gdb.git] / gdb / testsuite / gdb.threads / watchthreads-reorder.c
1 /* This testcase is part of GDB, the GNU debugger.
2
3 Copyright 2009 Free Software Foundation, Inc.
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
37 static pthread_mutex_t gdbstop_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
38
39 static pid_t thread1_tid;
40 static pthread_cond_t thread1_tid_cond = PTHREAD_COND_INITIALIZER;
41 static pthread_mutex_t thread1_tid_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
42
43 static pid_t thread2_tid;
44 static pthread_cond_t thread2_tid_cond = PTHREAD_COND_INITIALIZER;
45 static pthread_mutex_t thread2_tid_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
46
47 static pthread_mutex_t terminate_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
48
49 /* These variables must have lower in-memory addresses than thread1_rwatch and
50 thread2_rwatch so that they take their watchpoint slots. */
51
52 static int unused1_rwatch;
53 static int unused2_rwatch;
54
55 static volatile int thread1_rwatch;
56 static 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
61 static 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
86 static void *
87 thread1_func (void *unused)
88 {
89 int i;
90 volatile int rwatch_store;
91
92 thread1_tid = gettid ();
93 i = pthread_cond_signal (&thread1_tid_cond);
94 assert (i == 0);
95
96 /* Be sure GDB is already stopped before continuing. */
97 timed_mutex_lock (&gdbstop_mutex);
98 i = pthread_mutex_unlock (&gdbstop_mutex);
99 assert (i == 0);
100
101 rwatch_store = thread1_rwatch;
102
103 /* Be sure the "T (tracing stop)" test can proceed for both threads. */
104 timed_mutex_lock (&terminate_mutex);
105 i = pthread_mutex_unlock (&terminate_mutex);
106 assert (i == 0);
107
108 return NULL;
109 }
110
111 static void *
112 thread2_func (void *unused)
113 {
114 int i;
115 volatile int rwatch_store;
116
117 thread2_tid = gettid ();
118 i = pthread_cond_signal (&thread2_tid_cond);
119 assert (i == 0);
120
121 /* Be sure GDB is already stopped before continuing. */
122 timed_mutex_lock (&gdbstop_mutex);
123 i = pthread_mutex_unlock (&gdbstop_mutex);
124 assert (i == 0);
125
126 rwatch_store = thread2_rwatch;
127
128 /* Be sure the "T (tracing stop)" test can proceed for both threads. */
129 timed_mutex_lock (&terminate_mutex);
130 i = pthread_mutex_unlock (&terminate_mutex);
131 assert (i == 0);
132
133 return NULL;
134 }
135
136 static const char *
137 proc_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
179 static unsigned long
180 proc_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
197 static void
198 state_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");
214 if (strcmp (state, wanted) == 0)
215 {
216 free (filename);
217 return;
218 }
219
220 if (sched_yield ())
221 {
222 perror ("sched_yield()");
223 exit (EXIT_FAILURE);
224 }
225
226 i = clock_gettime (CLOCK_MONOTONIC, &now);
227 assert (i == 0);
228 assert (now.tv_sec >= start.tv_sec);
229 }
230 while (now.tv_sec - start.tv_sec < TIMEOUT);
231
232 fprintf (stderr, "Timed out waiting for PID %lu \"%s\" (now it is \"%s\")!\n",
233 (unsigned long) process, wanted, state);
234 exit (EXIT_FAILURE);
235 }
236
237 static volatile pid_t tracer = 0;
238 static pthread_t thread1, thread2;
239
240 static void
241 cleanup (void)
242 {
243 printf ("Resuming GDB PID %lu.\n", (unsigned long) tracer);
244
245 if (tracer)
246 {
247 int i;
248 int tracer_save = tracer;
249
250 tracer = 0;
251
252 i = kill (tracer_save, SIGCONT);
253 assert (i == 0);
254 }
255 }
256
257 int
258 main (int argc, char **argv)
259 {
260 int i;
261 int standalone = 0;
262
263 if (argc == 2 && strcmp (argv[1], "-s") == 0)
264 standalone = 1;
265 else
266 assert (argc == 1);
267
268 setbuf (stdout, NULL);
269
270 timed_mutex_lock (&gdbstop_mutex);
271
272 timed_mutex_lock (&terminate_mutex);
273
274 i = pthread_create (&thread1, NULL, thread1_func, NULL);
275 assert (i == 0);
276
277 i = pthread_create (&thread2, NULL, thread2_func, NULL);
278 assert (i == 0);
279
280 if (!standalone)
281 {
282 tracer = proc_ulong ("/proc/self/status", "TracerPid:\t");
283 if (tracer == 0)
284 {
285 fprintf (stderr, "The testcase must be run by GDB!\n");
286 exit (EXIT_FAILURE);
287 }
288 if (tracer != getppid ())
289 {
290 fprintf (stderr, "The testcase parent must be our GDB tracer!\n");
291 exit (EXIT_FAILURE);
292 }
293 }
294
295 /* SIGCONT our debugger in the case of our crash as we would deadlock
296 otherwise. */
297
298 atexit (cleanup);
299
300 printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer);
301
302 if (tracer)
303 {
304 i = kill (tracer, SIGSTOP);
305 assert (i == 0);
306 state_wait (tracer, "T (stopped)");
307 }
308
309 timed_mutex_lock (&thread1_tid_mutex);
310 timed_mutex_lock (&thread2_tid_mutex);
311
312 /* Let the threads start. */
313 i = pthread_mutex_unlock (&gdbstop_mutex);
314 assert (i == 0);
315
316 printf ("Waiting till the threads initialize their TIDs.\n");
317
318 if (thread1_tid == 0)
319 {
320 i = pthread_cond_wait (&thread1_tid_cond, &thread1_tid_mutex);
321 assert (i == 0);
322
323 assert (thread1_tid > 0);
324 }
325
326 if (thread2_tid == 0)
327 {
328 i = pthread_cond_wait (&thread2_tid_cond, &thread2_tid_mutex);
329 assert (i == 0);
330
331 assert (thread2_tid > 0);
332 }
333
334 printf ("Thread 1 TID = %lu, thread 2 TID = %lu, PID = %lu.\n",
335 (unsigned long) thread1_tid, (unsigned long) thread2_tid,
336 (unsigned long) getpid ());
337
338 printf ("Waiting till the threads get trapped by the watchpoints.\n");
339
340 if (tracer)
341 {
342 /* s390x-unknown-linux-gnu will fail with "R (running)". */
343
344 state_wait (thread1_tid, "T (tracing stop)");
345
346 state_wait (thread2_tid, "T (tracing stop)");
347 }
348
349 cleanup ();
350
351 printf ("Joining the threads.\n");
352
353 i = pthread_mutex_unlock (&terminate_mutex);
354 assert (i == 0);
355
356 i = pthread_join (thread1, NULL);
357 assert (i == 0);
358
359 i = pthread_join (thread2, NULL);
360 assert (i == 0);
361
362 printf ("Exiting.\n"); /* break-at-exit */
363
364 /* Just prevent compiler `warning: unusedX_rwatch defined but not used'. */
365 unused1_rwatch = 1;
366 unused2_rwatch = 2;
367
368 return EXIT_SUCCESS;
369 }
This page took 0.101339 seconds and 4 git commands to generate.