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