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