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