1*99451b44SJordan Rupprecht // This test is intended to create a situation in which one thread will exit 2*99451b44SJordan Rupprecht // while a breakpoint is being handled in another thread. This may not always 3*99451b44SJordan Rupprecht // happen because it's possible that the exiting thread will exit before the 4*99451b44SJordan Rupprecht // breakpoint is hit. The test case should be flexible enough to treat that 5*99451b44SJordan Rupprecht // as success. 6*99451b44SJordan Rupprecht 7*99451b44SJordan Rupprecht #include "pseudo_barrier.h" 8*99451b44SJordan Rupprecht #include <chrono> 9*99451b44SJordan Rupprecht #include <thread> 10*99451b44SJordan Rupprecht 11*99451b44SJordan Rupprecht volatile int g_test = 0; 12*99451b44SJordan Rupprecht 13*99451b44SJordan Rupprecht // A barrier to synchronize all the threads. 14*99451b44SJordan Rupprecht pseudo_barrier_t g_barrier1; 15*99451b44SJordan Rupprecht 16*99451b44SJordan Rupprecht // A barrier to keep the threads from exiting until after the breakpoint has 17*99451b44SJordan Rupprecht // been passed. 18*99451b44SJordan Rupprecht pseudo_barrier_t g_barrier2; 19*99451b44SJordan Rupprecht 20*99451b44SJordan Rupprecht void * break_thread_func()21*99451b44SJordan Rupprechtbreak_thread_func () 22*99451b44SJordan Rupprecht { 23*99451b44SJordan Rupprecht // Wait until all the threads are running 24*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier1); 25*99451b44SJordan Rupprecht 26*99451b44SJordan Rupprecht // Wait for the join thread to join 27*99451b44SJordan Rupprecht std::this_thread::sleep_for(std::chrono::microseconds(50)); 28*99451b44SJordan Rupprecht 29*99451b44SJordan Rupprecht // Do something 30*99451b44SJordan Rupprecht g_test++; // Set breakpoint here 31*99451b44SJordan Rupprecht 32*99451b44SJordan Rupprecht // Synchronize after the breakpoint 33*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier2); 34*99451b44SJordan Rupprecht 35*99451b44SJordan Rupprecht // Return 36*99451b44SJordan Rupprecht return NULL; 37*99451b44SJordan Rupprecht } 38*99451b44SJordan Rupprecht 39*99451b44SJordan Rupprecht void * wait_thread_func()40*99451b44SJordan Rupprechtwait_thread_func () 41*99451b44SJordan Rupprecht { 42*99451b44SJordan Rupprecht // Wait until the entire first group of threads is running 43*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier1); 44*99451b44SJordan Rupprecht 45*99451b44SJordan Rupprecht // Wait until the breakpoint has been passed 46*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier2); 47*99451b44SJordan Rupprecht 48*99451b44SJordan Rupprecht // Return 49*99451b44SJordan Rupprecht return NULL; 50*99451b44SJordan Rupprecht } 51*99451b44SJordan Rupprecht 52*99451b44SJordan Rupprecht void * join_thread_func(void * input)53*99451b44SJordan Rupprechtjoin_thread_func (void *input) 54*99451b44SJordan Rupprecht { 55*99451b44SJordan Rupprecht std::thread *thread_to_join = (std::thread *)input; 56*99451b44SJordan Rupprecht 57*99451b44SJordan Rupprecht // Sync up with the rest of the threads. 58*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier1); 59*99451b44SJordan Rupprecht 60*99451b44SJordan Rupprecht // Join the other thread 61*99451b44SJordan Rupprecht thread_to_join->join(); 62*99451b44SJordan Rupprecht 63*99451b44SJordan Rupprecht // Return 64*99451b44SJordan Rupprecht return NULL; 65*99451b44SJordan Rupprecht } 66*99451b44SJordan Rupprecht main()67*99451b44SJordan Rupprechtint main () 68*99451b44SJordan Rupprecht { 69*99451b44SJordan Rupprecht // The first barrier waits for the non-joining threads to start. 70*99451b44SJordan Rupprecht // This thread will also participate in that barrier. 71*99451b44SJordan Rupprecht // The idea here is to guarantee that the joining thread will be 72*99451b44SJordan Rupprecht // last in the internal list maintained by the debugger. 73*99451b44SJordan Rupprecht pseudo_barrier_init(g_barrier1, 5); 74*99451b44SJordan Rupprecht 75*99451b44SJordan Rupprecht // The second barrier keeps the waiting threads around until the breakpoint 76*99451b44SJordan Rupprecht // has been passed. 77*99451b44SJordan Rupprecht pseudo_barrier_init(g_barrier2, 4); 78*99451b44SJordan Rupprecht 79*99451b44SJordan Rupprecht // Create a thread to hit the breakpoint 80*99451b44SJordan Rupprecht std::thread thread_1(break_thread_func); 81*99451b44SJordan Rupprecht 82*99451b44SJordan Rupprecht // Create more threads to slow the debugger down during processing. 83*99451b44SJordan Rupprecht std::thread thread_2(wait_thread_func); 84*99451b44SJordan Rupprecht std::thread thread_3(wait_thread_func); 85*99451b44SJordan Rupprecht std::thread thread_4(wait_thread_func); 86*99451b44SJordan Rupprecht 87*99451b44SJordan Rupprecht // Create a thread to join the breakpoint thread 88*99451b44SJordan Rupprecht std::thread thread_5(join_thread_func, &thread_1); 89*99451b44SJordan Rupprecht 90*99451b44SJordan Rupprecht // Wait for the threads to finish 91*99451b44SJordan Rupprecht thread_5.join(); // implies thread_1 is already finished 92*99451b44SJordan Rupprecht thread_4.join(); 93*99451b44SJordan Rupprecht thread_3.join(); 94*99451b44SJordan Rupprecht thread_2.join(); 95*99451b44SJordan Rupprecht 96*99451b44SJordan Rupprecht return 0; 97*99451b44SJordan Rupprecht } 98