1 /* This testcase is part of GDB, the GNU debugger.
3 Copyright 2009-2023 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 /* These variables must have lower in-memory addresses than thread1_rwatch and
50 thread2_rwatch so that they take their watchpoint slots. */
52 static int unused1_rwatch
;
53 static int unused2_rwatch
;
55 static volatile int thread1_rwatch
;
56 static volatile int thread2_rwatch
;
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. */
61 static void timed_mutex_lock (pthread_mutex_t
*mutex
)
64 struct timespec start
, now
;
66 i
= clock_gettime (CLOCK_MONOTONIC
, &start
);
71 i
= pthread_mutex_trylock (mutex
);
76 i
= clock_gettime (CLOCK_MONOTONIC
, &now
);
78 assert (now
.tv_sec
>= start
.tv_sec
);
80 while (now
.tv_sec
- start
.tv_sec
< TIMEOUT
);
82 fprintf (stderr
, "Timed out waiting for internal lock!\n");
87 thread1_func (void *unused
)
90 volatile int rwatch_store
;
92 pthread_barrier_wait (&threads_started_barrier
);
94 timed_mutex_lock (&thread1_tid_mutex
);
96 /* THREAD1_TID_MUTEX must be already locked to avoid race. */
97 thread1_tid
= gettid ();
99 i
= pthread_cond_signal (&thread1_tid_cond
);
101 i
= pthread_mutex_unlock (&thread1_tid_mutex
);
104 rwatch_store
= thread1_rwatch
;
106 /* Be sure the "t (tracing stop)" test can proceed for both threads. */
107 timed_mutex_lock (&terminate_mutex
);
108 i
= pthread_mutex_unlock (&terminate_mutex
);
115 thread2_func (void *unused
)
118 volatile int rwatch_store
;
120 pthread_barrier_wait (&threads_started_barrier
);
122 timed_mutex_lock (&thread2_tid_mutex
);
124 /* THREAD2_TID_MUTEX must be already locked to avoid race. */
125 thread2_tid
= gettid ();
127 i
= pthread_cond_signal (&thread2_tid_cond
);
129 i
= pthread_mutex_unlock (&thread2_tid_mutex
);
132 rwatch_store
= thread2_rwatch
;
134 /* Be sure the "t (tracing stop)" test can proceed for both threads. */
135 timed_mutex_lock (&terminate_mutex
);
136 i
= pthread_mutex_unlock (&terminate_mutex
);
143 proc_string (const char *filename
, const char *line
)
146 static char buf
[LINE_MAX
];
147 size_t line_len
= strlen (line
);
149 f
= fopen (filename
, "r");
152 fprintf (stderr
, "fopen (\"%s\") for \"%s\": %s\n", filename
, line
,
156 while (errno
= 0, fgets (buf
, sizeof (buf
), f
))
160 s
= strchr (buf
, '\n');
164 if (strncmp (buf
, line
, line_len
) != 0)
169 fprintf (stderr
, "fclose (\"%s\") for \"%s\": %s\n", filename
, line
,
174 return &buf
[line_len
];
178 fprintf (stderr
, "fgets (\"%s\": %s\n", filename
, strerror (errno
));
181 fprintf (stderr
, "\"%s\": No line \"%s\" found.\n", filename
, line
);
186 proc_ulong (const char *filename
, const char *line
)
188 const char *s
= proc_string (filename
, line
);
193 retval
= strtol (s
, &end
, 10);
194 if (retval
< 0 || retval
>= LONG_MAX
|| (end
&& *end
))
196 fprintf (stderr
, "\"%s\":\"%s\": %ld, %s\n", filename
, line
, retval
,
204 state_wait (pid_t process
, const char *wanted
)
208 struct timespec start
, now
;
211 i
= asprintf (&filename
, "/proc/%lu/status", (unsigned long) process
);
214 i
= clock_gettime (CLOCK_MONOTONIC
, &start
);
219 state
= proc_string (filename
, "State:\t");
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)";
227 if (strcmp (state
, wanted
) == 0)
235 perror ("sched_yield()");
239 i
= clock_gettime (CLOCK_MONOTONIC
, &now
);
241 assert (now
.tv_sec
>= start
.tv_sec
);
243 while (now
.tv_sec
- start
.tv_sec
< TIMEOUT
);
245 fprintf (stderr
, "Timed out waiting for PID %lu \"%s\" (now it is \"%s\")!\n",
246 (unsigned long) process
, wanted
, state
);
250 static volatile pid_t tracer
= 0;
251 static pthread_t thread1
, thread2
;
256 printf ("Resuming GDB PID %lu.\n", (unsigned long) tracer
);
261 int tracer_save
= tracer
;
265 i
= kill (tracer_save
, SIGCONT
);
271 main (int argc
, char **argv
)
276 if (argc
== 2 && strcmp (argv
[1], "-s") == 0)
281 setbuf (stdout
, NULL
);
283 timed_mutex_lock (&thread1_tid_mutex
);
284 timed_mutex_lock (&thread2_tid_mutex
);
286 timed_mutex_lock (&terminate_mutex
);
288 pthread_barrier_init (&threads_started_barrier
, NULL
, 3);
290 i
= pthread_create (&thread1
, NULL
, thread1_func
, NULL
);
293 i
= pthread_create (&thread2
, NULL
, thread2_func
, NULL
);
298 tracer
= proc_ulong ("/proc/self/status", "TracerPid:\t");
301 fprintf (stderr
, "The testcase must be run by GDB!\n");
304 if (tracer
!= getppid ())
306 fprintf (stderr
, "The testcase parent must be our GDB tracer!\n");
311 /* SIGCONT our debugger in the case of our crash as we would deadlock
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
);
321 printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer
);
325 i
= kill (tracer
, SIGSTOP
);
327 state_wait (tracer
, "T (stopped)");
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. */
335 printf ("Waiting till the threads initialize their TIDs.\n");
337 while (thread1_tid
== 0)
339 i
= pthread_cond_wait (&thread1_tid_cond
, &thread1_tid_mutex
);
343 while (thread2_tid
== 0)
345 i
= pthread_cond_wait (&thread2_tid_cond
, &thread2_tid_mutex
);
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 ());
353 printf ("Waiting till the threads get trapped by the watchpoints.\n");
357 /* s390x-unknown-linux-gnu will fail with "R (running)". */
359 state_wait (thread1_tid
, "t (tracing stop)");
361 state_wait (thread2_tid
, "t (tracing stop)");
366 printf ("Joining the threads.\n");
368 i
= pthread_mutex_unlock (&terminate_mutex
);
371 i
= pthread_join (thread1
, NULL
);
374 i
= pthread_join (thread2
, NULL
);
377 printf ("Exiting.\n"); /* break-at-exit */
379 /* Just prevent compiler `warning: unusedX_rwatch defined but not used'. */