1 /* This testcase is part of GDB, the GNU debugger.
3 Copyright 2010-2014 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)
32 #define tgkill(tgid, tid, sig) syscall (__NR_tgkill, tgid, tid, sig)
34 /* Terminate always in the main task. It can lock up with SIGSTOPped
36 #define TIMEOUT (gettid () == getpid() ? 10 : 15)
38 static pid_t thread1_tid
;
39 static pthread_cond_t thread1_tid_cond
40 = PTHREAD_COND_INITIALIZER
;
41 static pthread_mutex_t thread1_tid_mutex
42 = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
;
43 static int thread1_sigusr1_hit
;
44 static int thread1_sigusr2_hit
;
46 static pid_t thread2_tid
;
47 static pthread_cond_t thread2_tid_cond
48 = PTHREAD_COND_INITIALIZER
;
49 static pthread_mutex_t thread2_tid_mutex
50 = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
;
51 static int thread2_sigusr1_hit
;
52 static int thread2_sigusr2_hit
;
54 static pthread_mutex_t terminate_mutex
55 = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
;
57 /* Do not use alarm as it would create a ptrace event which would hang
58 us up if we are being traced by GDB, which we stopped
62 timed_mutex_lock (pthread_mutex_t
*mutex
)
65 struct timespec start
, now
;
67 i
= clock_gettime (CLOCK_MONOTONIC
, &start
);
72 i
= pthread_mutex_trylock (mutex
);
77 i
= clock_gettime (CLOCK_MONOTONIC
, &now
);
79 assert (now
.tv_sec
>= start
.tv_sec
);
81 while (now
.tv_sec
- start
.tv_sec
< TIMEOUT
);
83 fprintf (stderr
, "Timed out waiting for internal lock!\n");
88 handler (int signo
, siginfo_t
*siginfo
, void *exception
)
92 assert (siginfo
->si_signo
== signo
);
93 assert (siginfo
->si_code
== SI_TKILL
);
94 assert (siginfo
->si_pid
== getpid ());
96 if (gettid () == thread1_tid
)
99 varp
= &thread1_sigusr1_hit
;
100 else if (signo
== SIGUSR2
)
101 varp
= &thread1_sigusr2_hit
;
105 else if (gettid () == thread2_tid
)
107 if (signo
== SIGUSR1
)
108 varp
= &thread2_sigusr1_hit
;
109 else if (signo
== SIGUSR2
)
110 varp
= &thread2_sigusr2_hit
;
119 fprintf (stderr
, "Signal %d for TID %lu has been already hit!\n", signo
,
120 (unsigned long) gettid ());
127 thread1_func (void *unused
)
131 timed_mutex_lock (&thread1_tid_mutex
);
133 /* THREAD1_TID_MUTEX must be already locked to avoid a race. */
134 thread1_tid
= gettid ();
136 i
= pthread_cond_signal (&thread1_tid_cond
);
138 i
= pthread_mutex_unlock (&thread1_tid_mutex
);
141 /* Be sure the "t (tracing stop)" test can proceed for both
143 timed_mutex_lock (&terminate_mutex
);
144 i
= pthread_mutex_unlock (&terminate_mutex
);
147 if (!thread1_sigusr1_hit
)
149 fprintf (stderr
, "Thread 1 signal SIGUSR1 not hit!\n");
152 if (!thread1_sigusr2_hit
)
154 fprintf (stderr
, "Thread 1 signal SIGUSR2 not hit!\n");
162 thread2_func (void *unused
)
166 timed_mutex_lock (&thread2_tid_mutex
);
168 /* THREAD2_TID_MUTEX must be already locked to avoid a race. */
169 thread2_tid
= gettid ();
171 i
= pthread_cond_signal (&thread2_tid_cond
);
173 i
= pthread_mutex_unlock (&thread2_tid_mutex
);
176 /* Be sure the "t (tracing stop)" test can proceed for both
178 timed_mutex_lock (&terminate_mutex
);
179 i
= pthread_mutex_unlock (&terminate_mutex
);
182 if (!thread2_sigusr1_hit
)
184 fprintf (stderr
, "Thread 2 signal SIGUSR1 not hit!\n");
187 if (!thread2_sigusr2_hit
)
189 fprintf (stderr
, "Thread 2 signal SIGUSR2 not hit!\n");
197 proc_string (const char *filename
, const char *line
)
200 static char buf
[LINE_MAX
];
201 size_t line_len
= strlen (line
);
203 f
= fopen (filename
, "r");
206 fprintf (stderr
, "fopen (\"%s\") for \"%s\": %s\n", filename
, line
,
210 while (errno
= 0, fgets (buf
, sizeof (buf
), f
))
214 s
= strchr (buf
, '\n');
218 if (strncmp (buf
, line
, line_len
) != 0)
223 fprintf (stderr
, "fclose (\"%s\") for \"%s\": %s\n", filename
, line
,
228 return &buf
[line_len
];
232 fprintf (stderr
, "fgets (\"%s\": %s\n", filename
, strerror (errno
));
235 fprintf (stderr
, "\"%s\": No line \"%s\" found.\n", filename
, line
);
240 proc_ulong (const char *filename
, const char *line
)
242 const char *s
= proc_string (filename
, line
);
247 retval
= strtol (s
, &end
, 10);
248 if (retval
< 0 || retval
>= LONG_MAX
|| (end
&& *end
))
250 fprintf (stderr
, "\"%s\":\"%s\": %ld, %s\n", filename
, line
, retval
,
258 state_wait (pid_t process
, const char *wanted
)
262 struct timespec start
, now
;
265 i
= asprintf (&filename
, "/proc/%lu/status", (unsigned long) process
);
268 i
= clock_gettime (CLOCK_MONOTONIC
, &start
);
273 state
= proc_string (filename
, "State:\t");
275 /* torvalds/linux-2.6.git 464763cf1c6df632dccc8f2f4c7e50163154a2c0
276 has changed "T (tracing stop)" to "t (tracing stop)". Make the GDB
277 testcase backward compatible with older Linux kernels. */
278 if (strcmp (state
, "T (tracing stop)") == 0)
279 state
= "t (tracing stop)";
281 if (strcmp (state
, wanted
) == 0)
289 perror ("sched_yield()");
293 i
= clock_gettime (CLOCK_MONOTONIC
, &now
);
295 assert (now
.tv_sec
>= start
.tv_sec
);
297 while (now
.tv_sec
- start
.tv_sec
< TIMEOUT
);
299 fprintf (stderr
, "Timed out waiting for PID %lu \"%s\" (now it is \"%s\")!\n",
300 (unsigned long) process
, wanted
, state
);
304 static volatile pid_t tracer
= 0;
305 static pthread_t thread1
, thread2
;
310 printf ("Resuming GDB PID %lu.\n", (unsigned long) tracer
);
315 int tracer_save
= tracer
;
319 i
= kill (tracer_save
, SIGCONT
);
325 main (int argc
, char **argv
)
329 struct sigaction act
;
331 if (argc
== 2 && strcmp (argv
[1], "-s") == 0)
336 setbuf (stdout
, NULL
);
338 timed_mutex_lock (&thread1_tid_mutex
);
339 timed_mutex_lock (&thread2_tid_mutex
);
341 timed_mutex_lock (&terminate_mutex
);
344 memset (&act
, 0, sizeof (act
));
345 act
.sa_sigaction
= handler
;
346 act
.sa_flags
= SA_RESTART
| SA_SIGINFO
;
347 i
= sigemptyset (&act
.sa_mask
);
348 assert_perror (errno
);
350 i
= sigaction (SIGUSR1
, &act
, NULL
);
351 assert_perror (errno
);
353 i
= sigaction (SIGUSR2
, &act
, NULL
);
354 assert_perror (errno
);
357 i
= pthread_create (&thread1
, NULL
, thread1_func
, NULL
);
360 i
= pthread_create (&thread2
, NULL
, thread2_func
, NULL
);
365 tracer
= proc_ulong ("/proc/self/status", "TracerPid:\t");
368 fprintf (stderr
, "The testcase must be run by GDB!\n");
371 if (tracer
!= getppid ())
373 fprintf (stderr
, "The testcase parent must be our GDB tracer!\n");
378 /* SIGCONT our debugger in the case of our crash as we would deadlock
383 printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer
);
387 i
= kill (tracer
, SIGSTOP
);
389 state_wait (tracer
, "T (stopped)");
392 /* Threads are now waiting at timed_mutex_lock (thread1_tid_mutex)
393 and so they could not trigger the signals before GDB is unstopped
394 later. Threads get resumed by the pthread_cond_wait below. Use
395 `while' loops for protection against spurious pthread_cond_wait
398 printf ("Waiting till the threads initialize their TIDs.\n");
400 while (thread1_tid
== 0)
402 i
= pthread_cond_wait (&thread1_tid_cond
, &thread1_tid_mutex
);
406 while (thread2_tid
== 0)
408 i
= pthread_cond_wait (&thread2_tid_cond
, &thread2_tid_mutex
);
412 printf ("Thread 1 TID = %lu, thread 2 TID = %lu, PID = %lu.\n",
413 (unsigned long) thread1_tid
, (unsigned long) thread2_tid
,
414 (unsigned long) getpid ());
417 i
= tgkill (getpid (), thread1_tid
, SIGUSR1
);
418 assert_perror (errno
);
420 i
= tgkill (getpid (), thread1_tid
, SIGUSR2
);
421 assert_perror (errno
);
423 i
= tgkill (getpid (), thread2_tid
, SIGUSR1
);
424 assert_perror (errno
);
426 i
= tgkill (getpid (), thread2_tid
, SIGUSR2
);
427 assert_perror (errno
);
430 printf ("Waiting till the threads are trapped by the signals.\n");
434 /* s390x-unknown-linux-gnu will fail with "R (running)". */
436 state_wait (thread1_tid
, "t (tracing stop)");
438 state_wait (thread2_tid
, "t (tracing stop)");
443 printf ("Joining the threads.\n");
445 i
= pthread_mutex_unlock (&terminate_mutex
);
448 i
= pthread_join (thread1
, NULL
);
451 i
= pthread_join (thread2
, NULL
);
454 printf ("Exiting.\n"); /* break-at-exit */