Ejemplo n.º 1
0
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;
}