104b766daSPavel Labath #include "pseudo_barrier.h" 204b766daSPavel Labath #include "thread.h" 39790406aSMichał 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> 109790406aSMichał 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; 169790406aSMichał Górny std::mutex print_mutex; 17*bcb8a945SFangrui Song std::atomic<bool> can_work; 189790406aSMichał Górny thread_local volatile sig_atomic_t can_exit_now = false; 199790406aSMichał Górny sigint_handler(int signo)209790406aSMichał Górnystatic void sigint_handler(int signo) {} 2104b766daSPavel Labath sigusr1_handler(int signo)2204b766daSPavel Labathstatic void sigusr1_handler(int signo) { 239790406aSMichał Górny std::lock_guard<std::mutex> lock{print_mutex}; 249790406aSMichał Górny std::printf("received SIGUSR1 on thread id: %" PRIx64 "\n", get_thread_id()); 259790406aSMichał Górny can_exit_now = true; 2604b766daSPavel Labath } 2704b766daSPavel Labath thread_func()2804b766daSPavel Labathstatic void thread_func() { 299790406aSMichał Górny // this ensures that all threads start before we stop 3004b766daSPavel Labath pseudo_barrier_wait(barrier); 319790406aSMichał Górny 329790406aSMichał Górny // wait till the main thread indicates that we can go 339790406aSMichał Górny // (note: using a mutex here causes hang on FreeBSD when another thread 349790406aSMichał Górny // is suspended) 359790406aSMichał Górny while (!can_work.load()) 369790406aSMichał Górny std::this_thread::sleep_for(std::chrono::milliseconds(50)); 379790406aSMichał Górny 389790406aSMichał Górny // the mutex guarantees that two writes don't get interspersed 399790406aSMichał Górny { 409790406aSMichał 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 } 439790406aSMichał Górny 449790406aSMichał Górny // give other threads a fair chance to run 459790406aSMichał Górny for (int i = 0; i < 5; ++i) { 469790406aSMichał Górny std::this_thread::yield(); 479790406aSMichał Górny std::this_thread::sleep_for(std::chrono::milliseconds(200)); 489790406aSMichał Górny if (can_exit_now) 499790406aSMichał Górny return; 509790406aSMichał Górny } 519790406aSMichał Górny 529790406aSMichał Górny // if we didn't get signaled, terminate the program explicitly. 539790406aSMichał 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 619790406aSMichał 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 689790406aSMichał Górny // use the barrier to make sure all threads start before we stop 6904b766daSPavel Labath pseudo_barrier_wait(barrier); 709790406aSMichał Górny std::raise(SIGINT); 7104b766daSPavel Labath 729790406aSMichał Górny // allow the threads to work 739790406aSMichał 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