179 lines · cpp
1// This test is intended to create a situation in which multiple events2// (breakpoints, watchpoints, crashes, and signal generation/delivery) happen3// from multiple threads. The test expects the debugger to set a breakpoint on4// the main thread (before any worker threads are spawned) and modify variables5// 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 16typedef std::vector<std::pair<unsigned, void*(*)(void*)> > action_counts;17typedef std::vector<pthread_t> thread_vector;18 19pseudo_barrier_t g_barrier;20int g_breakpoint = 0;21int g_sigusr1_count = 0;22uint32_t g_watchme;23 24struct action_args {25 int delay;26};27 28// Perform any extra actions required by thread 'input' arg29void do_action_args(void *input) {30 if (input) {31 action_args *args = static_cast<action_args*>(input);32 sleep(args->delay);33 }34}35 36void *37breakpoint_func (void *input)38{39 // Wait until all threads are running40 pseudo_barrier_wait(g_barrier);41 do_action_args(input);42 43 // Do something44 g_breakpoint++; // Set breakpoint here45 return 0;46}47 48void *49signal_func (void *input) {50 // Wait until all threads are running51 pseudo_barrier_wait(g_barrier);52 do_action_args(input);53 54 // Send a user-defined signal to the current process55 //kill(getpid(), SIGUSR1);56 // Send a user-defined signal to the current thread57 pthread_kill(pthread_self(), SIGUSR1);58 59 return 0;60}61 62void *63watchpoint_func (void *input) {64 pseudo_barrier_wait(g_barrier);65 do_action_args(input);66 67 g_watchme = 1; // watchpoint triggers here68 return 0;69}70 71void *72crash_func (void *input) {73 pseudo_barrier_wait(g_barrier);74 do_action_args(input);75 76 int *a = 0;77 *a = 5; // crash happens here78 return 0;79}80 81void sigusr1_handler(int sig) {82 if (sig == SIGUSR1)83 g_sigusr1_count += 1; // Break here in signal handler84}85 86/// Register a simple function for to handle signal87void 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 100void 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 113int dotest()114{115 g_watchme = 0;116 117 // Actions are triggered immediately after the thread is spawned118 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 delay124 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]_threads130 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 actions156 thread_vector threads;157 start_threads(threads, actions);158 159 // Create threads that handle delayed actions160 action_args delay_arg;161 delay_arg.delay = 1;162 start_threads(threads, delay_actions, &delay_arg);163 164 // Join all threads165 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 172int main ()173{174 dotest();175 return 0; // Break here and verify one thread is active.176}177 178 179