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 except the one that will exit. 14*99451b44SJordan Rupprecht pseudo_barrier_t g_barrier1; 15*99451b44SJordan Rupprecht 16*99451b44SJordan Rupprecht // A barrier to synchronize all the threads including the one that will exit. 17*99451b44SJordan Rupprecht pseudo_barrier_t g_barrier2; 18*99451b44SJordan Rupprecht 19*99451b44SJordan Rupprecht // A barrier to keep the first group of threads from exiting until after the 20*99451b44SJordan Rupprecht // breakpoint has been passed. 21*99451b44SJordan Rupprecht pseudo_barrier_t g_barrier3; 22*99451b44SJordan Rupprecht 23*99451b44SJordan Rupprecht void * break_thread_func()24*99451b44SJordan Rupprechtbreak_thread_func () 25*99451b44SJordan Rupprecht { 26*99451b44SJordan Rupprecht // Wait until the entire first group of threads is running 27*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier1); 28*99451b44SJordan Rupprecht 29*99451b44SJordan Rupprecht // Wait for the exiting thread to start 30*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier2); 31*99451b44SJordan Rupprecht 32*99451b44SJordan Rupprecht // Do something 33*99451b44SJordan Rupprecht g_test++; // Set breakpoint here 34*99451b44SJordan Rupprecht 35*99451b44SJordan Rupprecht // Synchronize after the breakpoint 36*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier3); 37*99451b44SJordan Rupprecht 38*99451b44SJordan Rupprecht // Return 39*99451b44SJordan Rupprecht return NULL; 40*99451b44SJordan Rupprecht } 41*99451b44SJordan Rupprecht 42*99451b44SJordan Rupprecht void * wait_thread_func()43*99451b44SJordan Rupprechtwait_thread_func () 44*99451b44SJordan Rupprecht { 45*99451b44SJordan Rupprecht // Wait until the entire first group of threads is running 46*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier1); 47*99451b44SJordan Rupprecht 48*99451b44SJordan Rupprecht // Wait for the exiting thread to start 49*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier2); 50*99451b44SJordan Rupprecht 51*99451b44SJordan Rupprecht // Wait until the breakpoint has been passed 52*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier3); 53*99451b44SJordan Rupprecht 54*99451b44SJordan Rupprecht // Return 55*99451b44SJordan Rupprecht return NULL; 56*99451b44SJordan Rupprecht } 57*99451b44SJordan Rupprecht 58*99451b44SJordan Rupprecht void * exit_thread_func()59*99451b44SJordan Rupprechtexit_thread_func () 60*99451b44SJordan Rupprecht { 61*99451b44SJordan Rupprecht // Sync up with the rest of the threads. 62*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier2); 63*99451b44SJordan Rupprecht 64*99451b44SJordan Rupprecht // Try to make sure this thread doesn't exit until the breakpoint is hit. 65*99451b44SJordan Rupprecht std::this_thread::sleep_for(std::chrono::microseconds(1)); 66*99451b44SJordan Rupprecht 67*99451b44SJordan Rupprecht // Return 68*99451b44SJordan Rupprecht return NULL; 69*99451b44SJordan Rupprecht } 70*99451b44SJordan Rupprecht main()71*99451b44SJordan Rupprechtint main () 72*99451b44SJordan Rupprecht { 73*99451b44SJordan Rupprecht 74*99451b44SJordan Rupprecht // The first barrier waits for the non-exiting threads to start. 75*99451b44SJordan Rupprecht // This thread will also participate in that barrier. 76*99451b44SJordan Rupprecht // The idea here is to guarantee that the exiting thread will be 77*99451b44SJordan Rupprecht // last in the internal list maintained by the debugger. 78*99451b44SJordan Rupprecht pseudo_barrier_init(g_barrier1, 5); 79*99451b44SJordan Rupprecht 80*99451b44SJordan Rupprecht // The second break synchronizes thread execution with the breakpoint. 81*99451b44SJordan Rupprecht pseudo_barrier_init(g_barrier2, 5); 82*99451b44SJordan Rupprecht 83*99451b44SJordan Rupprecht // The third barrier keeps the waiting threads around until the breakpoint 84*99451b44SJordan Rupprecht // has been passed. 85*99451b44SJordan Rupprecht pseudo_barrier_init(g_barrier3, 4); 86*99451b44SJordan Rupprecht 87*99451b44SJordan Rupprecht // Create a thread to hit the breakpoint 88*99451b44SJordan Rupprecht std::thread thread_1(break_thread_func); 89*99451b44SJordan Rupprecht 90*99451b44SJordan Rupprecht // Create more threads to slow the debugger down during processing. 91*99451b44SJordan Rupprecht std::thread thread_2(wait_thread_func); 92*99451b44SJordan Rupprecht std::thread thread_3(wait_thread_func); 93*99451b44SJordan Rupprecht std::thread thread_4(wait_thread_func); 94*99451b44SJordan Rupprecht 95*99451b44SJordan Rupprecht // Wait for all these threads to get started. 96*99451b44SJordan Rupprecht pseudo_barrier_wait(g_barrier1); 97*99451b44SJordan Rupprecht 98*99451b44SJordan Rupprecht // Create a thread to exit during the breakpoint 99*99451b44SJordan Rupprecht std::thread thread_5(exit_thread_func); 100*99451b44SJordan Rupprecht 101*99451b44SJordan Rupprecht // Wait for the threads to finish 102*99451b44SJordan Rupprecht thread_5.join(); 103*99451b44SJordan Rupprecht thread_4.join(); 104*99451b44SJordan Rupprecht thread_3.join(); 105*99451b44SJordan Rupprecht thread_2.join(); 106*99451b44SJordan Rupprecht thread_1.join(); 107*99451b44SJordan Rupprecht 108*99451b44SJordan Rupprecht return 0; 109*99451b44SJordan Rupprecht } 110