1 #include "pseudo_barrier.h" 2 #include "thread.h" 3 #include <atomic> 4 #include <chrono> 5 #include <cinttypes> 6 #include <csignal> 7 #include <cstdio> 8 #include <cstdlib> 9 #include <cstring> 10 #include <mutex> 11 #include <thread> 12 #include <unistd.h> 13 #include <vector> 14 15 pseudo_barrier_t barrier; 16 std::mutex print_mutex; 17 std::atomic<bool> can_work = ATOMIC_VAR_INIT(false); 18 thread_local volatile sig_atomic_t can_exit_now = false; 19 20 static void sigusr1_handler(int signo) { 21 std::lock_guard<std::mutex> lock{print_mutex}; 22 std::printf("received SIGUSR1 on thread id: %" PRIx64 "\n", get_thread_id()); 23 can_exit_now = true; 24 } 25 26 static void thread_func() { 27 // this ensures that all threads start before we SIGSTOP 28 pseudo_barrier_wait(barrier); 29 30 // wait till the main thread indicates that we can go 31 // (note: using a mutex here causes hang on FreeBSD when another thread 32 // is suspended) 33 while (!can_work.load()) 34 std::this_thread::sleep_for(std::chrono::milliseconds(50)); 35 36 // the mutex guarantees that two writes don't get interspersed 37 { 38 std::lock_guard<std::mutex> lock{print_mutex}; 39 std::printf("thread %" PRIx64 " running\n", get_thread_id()); 40 } 41 42 // give other threads a fair chance to run 43 for (int i = 0; i < 5; ++i) { 44 std::this_thread::yield(); 45 std::this_thread::sleep_for(std::chrono::milliseconds(200)); 46 if (can_exit_now) 47 return; 48 } 49 50 // if we didn't get signaled, terminate the program explicitly. 51 _exit(0); 52 } 53 54 int main(int argc, char **argv) { 55 int num = atoi(argv[1]); 56 57 pseudo_barrier_init(barrier, num + 1); 58 59 signal(SIGUSR1, sigusr1_handler); 60 61 std::vector<std::thread> threads; 62 for (int i = 0; i < num; ++i) 63 threads.emplace_back(thread_func); 64 65 // use the barrier to make sure all threads start before we SIGSTOP 66 pseudo_barrier_wait(barrier); 67 std::raise(SIGSTOP); 68 69 // allow the threads to work 70 can_work.store(true); 71 72 for (std::thread &thread : threads) 73 thread.join(); 74 return 0; 75 } 76