static void * thread1_func (void *unused) { int i; volatile int rwatch_store; timed_mutex_lock (&thread1_tid_mutex); /* THREAD1_TID_MUTEX must be already locked to avoid race. */ thread1_tid = gettid (); i = pthread_cond_signal (&thread1_tid_cond); assert (i == 0); i = pthread_mutex_unlock (&thread1_tid_mutex); assert (i == 0); rwatch_store = thread1_rwatch; /* Be sure the "T (tracing stop)" test can proceed for both threads. */ timed_mutex_lock (&terminate_mutex); i = pthread_mutex_unlock (&terminate_mutex); assert (i == 0); return NULL; }
static void * thread2_func (void *unused) { int i; pthread_barrier_wait (&threads_started_barrier); timed_mutex_lock (&thread2_tid_mutex); /* THREAD2_TID_MUTEX must be already locked to avoid a race. */ thread2_tid = gettid (); i = pthread_cond_signal (&thread2_tid_cond); assert (i == 0); i = pthread_mutex_unlock (&thread2_tid_mutex); assert (i == 0); /* Be sure the "t (tracing stop)" test can proceed for both threads. */ timed_mutex_lock (&terminate_mutex); i = pthread_mutex_unlock (&terminate_mutex); assert (i == 0); if (!thread2_sigusr1_hit) { fprintf (stderr, "Thread 2 signal SIGUSR1 not hit!\n"); exit (EXIT_FAILURE); } if (!thread2_sigusr2_hit) { fprintf (stderr, "Thread 2 signal SIGUSR2 not hit!\n"); exit (EXIT_FAILURE); } return NULL; }
int main (int argc, char **argv) { int i; int standalone = 0; struct sigaction act; if (argc == 2 && strcmp (argv[1], "-s") == 0) standalone = 1; else assert (argc == 1); setbuf (stdout, NULL); timed_mutex_lock (&thread1_tid_mutex); timed_mutex_lock (&thread2_tid_mutex); timed_mutex_lock (&terminate_mutex); errno = 0; memset (&act, 0, sizeof (act)); act.sa_sigaction = handler; act.sa_flags = SA_RESTART | SA_SIGINFO; i = sigemptyset (&act.sa_mask); assert_perror (errno); assert (i == 0); i = sigaction (SIGUSR1, &act, NULL); assert_perror (errno); assert (i == 0); i = sigaction (SIGUSR2, &act, NULL); assert_perror (errno); assert (i == 0); pthread_barrier_init (&threads_started_barrier, NULL, 3); i = pthread_create (&thread1, NULL, thread1_func, NULL); assert (i == 0); i = pthread_create (&thread2, NULL, thread2_func, NULL); assert (i == 0); if (!standalone) { tracer = proc_ulong ("/proc/self/status", "TracerPid:\t"); if (tracer == 0) { fprintf (stderr, "The testcase must be run by GDB!\n"); exit (EXIT_FAILURE); } if (tracer != getppid ()) { fprintf (stderr, "The testcase parent must be our GDB tracer!\n"); exit (EXIT_FAILURE); } } /* SIGCONT our debugger in the case of our crash as we would deadlock otherwise. */ atexit (cleanup); /* Wait until all threads are seen running. On Linux (at least), new threads start stopped, and the debugger must resume them. Need to wait for that before stopping GDB. */ pthread_barrier_wait (&threads_started_barrier); printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer); if (tracer) { i = kill (tracer, SIGSTOP); assert (i == 0); state_wait (tracer, "T (stopped)"); } /* Threads are now waiting at timed_mutex_lock (thread1_tid_mutex) and so they could not trigger the signals before GDB is unstopped later. Threads get resumed by the pthread_cond_wait below. Use `while' loops for protection against spurious pthread_cond_wait wakeups. */ printf ("Waiting till the threads initialize their TIDs.\n"); while (thread1_tid == 0) { i = pthread_cond_wait (&thread1_tid_cond, &thread1_tid_mutex); assert (i == 0); } while (thread2_tid == 0) { i = pthread_cond_wait (&thread2_tid_cond, &thread2_tid_mutex); assert (i == 0); } printf ("Thread 1 TID = %lu, thread 2 TID = %lu, PID = %lu.\n", (unsigned long) thread1_tid, (unsigned long) thread2_tid, (unsigned long) getpid ()); errno = 0; i = tgkill (getpid (), thread1_tid, SIGUSR1); assert_perror (errno); assert (i == 0); i = tgkill (getpid (), thread1_tid, SIGUSR2); assert_perror (errno); assert (i == 0); i = tgkill (getpid (), thread2_tid, SIGUSR1); assert_perror (errno); assert (i == 0); i = tgkill (getpid (), thread2_tid, SIGUSR2); assert_perror (errno); assert (i == 0); printf ("Waiting till the threads are trapped by the signals.\n"); if (tracer) { /* s390x-unknown-linux-gnu will fail with "R (running)". */ state_wait (thread1_tid, "t (tracing stop)"); state_wait (thread2_tid, "t (tracing stop)"); } cleanup (); printf ("Joining the threads.\n"); i = pthread_mutex_unlock (&terminate_mutex); assert (i == 0); i = pthread_join (thread1, NULL); assert (i == 0); i = pthread_join (thread2, NULL); assert (i == 0); printf ("Exiting.\n"); /* break-at-exit */ return EXIT_SUCCESS; }
int main (int argc, char **argv) { int i; int standalone = 0; if (argc == 2 && strcmp (argv[1], "-s") == 0) standalone = 1; else assert (argc == 1); setbuf (stdout, NULL); timed_mutex_lock (&thread1_tid_mutex); timed_mutex_lock (&thread2_tid_mutex); timed_mutex_lock (&terminate_mutex); i = pthread_create (&thread1, NULL, thread1_func, NULL); assert (i == 0); i = pthread_create (&thread2, NULL, thread2_func, NULL); assert (i == 0); if (!standalone) { tracer = proc_ulong ("/proc/self/status", "TracerPid:\t"); if (tracer == 0) { fprintf (stderr, "The testcase must be run by GDB!\n"); exit (EXIT_FAILURE); } if (tracer != getppid ()) { fprintf (stderr, "The testcase parent must be our GDB tracer!\n"); exit (EXIT_FAILURE); } } /* SIGCONT our debugger in the case of our crash as we would deadlock otherwise. */ atexit (cleanup); printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer); if (tracer) { i = kill (tracer, SIGSTOP); assert (i == 0); state_wait (tracer, "T (stopped)"); } /* Threads are now waiting at timed_mutex_lock (thread1_tid_mutex) and so they could not trigger the watchpoints before GDB gets unstopped later. Threads get resumed at pthread_cond_wait below. Use `while' loops for protection against spurious pthread_cond_wait wakeups. */ printf ("Waiting till the threads initialize their TIDs.\n"); while (thread1_tid == 0) { i = pthread_cond_wait (&thread1_tid_cond, &thread1_tid_mutex); assert (i == 0); } while (thread2_tid == 0) { i = pthread_cond_wait (&thread2_tid_cond, &thread2_tid_mutex); assert (i == 0); } printf ("Thread 1 TID = %lu, thread 2 TID = %lu, PID = %lu.\n", (unsigned long) thread1_tid, (unsigned long) thread2_tid, (unsigned long) getpid ()); printf ("Waiting till the threads get trapped by the watchpoints.\n"); if (tracer) { /* s390x-unknown-linux-gnu will fail with "R (running)". */ state_wait (thread1_tid, "T (tracing stop)"); state_wait (thread2_tid, "T (tracing stop)"); } cleanup (); printf ("Joining the threads.\n"); i = pthread_mutex_unlock (&terminate_mutex); assert (i == 0); i = pthread_join (thread1, NULL); assert (i == 0); i = pthread_join (thread2, NULL); assert (i == 0); printf ("Exiting.\n"); /* break-at-exit */ /* Just prevent compiler `warning: unusedX_rwatch defined but not used'. */ unused1_rwatch = 1; unused2_rwatch = 2; return EXIT_SUCCESS; }