//===- unittests/Threading.cpp - Thread tests -----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/Support/Threading.h" #include "llvm/Support/thread.h" #include "llvm/TargetParser/Host.h" #include "llvm/TargetParser/Triple.h" #include "gtest/gtest.h" #include #include using namespace llvm; namespace { static bool isThreadingSupportedArchAndOS() { #if LLVM_ENABLE_THREADS Triple Host(Triple::normalize(sys::getProcessTriple())); // Initially this is only testing detection of the number of // physical cores, which is currently only supported/tested on // some systems. return (Host.isOSWindows() && llvm_is_multithreaded()) || Host.isOSDarwin() || (Host.isX86() && Host.isOSLinux()) || (Host.isOSLinux() && !Host.isAndroid()) || (Host.isSystemZ() && Host.isOSzOS()); #else return false; #endif } TEST(Threading, PhysicalConcurrency) { auto Num = heavyweight_hardware_concurrency(); // Since Num is unsigned this will also catch us trying to // return -1. ASSERT_LE(Num.compute_thread_count(), hardware_concurrency().compute_thread_count()); } TEST(Threading, NumPhysicalCoresSupported) { if (!isThreadingSupportedArchAndOS()) GTEST_SKIP(); int Num = get_physical_cores(); ASSERT_GT(Num, 0); } TEST(Threading, NumPhysicalCoresUnsupported) { if (isThreadingSupportedArchAndOS()) GTEST_SKIP(); int Num = get_physical_cores(); ASSERT_EQ(Num, -1); } #if LLVM_ENABLE_THREADS class Notification { public: void notify() { { std::lock_guard Lock(M); Notified = true; // Broadcast with the lock held, so it's safe to destroy the Notification // after wait() returns. CV.notify_all(); } } bool wait() { std::unique_lock Lock(M); using steady_clock = std::chrono::steady_clock; auto Deadline = steady_clock::now() + std::chrono::duration_cast( std::chrono::duration(5)); return CV.wait_until(Lock, Deadline, [this] { return Notified; }); } private: bool Notified = false; mutable std::condition_variable CV; mutable std::mutex M; }; TEST(Threading, RunOnThreadSyncAsync) { Notification ThreadStarted, ThreadAdvanced, ThreadFinished; auto ThreadFunc = [&] { ThreadStarted.notify(); ASSERT_TRUE(ThreadAdvanced.wait()); ThreadFinished.notify(); }; llvm::thread Thread(ThreadFunc); Thread.detach(); ASSERT_TRUE(ThreadStarted.wait()); ThreadAdvanced.notify(); ASSERT_TRUE(ThreadFinished.wait()); } TEST(Threading, RunOnThreadSync) { std::atomic_bool Executed(false); llvm::thread Thread( [](void *Arg) { *static_cast(Arg) = true; }, &Executed); Thread.join(); ASSERT_EQ(Executed, true); } #if defined(__APPLE__) TEST(Threading, AppleStackSize) { llvm::thread Thread([] { volatile unsigned char Var[8 * 1024 * 1024 - 10240]; Var[0] = 0xff; ASSERT_EQ(Var[0], 0xff); }); Thread.join(); } #endif #endif } // namespace