1 /* This testcase is part of GDB, the GNU debugger. 2 3 Copyright 2010-2016 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 33 /* Terminate always in the main task, it can lock up with SIGSTOPped GDB 34 otherwise. */ 35 #define TIMEOUT (gettid () == getpid() ? 10 : 15) 36 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; 40 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; 44 45 static pthread_mutex_t terminate_mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; 46 47 static pthread_barrier_t threads_started_barrier; 48 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 52 static 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 77 static void * 78 thread_func (void *threadno_voidp) 79 { 80 int threadno = (intptr_t) threadno_voidp; 81 int i; 82 83 pthread_barrier_wait (&threads_started_barrier); 84 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 133 static const char * 134 proc_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 176 static unsigned long 177 proc_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 194 static void 195 state_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 241 static volatile pid_t tracer = 0; 242 static pthread_t thread1, thread2; 243 244 static void 245 cleanup (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 261 int 262 main (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 279 pthread_barrier_init (&threads_started_barrier, NULL, 3); 280 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 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 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 } 372