// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #pragma once #include "td/utils/port/config.h" #include "td/utils/common.h" #include "td/utils/Status.h" #if TD_PORT_POSIX #include #endif #include namespace td { class RwMutex { public: RwMutex() { init(); } RwMutex(const RwMutex &) = delete; RwMutex &operator=(const RwMutex &) = delete; RwMutex(RwMutex &&other) { init(); other.clear(); } RwMutex &operator=(RwMutex &&other) { other.clear(); return *this; } ~RwMutex() { clear(); } bool empty() const { return !is_valid_; } void init(); void clear(); struct ReadUnlock { void operator()(RwMutex *ptr) { ptr->unlock_read_unsafe(); } }; struct WriteUnlock { void operator()(RwMutex *ptr) { ptr->unlock_write_unsafe(); } }; using ReadLock = std::unique_ptr; using WriteLock = std::unique_ptr; Result lock_read() TD_WARN_UNUSED_RESULT { lock_read_unsafe(); return ReadLock(this); } Result lock_write() TD_WARN_UNUSED_RESULT { lock_write_unsafe(); return WriteLock(this); } void lock_read_unsafe(); void lock_write_unsafe(); void unlock_read_unsafe(); void unlock_write_unsafe(); private: bool is_valid_ = false; #if TD_PORT_POSIX pthread_rwlock_t mutex_; #elif TD_PORT_WINDOWS unique_ptr mutex_; #endif }; inline void RwMutex::init() { CHECK(empty()); is_valid_ = true; #if TD_PORT_POSIX pthread_rwlock_init(&mutex_, nullptr); #elif TD_PORT_WINDOWS mutex_ = make_unique(); InitializeSRWLock(mutex_.get()); #endif } inline void RwMutex::clear() { if (is_valid_) { #if TD_PORT_POSIX pthread_rwlock_destroy(&mutex_); #elif TD_PORT_WINDOWS mutex_.release(); #endif is_valid_ = false; } } inline void RwMutex::lock_read_unsafe() { CHECK(!empty()); // TODO error handling #if TD_PORT_POSIX pthread_rwlock_rdlock(&mutex_); #elif TD_PORT_WINDOWS AcquireSRWLockShared(mutex_.get()); #endif } inline void RwMutex::lock_write_unsafe() { CHECK(!empty()); #if TD_PORT_POSIX pthread_rwlock_wrlock(&mutex_); #elif TD_PORT_WINDOWS AcquireSRWLockExclusive(mutex_.get()); #endif } inline void RwMutex::unlock_read_unsafe() { CHECK(!empty()); #if TD_PORT_POSIX pthread_rwlock_unlock(&mutex_); #elif TD_PORT_WINDOWS ReleaseSRWLockShared(mutex_.get()); #endif } inline void RwMutex::unlock_write_unsafe() { CHECK(!empty()); #if TD_PORT_POSIX pthread_rwlock_unlock(&mutex_); #elif TD_PORT_WINDOWS ReleaseSRWLockExclusive(mutex_.get()); #endif } } // namespace td