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