1 /* This testcase is part of GDB, the GNU debugger. 2 3 Copyright 2010-2023 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 #define tgkill(tgid, tid, sig) syscall (__NR_tgkill, tgid, tid, sig) 33 34 /* Terminate always in the main task. It can lock up with SIGSTOPped 35 GDB otherwise. */ 36 #define TIMEOUT (gettid () == getpid() ? 10 : 15) 37 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; 45 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; 53 54 static pthread_mutex_t terminate_mutex 55 = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; 56 57 static pthread_barrier_t threads_started_barrier; 58 59 /* Do not use alarm as it would create a ptrace event which would hang 60 us up if we are being traced by GDB, which we stopped 61 ourselves. */ 62 63 static void 64 timed_mutex_lock (pthread_mutex_t *mutex) 65 { 66 int i; 67 struct timespec start, now; 68 69 i = clock_gettime (CLOCK_MONOTONIC, &start); 70 assert (i == 0); 71 72 do 73 { 74 i = pthread_mutex_trylock (mutex); 75 if (i == 0) 76 return; 77 assert (i == EBUSY); 78 79 i = clock_gettime (CLOCK_MONOTONIC, &now); 80 assert (i == 0); 81 assert (now.tv_sec >= start.tv_sec); 82 } 83 while (now.tv_sec - start.tv_sec < TIMEOUT); 84 85 fprintf (stderr, "Timed out waiting for internal lock!\n"); 86 exit (EXIT_FAILURE); 87 } 88 89 static void 90 handler (int signo, siginfo_t *siginfo, void *exception) 91 { 92 int *varp; 93 94 assert (siginfo->si_signo == signo); 95 assert (siginfo->si_code == SI_TKILL); 96 assert (siginfo->si_pid == getpid ()); 97 98 if (gettid () == thread1_tid) 99 { 100 if (signo == SIGUSR1) 101 varp = &thread1_sigusr1_hit; 102 else if (signo == SIGUSR2) 103 varp = &thread1_sigusr2_hit; 104 else 105 assert (0); 106 } 107 else if (gettid () == thread2_tid) 108 { 109 if (signo == SIGUSR1) 110 varp = &thread2_sigusr1_hit; 111 else if (signo == SIGUSR2) 112 varp = &thread2_sigusr2_hit; 113 else 114 assert (0); 115 } 116 else 117 assert (0); 118 119 if (*varp) 120 { 121 fprintf (stderr, "Signal %d for TID %lu has been already hit!\n", signo, 122 (unsigned long) gettid ()); 123 exit (EXIT_FAILURE); 124 } 125 *varp = 1; 126 } 127 128 static void * 129 thread1_func (void *unused) 130 { 131 int i; 132 133 pthread_barrier_wait (&threads_started_barrier); 134 135 timed_mutex_lock (&thread1_tid_mutex); 136 137 /* THREAD1_TID_MUTEX must be already locked to avoid a race. */ 138 thread1_tid = gettid (); 139 140 i = pthread_cond_signal (&thread1_tid_cond); 141 assert (i == 0); 142 i = pthread_mutex_unlock (&thread1_tid_mutex); 143 assert (i == 0); 144 145 /* Be sure the "t (tracing stop)" test can proceed for both 146 threads. */ 147 timed_mutex_lock (&terminate_mutex); 148 i = pthread_mutex_unlock (&terminate_mutex); 149 assert (i == 0); 150 151 if (!thread1_sigusr1_hit) 152 { 153 fprintf (stderr, "Thread 1 signal SIGUSR1 not hit!\n"); 154 exit (EXIT_FAILURE); 155 } 156 if (!thread1_sigusr2_hit) 157 { 158 fprintf (stderr, "Thread 1 signal SIGUSR2 not hit!\n"); 159 exit (EXIT_FAILURE); 160 } 161 162 return NULL; 163 } 164 165 static void * 166 thread2_func (void *unused) 167 { 168 int i; 169 170 pthread_barrier_wait (&threads_started_barrier); 171 172 timed_mutex_lock (&thread2_tid_mutex); 173 174 /* THREAD2_TID_MUTEX must be already locked to avoid a race. */ 175 thread2_tid = gettid (); 176 177 i = pthread_cond_signal (&thread2_tid_cond); 178 assert (i == 0); 179 i = pthread_mutex_unlock (&thread2_tid_mutex); 180 assert (i == 0); 181 182 /* Be sure the "t (tracing stop)" test can proceed for both 183 threads. */ 184 timed_mutex_lock (&terminate_mutex); 185 i = pthread_mutex_unlock (&terminate_mutex); 186 assert (i == 0); 187 188 if (!thread2_sigusr1_hit) 189 { 190 fprintf (stderr, "Thread 2 signal SIGUSR1 not hit!\n"); 191 exit (EXIT_FAILURE); 192 } 193 if (!thread2_sigusr2_hit) 194 { 195 fprintf (stderr, "Thread 2 signal SIGUSR2 not hit!\n"); 196 exit (EXIT_FAILURE); 197 } 198 199 return NULL; 200 } 201 202 static const char * 203 proc_string (const char *filename, const char *line) 204 { 205 FILE *f; 206 static char buf[LINE_MAX]; 207 size_t line_len = strlen (line); 208 209 f = fopen (filename, "r"); 210 if (f == NULL) 211 { 212 fprintf (stderr, "fopen (\"%s\") for \"%s\": %s\n", filename, line, 213 strerror (errno)); 214 exit (EXIT_FAILURE); 215 } 216 while (errno = 0, fgets (buf, sizeof (buf), f)) 217 { 218 char *s; 219 220 s = strchr (buf, '\n'); 221 assert (s != NULL); 222 *s = 0; 223 224 if (strncmp (buf, line, line_len) != 0) 225 continue; 226 227 if (fclose (f)) 228 { 229 fprintf (stderr, "fclose (\"%s\") for \"%s\": %s\n", filename, line, 230 strerror (errno)); 231 exit (EXIT_FAILURE); 232 } 233 234 return &buf[line_len]; 235 } 236 if (errno != 0) 237 { 238 fprintf (stderr, "fgets (\"%s\": %s\n", filename, strerror (errno)); 239 exit (EXIT_FAILURE); 240 } 241 fprintf (stderr, "\"%s\": No line \"%s\" found.\n", filename, line); 242 exit (EXIT_FAILURE); 243 } 244 245 static unsigned long 246 proc_ulong (const char *filename, const char *line) 247 { 248 const char *s = proc_string (filename, line); 249 long retval; 250 char *end; 251 252 errno = 0; 253 retval = strtol (s, &end, 10); 254 if (retval < 0 || retval >= LONG_MAX || (end && *end)) 255 { 256 fprintf (stderr, "\"%s\":\"%s\": %ld, %s\n", filename, line, retval, 257 strerror (errno)); 258 exit (EXIT_FAILURE); 259 } 260 return retval; 261 } 262 263 static void 264 state_wait (pid_t process, const char *wanted) 265 { 266 char *filename; 267 int i; 268 struct timespec start, now; 269 const char *state; 270 271 i = asprintf (&filename, "/proc/%lu/status", (unsigned long) process); 272 assert (i > 0); 273 274 i = clock_gettime (CLOCK_MONOTONIC, &start); 275 assert (i == 0); 276 277 do 278 { 279 state = proc_string (filename, "State:\t"); 280 281 /* torvalds/linux-2.6.git 464763cf1c6df632dccc8f2f4c7e50163154a2c0 282 has changed "T (tracing stop)" to "t (tracing stop)". Make the GDB 283 testcase backward compatible with older Linux kernels. */ 284 if (strcmp (state, "T (tracing stop)") == 0) 285 state = "t (tracing stop)"; 286 287 if (strcmp (state, wanted) == 0) 288 { 289 free (filename); 290 return; 291 } 292 293 if (sched_yield ()) 294 { 295 perror ("sched_yield()"); 296 exit (EXIT_FAILURE); 297 } 298 299 i = clock_gettime (CLOCK_MONOTONIC, &now); 300 assert (i == 0); 301 assert (now.tv_sec >= start.tv_sec); 302 } 303 while (now.tv_sec - start.tv_sec < TIMEOUT); 304 305 fprintf (stderr, "Timed out waiting for PID %lu \"%s\" (now it is \"%s\")!\n", 306 (unsigned long) process, wanted, state); 307 exit (EXIT_FAILURE); 308 } 309 310 static volatile pid_t tracer = 0; 311 static pthread_t thread1, thread2; 312 313 static void 314 cleanup (void) 315 { 316 printf ("Resuming GDB PID %lu.\n", (unsigned long) tracer); 317 318 if (tracer) 319 { 320 int i; 321 int tracer_save = tracer; 322 323 tracer = 0; 324 325 i = kill (tracer_save, SIGCONT); 326 assert (i == 0); 327 } 328 } 329 330 int 331 main (int argc, char **argv) 332 { 333 int i; 334 int standalone = 0; 335 struct sigaction act; 336 337 if (argc == 2 && strcmp (argv[1], "-s") == 0) 338 standalone = 1; 339 else 340 assert (argc == 1); 341 342 setbuf (stdout, NULL); 343 344 timed_mutex_lock (&thread1_tid_mutex); 345 timed_mutex_lock (&thread2_tid_mutex); 346 347 timed_mutex_lock (&terminate_mutex); 348 349 errno = 0; 350 memset (&act, 0, sizeof (act)); 351 act.sa_sigaction = handler; 352 act.sa_flags = SA_RESTART | SA_SIGINFO; 353 i = sigemptyset (&act.sa_mask); 354 assert_perror (errno); 355 assert (i == 0); 356 i = sigaction (SIGUSR1, &act, NULL); 357 assert_perror (errno); 358 assert (i == 0); 359 i = sigaction (SIGUSR2, &act, NULL); 360 assert_perror (errno); 361 assert (i == 0); 362 363 pthread_barrier_init (&threads_started_barrier, NULL, 3); 364 365 i = pthread_create (&thread1, NULL, thread1_func, NULL); 366 assert (i == 0); 367 368 i = pthread_create (&thread2, NULL, thread2_func, NULL); 369 assert (i == 0); 370 371 if (!standalone) 372 { 373 tracer = proc_ulong ("/proc/self/status", "TracerPid:\t"); 374 if (tracer == 0) 375 { 376 fprintf (stderr, "The testcase must be run by GDB!\n"); 377 exit (EXIT_FAILURE); 378 } 379 if (tracer != getppid ()) 380 { 381 fprintf (stderr, "The testcase parent must be our GDB tracer!\n"); 382 exit (EXIT_FAILURE); 383 } 384 } 385 386 /* SIGCONT our debugger in the case of our crash as we would deadlock 387 otherwise. */ 388 389 atexit (cleanup); 390 391 /* Wait until all threads are seen running. On Linux (at least), 392 new threads start stopped, and the debugger must resume them. 393 Need to wait for that before stopping GDB. */ 394 pthread_barrier_wait (&threads_started_barrier); 395 396 printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer); 397 398 if (tracer) 399 { 400 i = kill (tracer, SIGSTOP); 401 assert (i == 0); 402 state_wait (tracer, "T (stopped)"); 403 } 404 405 /* Threads are now waiting at timed_mutex_lock (thread1_tid_mutex) 406 and so they could not trigger the signals before GDB is unstopped 407 later. Threads get resumed by the pthread_cond_wait below. Use 408 `while' loops for protection against spurious pthread_cond_wait 409 wakeups. */ 410 411 printf ("Waiting till the threads initialize their TIDs.\n"); 412 413 while (thread1_tid == 0) 414 { 415 i = pthread_cond_wait (&thread1_tid_cond, &thread1_tid_mutex); 416 assert (i == 0); 417 } 418 419 while (thread2_tid == 0) 420 { 421 i = pthread_cond_wait (&thread2_tid_cond, &thread2_tid_mutex); 422 assert (i == 0); 423 } 424 425 printf ("Thread 1 TID = %lu, thread 2 TID = %lu, PID = %lu.\n", 426 (unsigned long) thread1_tid, (unsigned long) thread2_tid, 427 (unsigned long) getpid ()); 428 429 errno = 0; 430 i = tgkill (getpid (), thread1_tid, SIGUSR1); 431 assert_perror (errno); 432 assert (i == 0); 433 i = tgkill (getpid (), thread1_tid, SIGUSR2); 434 assert_perror (errno); 435 assert (i == 0); 436 i = tgkill (getpid (), thread2_tid, SIGUSR1); 437 assert_perror (errno); 438 assert (i == 0); 439 i = tgkill (getpid (), thread2_tid, SIGUSR2); 440 assert_perror (errno); 441 assert (i == 0); 442 443 printf ("Waiting till the threads are trapped by the signals.\n"); 444 445 if (tracer) 446 { 447 /* s390x-unknown-linux-gnu will fail with "R (running)". */ 448 449 state_wait (thread1_tid, "t (tracing stop)"); 450 451 state_wait (thread2_tid, "t (tracing stop)"); 452 } 453 454 cleanup (); 455 456 printf ("Joining the threads.\n"); 457 458 i = pthread_mutex_unlock (&terminate_mutex); 459 assert (i == 0); 460 461 i = pthread_join (thread1, NULL); 462 assert (i == 0); 463 464 i = pthread_join (thread2, NULL); 465 assert (i == 0); 466 467 printf ("Exiting.\n"); /* break-at-exit */ 468 469 return EXIT_SUCCESS; 470 } 471