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 using namespace std; 10 11 #include <pthread.h> 12 13 #include <signal.h> 14 #include <sys/types.h> 15 #include <unistd.h> 16 17 typedef std::vector<std::pair<unsigned, void*(*)(void*)> > action_counts; 18 typedef std::vector<pthread_t> thread_vector; 19 20 pseudo_barrier_t g_barrier; 21 int g_breakpoint = 0; 22 int g_sigusr1_count = 0; 23 uint32_t g_watchme; 24 25 struct action_args { 26 int delay; 27 }; 28 29 // Perform any extra actions required by thread 'input' arg 30 void do_action_args(void *input) { 31 if (input) { 32 action_args *args = static_cast<action_args*>(input); 33 sleep(args->delay); 34 } 35 } 36 37 void * 38 breakpoint_func (void *input) 39 { 40 // Wait until all threads are running 41 pseudo_barrier_wait(g_barrier); 42 do_action_args(input); 43 44 // Do something 45 g_breakpoint++; // Set breakpoint here 46 return 0; 47 } 48 49 void * 50 signal_func (void *input) { 51 // Wait until all threads are running 52 pseudo_barrier_wait(g_barrier); 53 do_action_args(input); 54 55 // Send a user-defined signal to the current process 56 //kill(getpid(), SIGUSR1); 57 // Send a user-defined signal to the current thread 58 pthread_kill(pthread_self(), SIGUSR1); 59 60 return 0; 61 } 62 63 void * 64 watchpoint_func (void *input) { 65 pseudo_barrier_wait(g_barrier); 66 do_action_args(input); 67 68 g_watchme = 1; // watchpoint triggers here 69 return 0; 70 } 71 72 void * 73 crash_func (void *input) { 74 pseudo_barrier_wait(g_barrier); 75 do_action_args(input); 76 77 int *a = 0; 78 *a = 5; // crash happens here 79 return 0; 80 } 81 82 void sigusr1_handler(int sig) { 83 if (sig == SIGUSR1) 84 g_sigusr1_count += 1; // Break here in signal handler 85 } 86 87 /// Register a simple function for to handle signal 88 void register_signal_handler(int signal, void (*handler)(int)) 89 { 90 sigset_t empty_sigset; 91 sigemptyset(&empty_sigset); 92 93 struct sigaction action; 94 action.sa_sigaction = 0; 95 action.sa_mask = empty_sigset; 96 action.sa_flags = 0; 97 action.sa_handler = handler; 98 sigaction(SIGUSR1, &action, 0); 99 } 100 101 void start_threads(thread_vector& threads, 102 action_counts& actions, 103 void* args = 0) { 104 action_counts::iterator b = actions.begin(), e = actions.end(); 105 for(action_counts::iterator i = b; i != e; ++i) { 106 for(unsigned count = 0; count < i->first; ++count) { 107 pthread_t t; 108 pthread_create(&t, 0, i->second, args); 109 threads.push_back(t); 110 } 111 } 112 } 113 114 int dotest() 115 { 116 g_watchme = 0; 117 118 // Actions are triggered immediately after the thread is spawned 119 unsigned num_breakpoint_threads = 1; 120 unsigned num_watchpoint_threads = 0; 121 unsigned num_signal_threads = 1; 122 unsigned num_crash_threads = 0; 123 124 // Actions below are triggered after a 1-second delay 125 unsigned num_delay_breakpoint_threads = 0; 126 unsigned num_delay_watchpoint_threads = 0; 127 unsigned num_delay_signal_threads = 0; 128 unsigned num_delay_crash_threads = 0; 129 130 register_signal_handler(SIGUSR1, sigusr1_handler); // Break here and adjust num_[breakpoint|watchpoint|signal|crash]_threads 131 132 unsigned total_threads = num_breakpoint_threads \ 133 + num_watchpoint_threads \ 134 + num_signal_threads \ 135 + num_crash_threads \ 136 + num_delay_breakpoint_threads \ 137 + num_delay_watchpoint_threads \ 138 + num_delay_signal_threads \ 139 + num_delay_crash_threads; 140 141 // Don't let either thread do anything until they're both ready. 142 pseudo_barrier_init(g_barrier, total_threads); 143 144 action_counts actions; 145 actions.push_back(std::make_pair(num_breakpoint_threads, breakpoint_func)); 146 actions.push_back(std::make_pair(num_watchpoint_threads, watchpoint_func)); 147 actions.push_back(std::make_pair(num_signal_threads, signal_func)); 148 actions.push_back(std::make_pair(num_crash_threads, crash_func)); 149 150 action_counts delay_actions; 151 delay_actions.push_back(std::make_pair(num_delay_breakpoint_threads, breakpoint_func)); 152 delay_actions.push_back(std::make_pair(num_delay_watchpoint_threads, watchpoint_func)); 153 delay_actions.push_back(std::make_pair(num_delay_signal_threads, signal_func)); 154 delay_actions.push_back(std::make_pair(num_delay_crash_threads, crash_func)); 155 156 // Create threads that handle instant actions 157 thread_vector threads; 158 start_threads(threads, actions); 159 160 // Create threads that handle delayed actions 161 action_args delay_arg; 162 delay_arg.delay = 1; 163 start_threads(threads, delay_actions, &delay_arg); 164 165 // Join all threads 166 typedef std::vector<pthread_t>::iterator thread_iterator; 167 for(thread_iterator t = threads.begin(); t != threads.end(); ++t) 168 pthread_join(*t, 0); 169 170 return 0; 171 } 172 173 int main () 174 { 175 dotest(); 176 return 0; // Break here and verify one thread is active. 177 } 178 179 180