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 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 * 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 * 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 * 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 * 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 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 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 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 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 172 int main () 173 { 174 dotest(); 175 return 0; // Break here and verify one thread is active. 176 } 177 178 179