1 //===-- llvm/Support/Threading.h - Control multithreading mode --*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file declares helper functions for running LLVM in a multi-threaded 11 // environment. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_SUPPORT_THREADING_H 16 #define LLVM_SUPPORT_THREADING_H 17 18 #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX 19 #include "llvm/Support/Compiler.h" 20 #include <ciso646> // So we can check the C++ standard lib macros. 21 #include <functional> 22 23 // std::call_once from libc++ is used on all Unix platforms. Other 24 // implementations like libstdc++ are known to have problems on NetBSD, 25 // OpenBSD and PowerPC. 26 #if defined(LLVM_ON_UNIX) && (defined(_LIBCPP_VERSION) || \ 27 !(defined(__NetBSD__) || defined(__OpenBSD__) || defined(__ppc__))) 28 #define LLVM_THREADING_USE_STD_CALL_ONCE 1 29 #else 30 #define LLVM_THREADING_USE_STD_CALL_ONCE 0 31 #endif 32 33 #if LLVM_THREADING_USE_STD_CALL_ONCE 34 #include <mutex> 35 #else 36 #include "llvm/Support/Atomic.h" 37 #endif 38 39 namespace llvm { 40 /// Returns true if LLVM is compiled with support for multi-threading, and 41 /// false otherwise. 42 bool llvm_is_multithreaded(); 43 44 /// llvm_execute_on_thread - Execute the given \p UserFn on a separate 45 /// thread, passing it the provided \p UserData and waits for thread 46 /// completion. 47 /// 48 /// This function does not guarantee that the code will actually be executed 49 /// on a separate thread or honoring the requested stack size, but tries to do 50 /// so where system support is available. 51 /// 52 /// \param UserFn - The callback to execute. 53 /// \param UserData - An argument to pass to the callback function. 54 /// \param RequestedStackSize - If non-zero, a requested size (in bytes) for 55 /// the thread stack. 56 void llvm_execute_on_thread(void (*UserFn)(void*), void *UserData, 57 unsigned RequestedStackSize = 0); 58 59 #if LLVM_THREADING_USE_STD_CALL_ONCE 60 61 typedef std::once_flag once_flag; 62 63 /// This macro is the only way you should define your once flag for LLVM's 64 /// call_once. 65 #define LLVM_DEFINE_ONCE_FLAG(flag) static once_flag flag 66 67 #else 68 69 enum InitStatus { Uninitialized = 0, Wait = 1, Done = 2 }; 70 typedef volatile sys::cas_flag once_flag; 71 72 /// This macro is the only way you should define your once flag for LLVM's 73 /// call_once. 74 #define LLVM_DEFINE_ONCE_FLAG(flag) static once_flag flag = Uninitialized 75 76 #endif 77 78 /// \brief Execute the function specified as a parameter once. 79 /// 80 /// Typical usage: 81 /// \code 82 /// void foo() {...}; 83 /// ... 84 /// LLVM_DEFINE_ONCE_FLAG(flag); 85 /// call_once(flag, foo); 86 /// \endcode 87 /// 88 /// \param flag Flag used for tracking whether or not this has run. 89 /// \param F Function to call once. 90 template <typename Function, typename... Args> call_once(once_flag & flag,Function && F,Args &&...ArgList)91 void call_once(once_flag &flag, Function &&F, Args &&... ArgList) { 92 #if LLVM_THREADING_USE_STD_CALL_ONCE 93 std::call_once(flag, std::forward<Function>(F), 94 std::forward<Args>(ArgList)...); 95 #else 96 // For other platforms we use a generic (if brittle) version based on our 97 // atomics. 98 sys::cas_flag old_val = sys::CompareAndSwap(&flag, Wait, Uninitialized); 99 if (old_val == Uninitialized) { 100 std::forward<Function>(F)(std::forward<Args>(ArgList)...); 101 sys::MemoryFence(); 102 TsanIgnoreWritesBegin(); 103 TsanHappensBefore(&flag); 104 flag = Done; 105 TsanIgnoreWritesEnd(); 106 } else { 107 // Wait until any thread doing the call has finished. 108 sys::cas_flag tmp = flag; 109 sys::MemoryFence(); 110 while (tmp != Done) { 111 tmp = flag; 112 sys::MemoryFence(); 113 } 114 } 115 TsanHappensAfter(&flag); 116 #endif 117 } 118 119 /// Get the amount of currency to use for tasks requiring significant 120 /// memory or other resources. Currently based on physical cores, if 121 /// available for the host system, otherwise falls back to 122 /// thread::hardware_concurrency(). 123 /// Returns 1 when LLVM is configured with LLVM_ENABLE_THREADS=OFF 124 unsigned heavyweight_hardware_concurrency(); 125 } 126 127 #endif 128