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.
22 pseudo_barrier_t g_barrier1;
23 
24 // A barrier to keep the threads from exiting until after the breakpoint has
25 // been passed.
26 pseudo_barrier_t g_barrier2;
27 
28 void *
29 break_thread_func ()
30 {
31     // Wait until all the threads are running
32     pseudo_barrier_wait(g_barrier1);
33 
34     // Wait for the join thread to join
35     std::this_thread::sleep_for(std::chrono::microseconds(50));
36 
37     // Do something
38     g_test++;       // Set breakpoint here
39 
40     // Synchronize after the breakpoint
41     pseudo_barrier_wait(g_barrier2);
42 
43     // Return
44     return NULL;
45 }
46 
47 void *
48 wait_thread_func ()
49 {
50     // Wait until the entire first group of threads is running
51     pseudo_barrier_wait(g_barrier1);
52 
53     // Wait until the breakpoint has been passed
54     pseudo_barrier_wait(g_barrier2);
55 
56     // Return
57     return NULL;
58 }
59 
60 void *
61 join_thread_func (void *input)
62 {
63     std::thread *thread_to_join = (std::thread *)input;
64 
65     // Sync up with the rest of the threads.
66     pseudo_barrier_wait(g_barrier1);
67 
68     // Join the other thread
69     thread_to_join->join();
70 
71     // Return
72     return NULL;
73 }
74 
75 int main ()
76 {
77     // The first barrier waits for the non-joining threads to start.
78     // This thread will also participate in that barrier.
79     // The idea here is to guarantee that the joining thread will be
80     // last in the internal list maintained by the debugger.
81     pseudo_barrier_init(g_barrier1, 5);
82 
83     // The second barrier keeps the waiting threads around until the breakpoint
84     // has been passed.
85     pseudo_barrier_init(g_barrier2, 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     // Create a thread to join the breakpoint thread
96     std::thread thread_5(join_thread_func, &thread_1);
97 
98     // Wait for the threads to finish
99     thread_5.join();  // implies thread_1 is already finished
100     thread_4.join();
101     thread_3.join();
102     thread_2.join();
103 
104     return 0;
105 }
106