1 //===- unittests/Threading.cpp - Thread tests -----------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Support/Threading.h" 10 #include "llvm/ADT/Triple.h" 11 #include "llvm/Support/Host.h" 12 #include "llvm/Support/thread.h" 13 #include "gtest/gtest.h" 14 15 #include <atomic> 16 #include <condition_variable> 17 18 using namespace llvm; 19 20 namespace { 21 22 static bool isThreadingSupportedArchAndOS() { 23 Triple Host(Triple::normalize(sys::getProcessTriple())); 24 25 // Initially this is only testing detection of the number of 26 // physical cores, which is currently only supported/tested on 27 // some systems. 28 return (Host.isOSWindows() && llvm_is_multithreaded()) || Host.isOSDarwin() || 29 (Host.isX86() && Host.isOSLinux()) || 30 (Host.isOSLinux() && !Host.isAndroid()) || 31 (Host.isSystemZ() && Host.isOSzOS()); 32 } 33 34 TEST(Threading, PhysicalConcurrency) { 35 auto Num = heavyweight_hardware_concurrency(); 36 // Since Num is unsigned this will also catch us trying to 37 // return -1. 38 ASSERT_LE(Num.compute_thread_count(), 39 hardware_concurrency().compute_thread_count()); 40 } 41 42 TEST(Threading, NumPhysicalCoresSupported) { 43 if (!isThreadingSupportedArchAndOS()) 44 GTEST_SKIP(); 45 int Num = get_physical_cores(); 46 ASSERT_GT(Num, 0); 47 } 48 49 TEST(Threading, NumPhysicalCoresUnsupported) { 50 if (isThreadingSupportedArchAndOS()) 51 GTEST_SKIP(); 52 int Num = get_physical_cores(); 53 ASSERT_EQ(Num, -1); 54 } 55 56 #if LLVM_ENABLE_THREADS 57 58 class Notification { 59 public: 60 void notify() { 61 { 62 std::lock_guard<std::mutex> Lock(M); 63 Notified = true; 64 // Broadcast with the lock held, so it's safe to destroy the Notification 65 // after wait() returns. 66 CV.notify_all(); 67 } 68 } 69 70 bool wait() { 71 std::unique_lock<std::mutex> Lock(M); 72 using steady_clock = std::chrono::steady_clock; 73 auto Deadline = steady_clock::now() + 74 std::chrono::duration_cast<steady_clock::duration>( 75 std::chrono::duration<double>(5)); 76 return CV.wait_until(Lock, Deadline, [this] { return Notified; }); 77 } 78 79 private: 80 bool Notified = false; 81 mutable std::condition_variable CV; 82 mutable std::mutex M; 83 }; 84 85 TEST(Threading, RunOnThreadSyncAsync) { 86 Notification ThreadStarted, ThreadAdvanced, ThreadFinished; 87 88 auto ThreadFunc = [&] { 89 ThreadStarted.notify(); 90 ASSERT_TRUE(ThreadAdvanced.wait()); 91 ThreadFinished.notify(); 92 }; 93 94 llvm::thread Thread(ThreadFunc); 95 Thread.detach(); 96 ASSERT_TRUE(ThreadStarted.wait()); 97 ThreadAdvanced.notify(); 98 ASSERT_TRUE(ThreadFinished.wait()); 99 } 100 101 TEST(Threading, RunOnThreadSync) { 102 std::atomic_bool Executed(false); 103 llvm::thread Thread( 104 [](void *Arg) { *static_cast<std::atomic_bool *>(Arg) = true; }, 105 &Executed); 106 Thread.join(); 107 ASSERT_EQ(Executed, true); 108 } 109 110 #if defined(__APPLE__) 111 TEST(Threading, AppleStackSize) { 112 llvm::thread Thread([] { 113 volatile unsigned char Var[8 * 1024 * 1024 - 10240]; 114 Var[0] = 0xff; 115 ASSERT_EQ(Var[0], 0xff); 116 }); 117 Thread.join(); 118 } 119 #endif 120 #endif 121 122 } // namespace 123