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