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