diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Support/CrashRecoveryContext.cpp | 5 | ||||
-rw-r--r-- | llvm/lib/Support/Threading.cpp | 51 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/Threading.inc | 63 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/Unix.h | 9 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Process.inc | 7 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Threading.inc | 50 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/WindowsSupport.h | 8 |
7 files changed, 132 insertions, 61 deletions
diff --git a/llvm/lib/Support/CrashRecoveryContext.cpp b/llvm/lib/Support/CrashRecoveryContext.cpp index 9d13fce9cc5..8d8529b474f 100644 --- a/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/llvm/lib/Support/CrashRecoveryContext.cpp @@ -404,7 +404,10 @@ bool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn, unsigned RequestedStackSize) { bool UseBackgroundPriority = hasThreadBackgroundPriority(); RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false }; - llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize); + llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, + RequestedStackSize == 0 + ? llvm::None + : llvm::Optional<unsigned>(RequestedStackSize)); if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl) CRC->setSwitchedThread(); return Info.Result; diff --git a/llvm/lib/Support/Threading.cpp b/llvm/lib/Support/Threading.cpp index e5899a60f4d..48750cef5ec 100644 --- a/llvm/lib/Support/Threading.cpp +++ b/llvm/lib/Support/Threading.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Threading.h" +#include "llvm/ADT/Optional.h" #include "llvm/Config/config.h" #include "llvm/Support/Host.h" @@ -39,8 +40,8 @@ bool llvm::llvm_is_multithreaded() { (!defined(_WIN32) && !defined(HAVE_PTHREAD_H)) // Support for non-Win32, non-pthread implementation. void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData, - unsigned RequestedStackSize) { - (void)RequestedStackSize; + llvm::Optional<unsigned> StackSizeInBytes) { + (void)StackSizeInBytes; Fn(UserData); } @@ -56,6 +57,25 @@ void llvm::set_thread_name(const Twine &Name) {} void llvm::get_thread_name(SmallVectorImpl<char> &Name) { Name.clear(); } +#if LLVM_ENABLE_THREADS == 0 +void llvm::llvm_execute_on_thread_async( + llvm::unique_function<void()> Func, + llvm::Optional<unsigned> StackSizeInBytes) { + (void)Func; + (void)StackSizeInBytes; + report_fatal_error("Spawning a detached thread doesn't make sense with no " + "threading support"); +} +#else +// Support for non-Win32, non-pthread implementation. +void llvm::llvm_execute_on_thread_async( + llvm::unique_function<void()> Func, + llvm::Optional<unsigned> StackSizeInBytes) { + (void)StackSizeInBytes; + std::thread(std::move(Func)).detach(); +} +#endif + #else #include <thread> @@ -84,6 +104,17 @@ unsigned llvm::hardware_concurrency() { return 1; } +namespace { +struct SyncThreadInfo { + void (*UserFn)(void *); + void *UserData; +}; + +using AsyncThreadInfo = llvm::unique_function<void()>; + +enum class JoiningPolicy { Join, Detach }; +} // namespace + // Include the platform-specific parts of this class. #ifdef LLVM_ON_UNIX #include "Unix/Threading.inc" @@ -92,4 +123,20 @@ unsigned llvm::hardware_concurrency() { #include "Windows/Threading.inc" #endif +void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData, + llvm::Optional<unsigned> StackSizeInBytes) { + + SyncThreadInfo Info = {Fn, UserData}; + llvm_execute_on_thread_impl(threadFuncSync, &Info, StackSizeInBytes, + JoiningPolicy::Join); +} + +void llvm::llvm_execute_on_thread_async( + llvm::unique_function<void()> Func, + llvm::Optional<unsigned> StackSizeInBytes) { + llvm_execute_on_thread_impl(&threadFuncAsync, + new AsyncThreadInfo(std::move(Func)), + StackSizeInBytes, JoiningPolicy::Detach); +} + #endif diff --git a/llvm/lib/Support/Unix/Threading.inc b/llvm/lib/Support/Unix/Threading.inc index ed9a9656305..afb887fc109 100644 --- a/llvm/lib/Support/Unix/Threading.inc +++ b/llvm/lib/Support/Unix/Threading.inc @@ -10,6 +10,8 @@ // //===----------------------------------------------------------------------===// +#include "Unix.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" @@ -40,47 +42,56 @@ #include <unistd.h> // For syscall() #endif -namespace { - struct ThreadInfo { - void(*UserFn)(void *); - void *UserData; - }; +static void *threadFuncSync(void *Arg) { + SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg); + TI->UserFn(TI->UserData); + return nullptr; } -static void *ExecuteOnThread_Dispatch(void *Arg) { - ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg); - TI->UserFn(TI->UserData); +static void *threadFuncAsync(void *Arg) { + std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg)); + (*Info)(); return nullptr; } -void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData, - unsigned RequestedStackSize) { - ThreadInfo Info = { Fn, UserData }; - pthread_attr_t Attr; - pthread_t Thread; +static void +llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg, + llvm::Optional<unsigned> StackSizeInBytes, + JoiningPolicy JP) { + int errnum; // Construct the attributes object. - if (::pthread_attr_init(&Attr) != 0) - return; + pthread_attr_t Attr; + if ((errnum = ::pthread_attr_init(&Attr)) != 0) { + ReportErrnumFatal("pthread_attr_init failed", errnum); + } + + auto AttrGuard = llvm::make_scope_exit([&] { + if ((errnum = ::pthread_attr_destroy(&Attr)) != 0) { + ReportErrnumFatal("pthread_attr_destroy failed", errnum); + } + }); // Set the requested stack size, if given. - if (RequestedStackSize != 0) { - if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0) - goto error; + if (StackSizeInBytes) { + if ((errnum = ::pthread_attr_setstacksize(&Attr, *StackSizeInBytes)) != 0) { + ReportErrnumFatal("pthread_attr_setstacksize failed", errnum); + } } // Construct and execute the thread. - if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0) - goto error; - - // Wait for the thread and clean up. - ::pthread_join(Thread, nullptr); + pthread_t Thread; + if ((errnum = ::pthread_create(&Thread, &Attr, ThreadFunc, Arg)) != 0) + ReportErrnumFatal("pthread_create failed", errnum); -error: - ::pthread_attr_destroy(&Attr); + if (JP == JoiningPolicy::Join) { + // Wait for the thread + if ((errnum = ::pthread_join(Thread, nullptr)) != 0) { + ReportErrnumFatal("pthread_join failed", errnum); + } + } } - uint64_t llvm::get_threadid() { #if defined(__APPLE__) // Calling "mach_thread_self()" bumps the reference count on the thread diff --git a/llvm/lib/Support/Unix/Unix.h b/llvm/lib/Support/Unix/Unix.h index 86309b0567f..1fc9a414f74 100644 --- a/llvm/lib/Support/Unix/Unix.h +++ b/llvm/lib/Support/Unix/Unix.h @@ -21,6 +21,7 @@ #include "llvm/Config/config.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/Errno.h" +#include "llvm/Support/ErrorHandling.h" #include <algorithm> #include <assert.h> #include <cerrno> @@ -69,6 +70,14 @@ static inline bool MakeErrMsg( return true; } +// Include StrError(errnum) in a fatal error message. +LLVM_ATTRIBUTE_NORETURN static inline void ReportErrnumFatal(const char *Msg, + int errnum) { + std::string ErrMsg; + MakeErrMsg(&ErrMsg, Msg, errnum); + llvm::report_fatal_error(ErrMsg); +} + namespace llvm { namespace sys { diff --git a/llvm/lib/Support/Windows/Process.inc b/llvm/lib/Support/Windows/Process.inc index 4b91f9f7fc6..3526e3dee6f 100644 --- a/llvm/lib/Support/Windows/Process.inc +++ b/llvm/lib/Support/Windows/Process.inc @@ -439,13 +439,6 @@ const char *Process::ResetColor() { return 0; } -// Include GetLastError() in a fatal error message. -static void ReportLastErrorFatal(const char *Msg) { - std::string ErrMsg; - MakeErrMsg(&ErrMsg, Msg); - report_fatal_error(ErrMsg); -} - unsigned Process::GetRandomNumber() { HCRYPTPROV HCPC; if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, diff --git a/llvm/lib/Support/Windows/Threading.inc b/llvm/lib/Support/Windows/Threading.inc index 96649472cc9..83b47ea1e3d 100644 --- a/llvm/lib/Support/Windows/Threading.inc +++ b/llvm/lib/Support/Windows/Threading.inc @@ -21,36 +21,36 @@ #undef MemoryFence #endif -namespace { - struct ThreadInfo { - void(*func)(void*); - void *param; - }; +static unsigned __stdcall threadFuncSync(void *Arg) { + SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg); + TI->UserFn(TI->UserData); + return 0; } -static unsigned __stdcall ThreadCallback(void *param) { - struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param); - info->func(info->param); - +static unsigned __stdcall threadFuncAsync(void *Arg) { + std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg)); + (*Info)(); return 0; } -void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData, - unsigned RequestedStackSize) { - struct ThreadInfo param = { Fn, UserData }; - - HANDLE hThread = (HANDLE)::_beginthreadex(NULL, - RequestedStackSize, ThreadCallback, - ¶m, 0, NULL); - - if (hThread) { - // We actually don't care whether the wait succeeds or fails, in - // the same way we don't care whether the pthread_join call succeeds - // or fails. There's not much we could do if this were to fail. But - // on success, this call will wait until the thread finishes executing - // before returning. - (void)::WaitForSingleObject(hThread, INFINITE); - ::CloseHandle(hThread); +static void +llvm_execute_on_thread_impl(_beginthreadex_proc_type ThreadFunc, void *Arg, + llvm::Optional<unsigned> StackSizeInBytes, + JoiningPolicy JP) { + HANDLE hThread = (HANDLE)::_beginthreadex( + NULL, StackSizeInBytes.getValueOr(0), ThreadFunc, Arg, 0, NULL); + + if (!hThread) { + ReportLastErrorFatal("_beginthreadex failed"); + } + + if (JP == JoiningPolicy::Join) { + if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) { + ReportLastErrorFatal("WaitForSingleObject failed"); + } + } + if (::CloseHandle(hThread) == FALSE) { + ReportLastErrorFatal("CloseHandle failed"); } } diff --git a/llvm/lib/Support/Windows/WindowsSupport.h b/llvm/lib/Support/Windows/WindowsSupport.h index 2e2e97430b7..bb7e79b8601 100644 --- a/llvm/lib/Support/Windows/WindowsSupport.h +++ b/llvm/lib/Support/Windows/WindowsSupport.h @@ -41,6 +41,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/VersionTuple.h" #include <cassert> #include <string> @@ -66,6 +67,13 @@ llvm::VersionTuple GetWindowsOSVersion(); bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix); +// Include GetLastError() in a fatal error message. +LLVM_ATTRIBUTE_NORETURN inline void ReportLastErrorFatal(const char *Msg) { + std::string ErrMsg; + MakeErrMsg(&ErrMsg, Msg); + llvm::report_fatal_error(ErrMsg); +} + template <typename HandleTraits> class ScopedHandle { typedef typename HandleTraits::handle_type handle_type; |