1 //===-- llvm/Support/Threading.cpp- Control multithreading mode --*- C++ -*-==// 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 // This file defines helper functions for running LLVM in a multi-threaded 10 // environment. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Support/Threading.h" 15 #include "llvm/ADT/Optional.h" 16 #include "llvm/Config/config.h" 17 #include "llvm/Support/Host.h" 18 19 #include <cassert> 20 #include <errno.h> 21 #include <stdlib.h> 22 #include <string.h> 23 24 using namespace llvm; 25 26 //===----------------------------------------------------------------------===// 27 //=== WARNING: Implementation here must contain only TRULY operating system 28 //=== independent code. 29 //===----------------------------------------------------------------------===// 30 31 bool llvm::llvm_is_multithreaded() { 32 #if LLVM_ENABLE_THREADS != 0 33 return true; 34 #else 35 return false; 36 #endif 37 } 38 39 #if LLVM_ENABLE_THREADS == 0 || \ 40 (!defined(_WIN32) && !defined(HAVE_PTHREAD_H)) 41 // Support for non-Win32, non-pthread implementation. 42 void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData, 43 llvm::Optional<unsigned> StackSizeInBytes) { 44 (void)StackSizeInBytes; 45 Fn(UserData); 46 } 47 48 unsigned llvm::heavyweight_hardware_concurrency() { return 1; } 49 50 unsigned llvm::hardware_concurrency() { return 1; } 51 52 uint64_t llvm::get_threadid() { return 0; } 53 54 uint32_t llvm::get_max_thread_name_length() { return 0; } 55 56 void llvm::set_thread_name(const Twine &Name) {} 57 58 void llvm::get_thread_name(SmallVectorImpl<char> &Name) { Name.clear(); } 59 60 #if LLVM_ENABLE_THREADS == 0 61 void llvm::llvm_execute_on_thread_async( 62 llvm::unique_function<void()> Func, 63 llvm::Optional<unsigned> StackSizeInBytes) { 64 (void)Func; 65 (void)StackSizeInBytes; 66 report_fatal_error("Spawning a detached thread doesn't make sense with no " 67 "threading support"); 68 } 69 #else 70 // Support for non-Win32, non-pthread implementation. 71 void llvm::llvm_execute_on_thread_async( 72 llvm::unique_function<void()> Func, 73 llvm::Optional<unsigned> StackSizeInBytes) { 74 (void)StackSizeInBytes; 75 std::thread(std::move(Func)).detach(); 76 } 77 #endif 78 79 #else 80 81 #include <thread> 82 unsigned llvm::heavyweight_hardware_concurrency() { 83 // Since we can't get here unless LLVM_ENABLE_THREADS == 1, it is safe to use 84 // `std::thread` directly instead of `llvm::thread` (and indeed, doing so 85 // allows us to not define `thread` in the llvm namespace, which conflicts 86 // with some platforms such as FreeBSD whose headers also define a struct 87 // called `thread` in the global namespace which can cause ambiguity due to 88 // ADL. 89 int NumPhysical = sys::getHostNumPhysicalCores(); 90 if (NumPhysical == -1) 91 return std::thread::hardware_concurrency(); 92 return NumPhysical; 93 } 94 95 unsigned llvm::hardware_concurrency() { 96 #if defined(HAVE_SCHED_GETAFFINITY) && defined(HAVE_CPU_COUNT) 97 cpu_set_t Set; 98 if (sched_getaffinity(0, sizeof(Set), &Set)) 99 return CPU_COUNT(&Set); 100 #endif 101 // Guard against std::thread::hardware_concurrency() returning 0. 102 if (unsigned Val = std::thread::hardware_concurrency()) 103 return Val; 104 return 1; 105 } 106 107 namespace { 108 struct SyncThreadInfo { 109 void (*UserFn)(void *); 110 void *UserData; 111 }; 112 113 using AsyncThreadInfo = llvm::unique_function<void()>; 114 115 enum class JoiningPolicy { Join, Detach }; 116 } // namespace 117 118 // Include the platform-specific parts of this class. 119 #ifdef LLVM_ON_UNIX 120 #include "Unix/Threading.inc" 121 #endif 122 #ifdef _WIN32 123 #include "Windows/Threading.inc" 124 #endif 125 126 void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData, 127 llvm::Optional<unsigned> StackSizeInBytes) { 128 129 SyncThreadInfo Info = {Fn, UserData}; 130 llvm_execute_on_thread_impl(threadFuncSync, &Info, StackSizeInBytes, 131 JoiningPolicy::Join); 132 } 133 134 void llvm::llvm_execute_on_thread_async( 135 llvm::unique_function<void()> Func, 136 llvm::Optional<unsigned> StackSizeInBytes) { 137 llvm_execute_on_thread_impl(&threadFuncAsync, 138 new AsyncThreadInfo(std::move(Func)), 139 StackSizeInBytes, JoiningPolicy::Detach); 140 } 141 142 #endif 143