Home | History | Annotate | Download | only in break_after_join
      1 //===-- main.cpp ------------------------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 // This test is intended to create a situation in which one thread will exit
     11 // while a breakpoint is being handled in another thread.  This may not always
     12 // happen because it's possible that the exiting thread will exit before the
     13 // breakpoint is hit.  The test case should be flexible enough to treat that
     14 // as success.
     15 
     16 #include <pthread.h>
     17 #include <unistd.h>
     18 #include <atomic>
     19 
     20 volatile int g_test = 0;
     21 
     22 // Note that although hogging the CPU while waiting for a variable to change
     23 // would be terrible in production code, it's great for testing since it
     24 // avoids a lot of messy context switching to get multiple threads synchronized.
     25 #define do_nothing()
     26 
     27 #define pseudo_barrier_wait(bar) \
     28     --bar;                       \
     29     while (bar > 0)              \
     30         do_nothing();
     31 
     32 #define pseudo_barrier_init(bar, count) (bar = count)
     33 
     34 // A barrier to synchronize all the threads.
     35 std::atomic_int g_barrier1;
     36 
     37 // A barrier to keep the threads from exiting until after the breakpoint has
     38 // been passed.
     39 std::atomic_int g_barrier2;
     40 
     41 void *
     42 break_thread_func (void *input)
     43 {
     44     // Wait until all the threads are running
     45     pseudo_barrier_wait(g_barrier1);
     46 
     47     // Wait for the join thread to join
     48     usleep(50);
     49 
     50     // Do something
     51     g_test++;       // Set breakpoint here
     52 
     53     // Synchronize after the breakpoint
     54     pseudo_barrier_wait(g_barrier2);
     55 
     56     // Return
     57     return NULL;
     58 }
     59 
     60 void *
     61 wait_thread_func (void *input)
     62 {
     63     // Wait until the entire first group of threads is running
     64     pseudo_barrier_wait(g_barrier1);
     65 
     66     // Wait until the breakpoint has been passed
     67     pseudo_barrier_wait(g_barrier2);
     68 
     69     // Return
     70     return NULL;
     71 }
     72 
     73 void *
     74 join_thread_func (void *input)
     75 {
     76     pthread_t *thread_to_join = (pthread_t*)input;
     77 
     78     // Sync up with the rest of the threads.
     79     pseudo_barrier_wait(g_barrier1);
     80 
     81     // Join the other thread
     82     pthread_join(*thread_to_join, NULL);
     83 
     84     // Return
     85     return NULL;
     86 }
     87 
     88 int main ()
     89 {
     90     pthread_t thread_1;
     91     pthread_t thread_2;
     92     pthread_t thread_3;
     93     pthread_t thread_4;
     94     pthread_t thread_5;
     95 
     96     // The first barrier waits for the non-joining threads to start.
     97     // This thread will also participate in that barrier.
     98     // The idea here is to guarantee that the joining thread will be
     99     // last in the internal list maintained by the debugger.
    100     pseudo_barrier_init(g_barrier1, 5);
    101 
    102     // The second barrier keeps the waiting threads around until the breakpoint
    103     // has been passed.
    104     pseudo_barrier_init(g_barrier2, 4);
    105 
    106     // Create a thread to hit the breakpoint
    107     pthread_create (&thread_1, NULL, break_thread_func, NULL);
    108 
    109     // Create more threads to slow the debugger down during processing.
    110     pthread_create (&thread_2, NULL, wait_thread_func, NULL);
    111     pthread_create (&thread_3, NULL, wait_thread_func, NULL);
    112     pthread_create (&thread_4, NULL, wait_thread_func, NULL);
    113 
    114     // Create a thread to join the breakpoint thread
    115     pthread_create (&thread_5, NULL, join_thread_func, &thread_4);
    116 
    117     // Wait for the threads to finish
    118     pthread_join(thread_5, NULL);
    119     pthread_join(thread_4, NULL);
    120     pthread_join(thread_3, NULL);
    121     pthread_join(thread_2, NULL);
    122     pthread_join(thread_1, NULL);
    123 
    124     return 0;
    125 }
    126