/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include namespace folly { namespace detail { namespace proxylockable_detail { template void throwIfAlreadyLocked(Bool&& locked) { if (kIsDebug && locked) { throw std::system_error{ std::make_error_code(std::errc::resource_deadlock_would_occur)}; } } template void throwIfNotLocked(Bool&& locked) { if (kIsDebug && !locked) { throw std::system_error{ std::make_error_code(std::errc::operation_not_permitted)}; } } template void throwIfNoMutex(Bool&& mutex) { if (kIsDebug && !mutex) { throw std::system_error{ std::make_error_code(std::errc::operation_not_permitted)}; } } } // namespace proxylockable_detail template ProxyLockableUniqueLock::~ProxyLockableUniqueLock() { if (owns_lock()) { unlock(); } } template ProxyLockableUniqueLock::ProxyLockableUniqueLock( mutex_type& mutex) noexcept { proxy_.emplace(mutex.lock()); mutex_ = std::addressof(mutex); } template ProxyLockableUniqueLock::ProxyLockableUniqueLock( ProxyLockableUniqueLock&& a) noexcept { *this = std::move(a); } template ProxyLockableUniqueLock& ProxyLockableUniqueLock::operator=( ProxyLockableUniqueLock&& other) noexcept { proxy_ = std::move(other.proxy_); mutex_ = std::exchange(other.mutex_, nullptr); return *this; } template ProxyLockableUniqueLock::ProxyLockableUniqueLock( mutex_type& mutex, std::defer_lock_t) noexcept { mutex_ = std::addressof(mutex); } template ProxyLockableUniqueLock::ProxyLockableUniqueLock( mutex_type& mutex, std::try_to_lock_t) { mutex_ = std::addressof(mutex); if (auto state = mutex.try_lock()) { proxy_.emplace(std::move(state)); } } template template ProxyLockableUniqueLock::ProxyLockableUniqueLock( mutex_type& mutex, const std::chrono::duration& duration) { mutex_ = std::addressof(mutex); if (auto state = mutex.try_lock_for(duration)) { proxy_.emplace(std::move(state)); } } template template ProxyLockableUniqueLock::ProxyLockableUniqueLock( mutex_type& mutex, const std::chrono::time_point& time) { mutex_ = std::addressof(mutex); if (auto state = mutex.try_lock_until(time)) { proxy_.emplace(std::move(state)); } } template void ProxyLockableUniqueLock::lock() { proxylockable_detail::throwIfAlreadyLocked(proxy_); proxylockable_detail::throwIfNoMutex(mutex_); proxy_.emplace(mutex_->lock()); } template void ProxyLockableUniqueLock::unlock() { proxylockable_detail::throwIfNoMutex(mutex_); proxylockable_detail::throwIfNotLocked(proxy_); mutex_->unlock(std::move(*proxy_)); proxy_.reset(); } template bool ProxyLockableUniqueLock::try_lock() { proxylockable_detail::throwIfNoMutex(mutex_); proxylockable_detail::throwIfAlreadyLocked(proxy_); if (auto state = mutex_->try_lock()) { proxy_.emplace(std::move(state)); return true; } return false; } template template bool ProxyLockableUniqueLock::try_lock_for( const std::chrono::duration& duration) { proxylockable_detail::throwIfNoMutex(mutex_); proxylockable_detail::throwIfAlreadyLocked(proxy_); if (auto state = mutex_->try_lock_for(duration)) { proxy_.emplace(std::move(state)); return true; } return false; } template template bool ProxyLockableUniqueLock::try_lock_until( const std::chrono::time_point& time) { proxylockable_detail::throwIfNoMutex(mutex_); proxylockable_detail::throwIfAlreadyLocked(proxy_); if (auto state = mutex_->try_lock_until(time)) { proxy_.emplace(std::move(state)); return true; } return false; } template void ProxyLockableUniqueLock::swap( ProxyLockableUniqueLock& other) noexcept { std::swap(mutex_, other.mutex_); std::swap(proxy_, other.proxy_); } template typename ProxyLockableUniqueLock::mutex_type* ProxyLockableUniqueLock::mutex() const noexcept { return mutex_; } template typename ProxyLockableUniqueLock::proxy_type* ProxyLockableUniqueLock::proxy() const noexcept { return proxy_ ? std::addressof(proxy_.value()) : nullptr; } template bool ProxyLockableUniqueLock::owns_lock() const noexcept { return proxy_.has_value(); } template ProxyLockableUniqueLock::operator bool() const noexcept { return owns_lock(); } template ProxyLockableLockGuard::ProxyLockableLockGuard(mutex_type& mutex) : ProxyLockableUniqueLock{mutex} {} } // namespace detail } // namespace folly