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