brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · 84d8c70 Raw
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