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