xref: /llvm-project/lldb/test/API/functionalities/thread/concurrent_events/main.cpp (revision 9bd72b5c258549b8743557a79c7929de38f05a6d)
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