xref: /llvm-project/lldb/test/API/tools/lldb-server/vCont-threads/main.cpp (revision bcb8a94503887250d3a818a6b631899e9233080c)
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órny static void sigint_handler(int signo) {}
2104b766daSPavel Labath 
sigusr1_handler(int signo)2204b766daSPavel Labath static 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 Labath static 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 Labath int 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