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