xref: /llvm-project/lldb/test/API/functionalities/thread/exit_during_break/main.cpp (revision fdea9a4ec9b0d9585b8fe8a612686d9f44f40ddc)
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()24 break_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()43 wait_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()59 exit_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()71 int 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