104b766daSPavel Labath #include "pseudo_barrier.h" 204b766daSPavel Labath #include "thread.h" 3*9790406aSMichał Górny #include <atomic> 404b766daSPavel Labath #include <chrono> 504b766daSPavel Labath #include <cinttypes> 604b766daSPavel Labath #include <csignal> 70bbe2a3cSPavel Labath #include <cstdio> 897091866SPavel Labath #include <cstdlib> 904b766daSPavel Labath #include <cstring> 10*9790406aSMichał Górny #include <mutex> 1104b766daSPavel Labath #include <thread> 1204b766daSPavel Labath #include <unistd.h> 1304b766daSPavel Labath #include <vector> 1404b766daSPavel Labath 1504b766daSPavel Labath pseudo_barrier_t barrier; 16*9790406aSMichał Górny std::mutex print_mutex; 17*9790406aSMichał Górny std::atomic<bool> can_work = ATOMIC_VAR_INIT(false); 18*9790406aSMichał Górny thread_local volatile sig_atomic_t can_exit_now = false; 19*9790406aSMichał Górny sigint_handler(int signo)20*9790406aSMichał Górnystatic void sigint_handler(int signo) {} 2104b766daSPavel Labath sigusr1_handler(int signo)2204b766daSPavel Labathstatic void sigusr1_handler(int signo) { 23*9790406aSMichał Górny std::lock_guard<std::mutex> lock{print_mutex}; 24*9790406aSMichał Górny std::printf("received SIGUSR1 on thread id: %" PRIx64 "\n", get_thread_id()); 25*9790406aSMichał Górny can_exit_now = true; 2604b766daSPavel Labath } 2704b766daSPavel Labath thread_func()2804b766daSPavel Labathstatic void thread_func() { 29*9790406aSMichał Górny // this ensures that all threads start before we stop 3004b766daSPavel Labath pseudo_barrier_wait(barrier); 31*9790406aSMichał Górny 32*9790406aSMichał Górny // wait till the main thread indicates that we can go 33*9790406aSMichał Górny // (note: using a mutex here causes hang on FreeBSD when another thread 34*9790406aSMichał Górny // is suspended) 35*9790406aSMichał Górny while (!can_work.load()) 36*9790406aSMichał Górny std::this_thread::sleep_for(std::chrono::milliseconds(50)); 37*9790406aSMichał Górny 38*9790406aSMichał Górny // the mutex guarantees that two writes don't get interspersed 39*9790406aSMichał Górny { 40*9790406aSMichał Górny std::lock_guard<std::mutex> lock{print_mutex}; 41b4f2d7cdSMichał Górny std::printf("thread %" PRIx64 " running\n", get_thread_id()); 4286e47231SMichał Górny } 43*9790406aSMichał Górny 44*9790406aSMichał Górny // give other threads a fair chance to run 45*9790406aSMichał Górny for (int i = 0; i < 5; ++i) { 46*9790406aSMichał Górny std::this_thread::yield(); 47*9790406aSMichał Górny std::this_thread::sleep_for(std::chrono::milliseconds(200)); 48*9790406aSMichał Górny if (can_exit_now) 49*9790406aSMichał Górny return; 50*9790406aSMichał Górny } 51*9790406aSMichał Górny 52*9790406aSMichał Górny // if we didn't get signaled, terminate the program explicitly. 53*9790406aSMichał Górny _exit(0); 5404b766daSPavel Labath } 5504b766daSPavel Labath main(int argc,char ** argv)5604b766daSPavel Labathint main(int argc, char **argv) { 5704b766daSPavel Labath int num = atoi(argv[1]); 5804b766daSPavel Labath 5904b766daSPavel Labath pseudo_barrier_init(barrier, num + 1); 6004b766daSPavel Labath 61*9790406aSMichał Górny signal(SIGINT, sigint_handler); 6204b766daSPavel Labath signal(SIGUSR1, sigusr1_handler); 6304b766daSPavel Labath 6404b766daSPavel Labath std::vector<std::thread> threads; 6504b766daSPavel Labath for (int i = 0; i < num; ++i) 6604b766daSPavel Labath threads.emplace_back(thread_func); 6704b766daSPavel Labath 68*9790406aSMichał Górny // use the barrier to make sure all threads start before we stop 6904b766daSPavel Labath pseudo_barrier_wait(barrier); 70*9790406aSMichał Górny std::raise(SIGINT); 7104b766daSPavel Labath 72*9790406aSMichał Górny // allow the threads to work 73*9790406aSMichał Górny can_work.store(true); 7404b766daSPavel Labath 7504b766daSPavel Labath for (std::thread &thread : threads) 7604b766daSPavel Labath thread.join(); 7704b766daSPavel Labath return 0; 7804b766daSPavel Labath } 79