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