1 /* This testcase is part of GDB, the GNU debugger.
3 Copyright 2010-2024 Free Software Foundation, Inc.
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.
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.
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/>. */
26 #include <sys/types.h>
29 #include <asm/unistd.h>
31 #define gettid() syscall (__NR_gettid)
33 /* Terminate always in the main task, it can lock up with SIGSTOPped GDB
35 #define TIMEOUT (gettid () == getpid() ? 10 : 15)
37 static pid_t thread1_tid
;
38 static pthread_cond_t thread1_tid_cond
= PTHREAD_COND_INITIALIZER
;
39 static pthread_mutex_t thread1_tid_mutex
= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
;
41 static pid_t thread2_tid
;
42 static pthread_cond_t thread2_tid_cond
= PTHREAD_COND_INITIALIZER
;
43 static pthread_mutex_t thread2_tid_mutex
= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
;
45 static pthread_mutex_t terminate_mutex
= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
;
47 static pthread_barrier_t threads_started_barrier
;
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. */
52 static void timed_mutex_lock (pthread_mutex_t
*mutex
)
55 struct timespec start
, now
;
57 i
= clock_gettime (CLOCK_MONOTONIC
, &start
);
62 i
= pthread_mutex_trylock (mutex
);
67 i
= clock_gettime (CLOCK_MONOTONIC
, &now
);
69 assert (now
.tv_sec
>= start
.tv_sec
);
71 while (now
.tv_sec
- start
.tv_sec
< TIMEOUT
);
73 fprintf (stderr
, "Timed out waiting for internal lock!\n");
78 thread_func (void *threadno_voidp
)
80 int threadno
= (intptr_t) threadno_voidp
;
83 pthread_barrier_wait (&threads_started_barrier
);
88 timed_mutex_lock (&thread1_tid_mutex
);
90 /* THREAD1_TID_MUTEX must be already locked to avoid race. */
91 thread1_tid
= gettid ();
93 i
= pthread_cond_signal (&thread1_tid_cond
);
95 i
= pthread_mutex_unlock (&thread1_tid_mutex
);
101 timed_mutex_lock (&thread2_tid_mutex
);
103 /* THREAD2_TID_MUTEX must be already locked to avoid race. */
104 thread2_tid
= gettid ();
106 i
= pthread_cond_signal (&thread2_tid_cond
);
108 i
= pthread_mutex_unlock (&thread2_tid_mutex
);
118 asm volatile ("label:\n"
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
);
134 proc_string (const char *filename
, const char *line
)
137 static char buf
[LINE_MAX
];
138 size_t line_len
= strlen (line
);
140 f
= fopen (filename
, "r");
143 fprintf (stderr
, "fopen (\"%s\") for \"%s\": %s\n", filename
, line
,
147 while (errno
= 0, fgets (buf
, sizeof (buf
), f
))
151 s
= strchr (buf
, '\n');
155 if (strncmp (buf
, line
, line_len
) != 0)
160 fprintf (stderr
, "fclose (\"%s\") for \"%s\": %s\n", filename
, line
,
165 return &buf
[line_len
];
169 fprintf (stderr
, "fgets (\"%s\": %s\n", filename
, strerror (errno
));
172 fprintf (stderr
, "\"%s\": No line \"%s\" found.\n", filename
, line
);
177 proc_ulong (const char *filename
, const char *line
)
179 const char *s
= proc_string (filename
, line
);
184 retval
= strtol (s
, &end
, 10);
185 if (retval
< 0 || retval
>= LONG_MAX
|| (end
&& *end
))
187 fprintf (stderr
, "\"%s\":\"%s\": %ld, %s\n", filename
, line
, retval
,
195 state_wait (pid_t process
, const char *wanted
)
199 struct timespec start
, now
;
202 i
= asprintf (&filename
, "/proc/%lu/status", (unsigned long) process
);
205 i
= clock_gettime (CLOCK_MONOTONIC
, &start
);
210 state
= proc_string (filename
, "State:\t");
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)";
218 if (strcmp (state
, wanted
) == 0)
226 perror ("sched_yield()");
230 i
= clock_gettime (CLOCK_MONOTONIC
, &now
);
232 assert (now
.tv_sec
>= start
.tv_sec
);
234 while (now
.tv_sec
- start
.tv_sec
< TIMEOUT
);
236 fprintf (stderr
, "Timed out waiting for PID %lu \"%s\" (now it is \"%s\")!\n",
237 (unsigned long) process
, wanted
, state
);
241 static volatile pid_t tracer
= 0;
242 static pthread_t thread1
, thread2
;
247 printf ("Resuming GDB PID %lu.\n", (unsigned long) tracer
);
252 int tracer_save
= tracer
;
256 i
= kill (tracer_save
, SIGCONT
);
262 main (int argc
, char **argv
)
267 if (argc
== 2 && strcmp (argv
[1], "-s") == 0)
272 setbuf (stdout
, NULL
);
274 timed_mutex_lock (&thread1_tid_mutex
);
275 timed_mutex_lock (&thread2_tid_mutex
);
277 timed_mutex_lock (&terminate_mutex
);
279 pthread_barrier_init (&threads_started_barrier
, NULL
, 3);
281 i
= pthread_create (&thread1
, NULL
, thread_func
, (void *) (intptr_t) 1);
284 i
= pthread_create (&thread2
, NULL
, thread_func
, (void *) (intptr_t) 2);
289 tracer
= proc_ulong ("/proc/self/status", "TracerPid:\t");
292 fprintf (stderr
, "The testcase must be run by GDB!\n");
295 if (tracer
!= getppid ())
297 fprintf (stderr
, "The testcase parent must be our GDB tracer!\n");
302 /* SIGCONT our debugger in the case of our crash as we would deadlock
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
);
312 printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer
);
316 i
= kill (tracer
, SIGSTOP
);
318 state_wait (tracer
, "T (stopped)");
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. */
326 printf ("Waiting till the threads initialize their TIDs.\n");
328 while (thread1_tid
== 0)
330 i
= pthread_cond_wait (&thread1_tid_cond
, &thread1_tid_mutex
);
334 while (thread2_tid
== 0)
336 i
= pthread_cond_wait (&thread2_tid_cond
, &thread2_tid_mutex
);
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 ());
344 printf ("Waiting till the threads get trapped by the breakpoint.\n");
348 /* s390x-unknown-linux-gnu will fail with "R (running)". */
350 state_wait (thread1_tid
, "t (tracing stop)");
352 state_wait (thread2_tid
, "t (tracing stop)");
357 printf ("Joining the threads.\n");
359 i
= pthread_mutex_unlock (&terminate_mutex
);
362 i
= pthread_join (thread1
, NULL
);
365 i
= pthread_join (thread2
, NULL
);
368 printf ("Exiting.\n"); /* break-at-exit */