// Stress test for https://reviews.llvm.org/D101881 // RUN: %clangxx_hwasan -DREUSE=0 %s -pthread -O2 -o %t && %run %t 2>&1 // RUN: %clangxx_hwasan -DREUSE=1 %s -pthread -O2 -o %t_reuse && %run %t_reuse 2>&1 #include #include #include #include #include #include constexpr int kTopThreads = 20; constexpr int kChildThreads = 30; constexpr int kChildIterations = REUSE ? 8 : 1; constexpr int kProcessIterations = 20; void Thread() { for (int i = 0; i < kChildIterations; ++i) { std::vector threads; threads.reserve(kChildThreads); for (int i = 0; i < kChildThreads; ++i) threads.emplace_back([]() {}); for (auto &t : threads) t.join(); } } void run() { std::vector threads; threads.reserve(kTopThreads); for (int i = 0; i < kTopThreads; ++i) threads.emplace_back(Thread); for (auto &t : threads) t.join(); } int main() { #if REUSE // Test thread reuse with multiple iterations of thread create / join in a single process. run(); #else // Test new, non-reused thread creation by running a single iteration of create / join in a freshly started process. for (int i = 0; i < kProcessIterations; ++i) { int pid = fork(); if (pid) { int wstatus; do { waitpid(pid, &wstatus, 0); } while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus)); if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) { fprintf(stderr, "failed at iteration %d / %d\n", i, kProcessIterations); return 1; } } else { run(); return 0; } } #endif }