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