From b8ce57c5a8c56c7d0bba4192920d99fad5a07686 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Thu, 15 Aug 2019 16:55:23 +0000 Subject: [PATCH] [Support] Base RWMutex on std::shared_timed_mutex (C++14) This should have the same semantics. We use std::shared_mutex instead on MSVC and C++17, std::shared_timed_mutex is less efficient than our custom implementation on Windows, std::shared_mutex should be faster. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@369018 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Support/RWMutex.h | 122 +++++++----------------------- lib/Support/CMakeLists.txt | 1 - lib/Support/RWMutex.cpp | 124 ------------------------------- lib/Support/Unix/RWMutex.inc | 50 ------------- lib/Support/Windows/RWMutex.inc | 128 -------------------------------- 5 files changed, 27 insertions(+), 398 deletions(-) delete mode 100644 lib/Support/RWMutex.cpp delete mode 100644 lib/Support/Unix/RWMutex.inc delete mode 100644 lib/Support/Windows/RWMutex.inc diff --git a/include/llvm/Support/RWMutex.h b/include/llvm/Support/RWMutex.h index 9cd57cbd65a..d4587772ac6 100644 --- a/include/llvm/Support/RWMutex.h +++ b/include/llvm/Support/RWMutex.h @@ -16,87 +16,33 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Support/Threading.h" #include +#include +#include namespace llvm { namespace sys { - /// Platform agnostic RWMutex class. - class RWMutexImpl - { - /// @name Constructors - /// @{ - public: - - /// Initializes the lock but doesn't acquire it. - /// Default Constructor. - explicit RWMutexImpl(); - - /// @} - /// @name Do Not Implement - /// @{ - RWMutexImpl(const RWMutexImpl & original) = delete; - RWMutexImpl &operator=(const RWMutexImpl &) = delete; - /// @} - - /// Releases and removes the lock - /// Destructor - ~RWMutexImpl(); - - /// @} - /// @name Methods - /// @{ - public: - - /// Attempts to unconditionally acquire the lock in reader mode. If the - /// lock is held by a writer, this method will wait until it can acquire - /// the lock. - /// @returns false if any kind of error occurs, true otherwise. - /// Unconditionally acquire the lock in reader mode. - bool reader_acquire(); - - /// Attempts to release the lock in reader mode. - /// @returns false if any kind of error occurs, true otherwise. - /// Unconditionally release the lock in reader mode. - bool reader_release(); - - /// Attempts to unconditionally acquire the lock in reader mode. If the - /// lock is held by any readers, this method will wait until it can - /// acquire the lock. - /// @returns false if any kind of error occurs, true otherwise. - /// Unconditionally acquire the lock in writer mode. - bool writer_acquire(); - - /// Attempts to release the lock in writer mode. - /// @returns false if any kind of error occurs, true otherwise. - /// Unconditionally release the lock in write mode. - bool writer_release(); - - //@} - /// @name Platform Dependent Data - /// @{ - private: -#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0 - void* data_ = nullptr; ///< We don't know what the data will be -#endif - }; - /// SmartMutex - An R/W mutex with a compile time constant parameter that /// indicates whether this mutex should become a no-op when we're not /// running in multithreaded mode. template class SmartRWMutex { - RWMutexImpl impl; + // shared_mutex (C++17) is more efficient than shared_timed_mutex (C++14) + // on Windows and always available on MSVC. +#if defined(_MSC_VER) || __cplusplus > 201402L + std::shared_mutex impl; +#else + std::shared_timed_mutex impl; +#endif unsigned readers = 0; unsigned writers = 0; public: - explicit SmartRWMutex() = default; - SmartRWMutex(const SmartRWMutex & original) = delete; - SmartRWMutex &operator=(const SmartRWMutex &) = delete; - bool lock_shared() { - if (!mt_only || llvm_is_multithreaded()) - return impl.reader_acquire(); + if (!mt_only || llvm_is_multithreaded()) { + impl.lock_shared(); + return true; + } // Single-threaded debugging code. This would be racy in multithreaded // mode, but provides not sanity checks in single threaded mode. @@ -105,8 +51,10 @@ namespace sys { } bool unlock_shared() { - if (!mt_only || llvm_is_multithreaded()) - return impl.reader_release(); + if (!mt_only || llvm_is_multithreaded()) { + impl.unlock_shared(); + return true; + } // Single-threaded debugging code. This would be racy in multithreaded // mode, but provides not sanity checks in single threaded mode. @@ -116,8 +64,10 @@ namespace sys { } bool lock() { - if (!mt_only || llvm_is_multithreaded()) - return impl.writer_acquire(); + if (!mt_only || llvm_is_multithreaded()) { + impl.lock(); + return true; + } // Single-threaded debugging code. This would be racy in multithreaded // mode, but provides not sanity checks in single threaded mode. @@ -127,8 +77,10 @@ namespace sys { } bool unlock() { - if (!mt_only || llvm_is_multithreaded()) - return impl.writer_release(); + if (!mt_only || llvm_is_multithreaded()) { + impl.unlock(); + return true; + } // Single-threaded debugging code. This would be racy in multithreaded // mode, but provides not sanity checks in single threaded mode. @@ -142,33 +94,13 @@ namespace sys { /// ScopedReader - RAII acquisition of a reader lock template - struct SmartScopedReader { - SmartRWMutex& mutex; - - explicit SmartScopedReader(SmartRWMutex& m) : mutex(m) { - mutex.lock_shared(); - } - - ~SmartScopedReader() { - mutex.unlock_shared(); - } - }; + using SmartScopedReader = const std::shared_lock>; typedef SmartScopedReader ScopedReader; /// ScopedWriter - RAII acquisition of a writer lock template - struct SmartScopedWriter { - SmartRWMutex& mutex; - - explicit SmartScopedWriter(SmartRWMutex& m) : mutex(m) { - mutex.lock(); - } - - ~SmartScopedWriter() { - mutex.unlock(); - } - }; + using SmartScopedWriter = std::lock_guard>; typedef SmartScopedWriter ScopedWriter; diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index 013e6e6359f..f75cb902815 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -173,7 +173,6 @@ add_llvm_library(LLVMSupport Path.cpp Process.cpp Program.cpp - RWMutex.cpp Signals.cpp TargetRegistry.cpp ThreadLocal.cpp diff --git a/lib/Support/RWMutex.cpp b/lib/Support/RWMutex.cpp deleted file mode 100644 index 7ce856b716c..00000000000 --- a/lib/Support/RWMutex.cpp +++ /dev/null @@ -1,124 +0,0 @@ -//===- RWMutex.cpp - Reader/Writer Mutual Exclusion Lock --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the llvm::sys::RWMutex class. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Allocator.h" -#include "llvm/Support/RWMutex.h" -#include "llvm/Config/config.h" - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// - -#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0 -// Define all methods as no-ops if threading is explicitly disabled - -using namespace llvm; -using namespace sys; - -RWMutexImpl::RWMutexImpl() = default; -RWMutexImpl::~RWMutexImpl() = default; - -bool RWMutexImpl::reader_acquire() { return true; } -bool RWMutexImpl::reader_release() { return true; } -bool RWMutexImpl::writer_acquire() { return true; } -bool RWMutexImpl::writer_release() { return true; } - -#else - -#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_RWLOCK_INIT) - -#include -#include -#include - -using namespace llvm; -using namespace sys; - -// Construct a RWMutex using pthread calls -RWMutexImpl::RWMutexImpl() -{ - // Declare the pthread_rwlock data structures - pthread_rwlock_t* rwlock = - static_cast(safe_malloc(sizeof(pthread_rwlock_t))); - -#ifdef __APPLE__ - // Workaround a bug/mis-feature in Darwin's pthread_rwlock_init. - bzero(rwlock, sizeof(pthread_rwlock_t)); -#endif - - // Initialize the rwlock - int errorcode = pthread_rwlock_init(rwlock, nullptr); - (void)errorcode; - assert(errorcode == 0); - - // Assign the data member - data_ = rwlock; -} - -// Destruct a RWMutex -RWMutexImpl::~RWMutexImpl() -{ - pthread_rwlock_t* rwlock = static_cast(data_); - assert(rwlock != nullptr); - pthread_rwlock_destroy(rwlock); - free(rwlock); -} - -bool -RWMutexImpl::reader_acquire() -{ - pthread_rwlock_t* rwlock = static_cast(data_); - assert(rwlock != nullptr); - - int errorcode = pthread_rwlock_rdlock(rwlock); - return errorcode == 0; -} - -bool -RWMutexImpl::reader_release() -{ - pthread_rwlock_t* rwlock = static_cast(data_); - assert(rwlock != nullptr); - - int errorcode = pthread_rwlock_unlock(rwlock); - return errorcode == 0; -} - -bool -RWMutexImpl::writer_acquire() -{ - pthread_rwlock_t* rwlock = static_cast(data_); - assert(rwlock != nullptr); - - int errorcode = pthread_rwlock_wrlock(rwlock); - return errorcode == 0; -} - -bool -RWMutexImpl::writer_release() -{ - pthread_rwlock_t* rwlock = static_cast(data_); - assert(rwlock != nullptr); - - int errorcode = pthread_rwlock_unlock(rwlock); - return errorcode == 0; -} - -#elif defined(LLVM_ON_UNIX) -#include "Unix/RWMutex.inc" -#elif defined( _WIN32) -#include "Windows/RWMutex.inc" -#else -#warning Neither LLVM_ON_UNIX nor _WIN32 was set in Support/Mutex.cpp -#endif -#endif diff --git a/lib/Support/Unix/RWMutex.inc b/lib/Support/Unix/RWMutex.inc deleted file mode 100644 index 8b47dfa0f85..00000000000 --- a/lib/Support/Unix/RWMutex.inc +++ /dev/null @@ -1,50 +0,0 @@ -//= llvm/Support/Unix/RWMutex.inc - Unix Reader/Writer Mutual Exclusion Lock =// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the Unix specific (non-pthread) RWMutex class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Mutex.h" - -namespace llvm { - -using namespace sys; - -// This naive implementation treats readers the same as writers. This -// will therefore deadlock if a thread tries to acquire a read lock -// multiple times. - -RWMutexImpl::RWMutexImpl() : data_(new MutexImpl(false)) { } - -RWMutexImpl::~RWMutexImpl() { - delete static_cast(data_); -} - -bool RWMutexImpl::reader_acquire() { - return static_cast(data_)->acquire(); -} - -bool RWMutexImpl::reader_release() { - return static_cast(data_)->release(); -} - -bool RWMutexImpl::writer_acquire() { - return static_cast(data_)->acquire(); -} - -bool RWMutexImpl::writer_release() { - return static_cast(data_)->release(); -} - -} diff --git a/lib/Support/Windows/RWMutex.inc b/lib/Support/Windows/RWMutex.inc deleted file mode 100644 index 8df9bc39416..00000000000 --- a/lib/Support/Windows/RWMutex.inc +++ /dev/null @@ -1,128 +0,0 @@ -//= llvm/Support/Win32/Mutex.inc - Win32 Reader/Writer Mutual Exclusion Lock =// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the Win32 specific (non-pthread) RWMutex class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -#include "WindowsSupport.h" - -namespace llvm { - -// Windows has slim read-writer lock support on Vista and higher, so we -// will attempt to load the APIs. If they exist, we will use them, and -// if not, we will fall back on critical sections. When we drop support -// for XP, we can stop lazy-loading these APIs and just use them directly. -#if defined(__MINGW32__) - // Taken from WinNT.h - typedef struct _RTL_SRWLOCK { - PVOID Ptr; - } RTL_SRWLOCK, *PRTL_SRWLOCK; - - // Taken from WinBase.h - typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; -#endif - -static VOID (WINAPI *fpInitializeSRWLock)(PSRWLOCK lock) = NULL; -static VOID (WINAPI *fpAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL; -static VOID (WINAPI *fpAcquireSRWLockShared)(PSRWLOCK lock) = NULL; -static VOID (WINAPI *fpReleaseSRWLockExclusive)(PSRWLOCK lock) = NULL; -static VOID (WINAPI *fpReleaseSRWLockShared)(PSRWLOCK lock) = NULL; - -static bool sHasSRW = false; - -static bool loadSRW() { - static bool sChecked = false; - if (!sChecked) { - sChecked = true; - - if (HMODULE hLib = ::GetModuleHandleW(L"Kernel32.dll")) { - fpInitializeSRWLock = - (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, - "InitializeSRWLock"); - fpAcquireSRWLockExclusive = - (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, - "AcquireSRWLockExclusive"); - fpAcquireSRWLockShared = - (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, - "AcquireSRWLockShared"); - fpReleaseSRWLockExclusive = - (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, - "ReleaseSRWLockExclusive"); - fpReleaseSRWLockShared = - (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, - "ReleaseSRWLockShared"); - - if (fpInitializeSRWLock != NULL) { - sHasSRW = true; - } - } - } - return sHasSRW; -} - -sys::RWMutexImpl::RWMutexImpl() { - if (loadSRW()) { - data_ = safe_calloc(1, sizeof(SRWLOCK)); - fpInitializeSRWLock(static_cast(data_)); - } else { - data_ = safe_calloc(1, sizeof(CRITICAL_SECTION)); - InitializeCriticalSection(static_cast(data_)); - } -} - -sys::RWMutexImpl::~RWMutexImpl() { - if (!sHasSRW) - DeleteCriticalSection(static_cast(data_)); - // Nothing to do in the case of slim reader/writers except free the memory. - free(data_); -} - -bool sys::RWMutexImpl::reader_acquire() { - if (sHasSRW) { - fpAcquireSRWLockShared(static_cast(data_)); - } else { - EnterCriticalSection(static_cast(data_)); - } - return true; -} - -bool sys::RWMutexImpl::reader_release() { - if (sHasSRW) { - fpReleaseSRWLockShared(static_cast(data_)); - } else { - LeaveCriticalSection(static_cast(data_)); - } - return true; -} - -bool sys::RWMutexImpl::writer_acquire() { - if (sHasSRW) { - fpAcquireSRWLockExclusive(static_cast(data_)); - } else { - EnterCriticalSection(static_cast(data_)); - } - return true; -} - -bool sys::RWMutexImpl::writer_release() { - if (sHasSRW) { - fpReleaseSRWLockExclusive(static_cast(data_)); - } else { - LeaveCriticalSection(static_cast(data_)); - } - return true; -} - - -} -- 2.40.0