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// We use std::call_once on all Unix platforms except for NetBSD with 24// libstdc++. That platform has a bug they are working to fix, and they'll 25// remove the NetBSD checks once fixed. 26#if defined(LLVM_ON_UNIX) && \ 27 !(defined(__NetBSD__) && !defined(_LIBCPP_VERSION)) && !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 39namespace 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> 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 120#endif 121