1 //===-- main.cpp ------------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // This test is intended to create a situation in which multiple events
11 // (breakpoints, watchpoints, crashes, and signal generation/delivery) happen
12 // from multiple threads. The test expects the debugger to set a breakpoint on
13 // the main thread (before any worker threads are spawned) and modify variables
14 // which control the number of therads that are spawned for each action.
15 
16 #include <atomic>
17 #include <vector>
18 using namespace std;
19 
20 #include <pthread.h>
21 
22 #include <signal.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 
26 // Note that although hogging the CPU while waiting for a variable to change
27 // would be terrible in production code, it's great for testing since it
28 // avoids a lot of messy context switching to get multiple threads synchronized.
29 #define do_nothing()
30 
31 #define pseudo_barrier_wait(bar) \
32     --bar;                       \
33     while (bar > 0)              \
34         do_nothing();
35 
36 #define pseudo_barrier_init(bar, count) (bar = count)
37 
38 typedef std::vector<std::pair<unsigned, void*(*)(void*)> > action_counts;
39 typedef std::vector<pthread_t> thread_vector;
40 
41 std::atomic_int g_barrier;
42 int g_breakpoint = 0;
43 int g_sigusr1_count = 0;
44 std::atomic_int g_watchme;
45 
46 struct action_args {
47   int delay;
48 };
49 
50 // Perform any extra actions required by thread 'input' arg
do_action_args(void * input)51 void do_action_args(void *input) {
52     if (input) {
53       action_args *args = static_cast<action_args*>(input);
54       sleep(args->delay);
55     }
56 }
57 
58 void *
breakpoint_func(void * input)59 breakpoint_func (void *input)
60 {
61     // Wait until all threads are running
62     pseudo_barrier_wait(g_barrier);
63     do_action_args(input);
64 
65     // Do something
66     g_breakpoint++;       // Set breakpoint here
67     return 0;
68 }
69 
70 void *
signal_func(void * input)71 signal_func (void *input) {
72     // Wait until all threads are running
73     pseudo_barrier_wait(g_barrier);
74     do_action_args(input);
75 
76     // Send a user-defined signal to the current process
77     //kill(getpid(), SIGUSR1);
78     // Send a user-defined signal to the current thread
79     pthread_kill(pthread_self(), SIGUSR1);
80 
81     return 0;
82 }
83 
84 void *
watchpoint_func(void * input)85 watchpoint_func (void *input) {
86     pseudo_barrier_wait(g_barrier);
87     do_action_args(input);
88 
89     g_watchme += 1;     // watchpoint triggers here
90     return 0;
91 }
92 
93 void *
crash_func(void * input)94 crash_func (void *input) {
95     pseudo_barrier_wait(g_barrier);
96     do_action_args(input);
97 
98     int *a = 0;
99     *a = 5; // crash happens here
100     return 0;
101 }
102 
sigusr1_handler(int sig)103 void sigusr1_handler(int sig) {
104     if (sig == SIGUSR1)
105         g_sigusr1_count += 1; // Break here in signal handler
106 }
107 
108 /// Register a simple function for to handle signal
register_signal_handler(int signal,void (* handler)(int))109 void register_signal_handler(int signal, void (*handler)(int))
110 {
111     sigset_t empty_sigset;
112     sigemptyset(&empty_sigset);
113 
114     struct sigaction action;
115     action.sa_sigaction = 0;
116     action.sa_mask = empty_sigset;
117     action.sa_flags = 0;
118     action.sa_handler = handler;
119     sigaction(SIGUSR1, &action, 0);
120 }
121 
start_threads(thread_vector & threads,action_counts & actions,void * args=0)122 void start_threads(thread_vector& threads,
123                    action_counts& actions,
124                    void* args = 0) {
125     action_counts::iterator b = actions.begin(), e = actions.end();
126     for(action_counts::iterator i = b; i != e; ++i) {
127         for(unsigned count = 0; count < i->first; ++count) {
128             pthread_t t;
129             pthread_create(&t, 0, i->second, args);
130             threads.push_back(t);
131         }
132     }
133 }
134 
dotest()135 int dotest()
136 {
137     g_watchme = 0;
138 
139     // Actions are triggered immediately after the thread is spawned
140     unsigned num_breakpoint_threads = 1;
141     unsigned num_watchpoint_threads = 0;
142     unsigned num_signal_threads = 1;
143     unsigned num_crash_threads = 0;
144 
145     // Actions below are triggered after a 1-second delay
146     unsigned num_delay_breakpoint_threads = 0;
147     unsigned num_delay_watchpoint_threads = 0;
148     unsigned num_delay_signal_threads = 0;
149     unsigned num_delay_crash_threads = 0;
150 
151     register_signal_handler(SIGUSR1, sigusr1_handler); // Break here and adjust num_[breakpoint|watchpoint|signal|crash]_threads
152 
153     unsigned total_threads = num_breakpoint_threads \
154                              + num_watchpoint_threads \
155                              + num_signal_threads \
156                              + num_crash_threads \
157                              + num_delay_breakpoint_threads \
158                              + num_delay_watchpoint_threads \
159                              + num_delay_signal_threads \
160                              + num_delay_crash_threads;
161 
162     // Don't let either thread do anything until they're both ready.
163     pseudo_barrier_init(g_barrier, total_threads);
164 
165     action_counts actions;
166     actions.push_back(std::make_pair(num_breakpoint_threads, breakpoint_func));
167     actions.push_back(std::make_pair(num_watchpoint_threads, watchpoint_func));
168     actions.push_back(std::make_pair(num_signal_threads, signal_func));
169     actions.push_back(std::make_pair(num_crash_threads, crash_func));
170 
171     action_counts delay_actions;
172     actions.push_back(std::make_pair(num_delay_breakpoint_threads, breakpoint_func));
173     actions.push_back(std::make_pair(num_delay_watchpoint_threads, watchpoint_func));
174     actions.push_back(std::make_pair(num_delay_signal_threads, signal_func));
175     actions.push_back(std::make_pair(num_delay_crash_threads, crash_func));
176 
177     // Create threads that handle instant actions
178     thread_vector threads;
179     start_threads(threads, actions);
180 
181     // Create threads that handle delayed actions
182     action_args delay_arg;
183     delay_arg.delay = 1;
184     start_threads(threads, delay_actions, &delay_arg);
185 
186     // Join all threads
187     typedef std::vector<pthread_t>::iterator thread_iterator;
188     for(thread_iterator t = threads.begin(); t != threads.end(); ++t)
189         pthread_join(*t, 0);
190 
191     return 0;
192 }
193 
main()194 int main ()
195 {
196     dotest();
197     return 0; // Break here and verify one thread is active.
198 }
199 
200 
201