main.cpp revision 21f98a38a0cfa10b9935248f1b3628b5ba914402
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>
18using 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
38typedef std::vector<std::pair<unsigned, void*(*)(void*)> > action_counts;
39typedef std::vector<pthread_t> thread_vector;
40
41std::atomic_int g_barrier;
42int g_breakpoint = 0;
43int g_sigusr1_count = 0;
44std::atomic_int g_watchme;
45
46struct action_args {
47  int delay;
48};
49
50// Perform any extra actions required by thread 'input' arg
51void do_action_args(void *input) {
52    if (input) {
53      action_args *args = static_cast<action_args*>(input);
54      sleep(args->delay);
55    }
56}
57
58void *
59breakpoint_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
70void *
71signal_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
84void *
85watchpoint_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
93void *
94crash_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
103void 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
109void 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
122void 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
135int 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
194int main ()
195{
196    dotest();
197    return 0; // Break here and verify one thread is active.
198}
199
200
201