diff --git a/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp b/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp index 79243f49..8acf9c2f 100644 --- a/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp +++ b/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_filesystem_interface_adapter.hpp @@ -42,9 +42,9 @@ namespace ams::fssrv::impl { private: ams::sf::SharedPointer parent_filesystem; std::unique_ptr base_file; - std::unique_lock open_count_semaphore; + util::unique_lock open_count_semaphore; public: - FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, std::unique_lock &&sema); + FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema); ~FileInterfaceAdapter(); private: void InvalidateCache(); @@ -64,9 +64,9 @@ namespace ams::fssrv::impl { private: ams::sf::SharedPointer parent_filesystem; std::unique_ptr base_dir; - std::unique_lock open_count_semaphore; + util::unique_lock open_count_semaphore; public: - DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, std::unique_lock &&sema); + DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema); ~DirectoryInterfaceAdapter(); public: /* Command API */ @@ -79,7 +79,7 @@ namespace ams::fssrv::impl { NON_COPYABLE(FileSystemInterfaceAdapter); private: std::shared_ptr base_fs; - std::unique_lock mount_count_semaphore; + util::unique_lock mount_count_semaphore; os::ReadWriteLock invalidation_lock; bool open_count_limited; bool deep_retry_enabled = false; diff --git a/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp b/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp index c1a74b42..7f442da3 100644 --- a/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp +++ b/libstratosphere/include/stratosphere/fssrv/interface_adapters/fssrv_storage_interface_adapter.hpp @@ -32,7 +32,7 @@ namespace ams::fssrv::impl { private: /* TODO: Nintendo uses fssystem::AsynchronousAccessStorage here. */ std::shared_ptr base_storage; - std::unique_lock open_count_semaphore; + util::unique_lock open_count_semaphore; os::ReadWriteLock invalidation_lock; /* TODO: DataStorageContext. */ bool deep_retry_enabled = false; diff --git a/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp b/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp index 70800f9f..f465b79d 100644 --- a/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp +++ b/libstratosphere/source/fssrv/fssrv_filesystem_interface_adapter.cpp @@ -19,7 +19,7 @@ namespace ams::fssrv::impl { - FileInterfaceAdapter::FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, std::unique_lock &&sema) + FileInterfaceAdapter::FileInterfaceAdapter(std::unique_ptr &&file, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema) : parent_filesystem(parent, true), base_file(std::move(file)), open_count_semaphore(std::move(sema)) { /* ... */ @@ -89,7 +89,7 @@ namespace ams::fssrv::impl { return ResultSuccess(); } - DirectoryInterfaceAdapter::DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, std::unique_lock &&sema) + DirectoryInterfaceAdapter::DirectoryInterfaceAdapter(std::unique_ptr &&dir, FileSystemInterfaceAdapter *parent, util::unique_lock &&sema) : parent_filesystem(parent, true), base_dir(std::move(dir)), open_count_semaphore(std::move(sema)) { /* ... */ @@ -236,7 +236,7 @@ namespace ams::fssrv::impl { Result FileSystemInterfaceAdapter::OpenFile(ams::sf::Out> out, const fssrv::sf::Path &path, u32 mode) { auto read_lock = this->AcquireCacheInvalidationReadLock(); - std::unique_lock open_count_semaphore; + util::unique_lock open_count_semaphore; if (this->open_count_limited) { /* TODO: This calls into fssrv::FileSystemProxyImpl, which we don't have yet. */ AMS_ABORT_UNLESS(false); @@ -264,7 +264,7 @@ namespace ams::fssrv::impl { Result FileSystemInterfaceAdapter::OpenDirectory(ams::sf::Out> out, const fssrv::sf::Path &path, u32 mode) { auto read_lock = this->AcquireCacheInvalidationReadLock(); - std::unique_lock open_count_semaphore; + util::unique_lock open_count_semaphore; if (this->open_count_limited) { /* TODO: This calls into fssrv::FileSystemProxyImpl, which we don't have yet. */ AMS_ABORT_UNLESS(false); diff --git a/libstratosphere/source/fssystem/fssystem_key_slot_cache.hpp b/libstratosphere/source/fssystem/fssystem_key_slot_cache.hpp index 89cad629..6b4f9234 100644 --- a/libstratosphere/source/fssystem/fssystem_key_slot_cache.hpp +++ b/libstratosphere/source/fssystem/fssystem_key_slot_cache.hpp @@ -22,10 +22,10 @@ namespace ams::fssystem { NON_COPYABLE(KeySlotCacheAccessor); NON_MOVEABLE(KeySlotCacheAccessor); private: - std::unique_lock lk; + util::unique_lock lk; const s32 slot_index; public: - KeySlotCacheAccessor(s32 idx, std::unique_lock &&l) : lk(std::move(l)), slot_index(idx) { /* ... */ } + KeySlotCacheAccessor(s32 idx, util::unique_lock &&l) : lk(std::move(l)), slot_index(idx) { /* ... */ } s32 GetKeySlotIndex() const { return this->slot_index; } }; @@ -79,7 +79,7 @@ namespace ams::fssystem { } Result Find(std::unique_ptr *out, const void *key, size_t key_size, s32 key2) { - std::unique_lock lk(this->mutex); + util::unique_lock lk(this->mutex); KeySlotCacheEntryList *lists[2] = { std::addressof(this->high_priority_mru_list), std::addressof(this->low_priority_mru_list) }; for (auto list : lists) { @@ -100,12 +100,12 @@ namespace ams::fssystem { } void AddEntry(KeySlotCacheEntry *entry) { - std::unique_lock lk(this->mutex); + util::unique_lock lk(this->mutex); this->low_priority_mru_list.push_front(*entry); } private: Result AllocateFromLru(std::unique_ptr *out, KeySlotCacheEntryList &dst_list, const void *key, size_t key_size, s32 key2) { - std::unique_lock lk(this->mutex); + util::unique_lock lk(this->mutex); KeySlotCacheEntryList &src_list = this->low_priority_mru_list.empty() ? this->high_priority_mru_list : this->low_priority_mru_list; AMS_ASSERT(!src_list.empty()); diff --git a/libvapours/include/vapours/util.hpp b/libvapours/include/vapours/util.hpp index 7260a93e..0a7702ed 100644 --- a/libvapours/include/vapours/util.hpp +++ b/libvapours/include/vapours/util.hpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/libvapours/include/vapours/util/util_mutex_utils.hpp b/libvapours/include/vapours/util/util_mutex_utils.hpp new file mode 100644 index 00000000..780c994c --- /dev/null +++ b/libvapours/include/vapours/util/util_mutex_utils.hpp @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +namespace ams::util { + + template + class unique_lock { + NON_COPYABLE(unique_lock); + public: + using mutex_type = _Mutex; + private: + mutex_type *m_mutex; + bool m_owns; + public: + unique_lock() noexcept : m_mutex(nullptr), m_owns(false) { /* ... */ } + + explicit unique_lock(mutex_type &m) noexcept : m_mutex(std::addressof(m)), m_owns(false) { + this->lock(); + m_owns = true; + } + + unique_lock(mutex_type &m, std::defer_lock_t) noexcept : m_mutex(std::addressof(m)), m_owns(false) { /* ... */ } + unique_lock(mutex_type &m, std::try_to_lock_t) noexcept : m_mutex(std::addressof(m)), m_owns(m_mutex->try_lock()) { /* ... */ } + unique_lock(mutex_type &m, std::adopt_lock_t) noexcept : m_mutex(std::addressof(m)), m_owns(true) { /* ... */ } + + template + unique_lock(mutex_type &m, const std::chrono::time_point<_Clock, _Duration> &time) noexcept : m_mutex(std::addressof(m)), m_owns(m_mutex->try_lock_until(time)) { /* ... */ } + + template + unique_lock(mutex_type &m, const std::chrono::duration<_Rep, _Period> &time) noexcept : m_mutex(std::addressof(m)), m_owns(m_mutex->try_lock_for(time)) { /* ... */ } + + ~unique_lock() noexcept { + if (m_owns) { + this->unlock(); + } + } + + unique_lock(unique_lock &&rhs) noexcept : m_mutex(rhs.m_mutex), m_owns(rhs.m_owns) { + rhs.m_mutex = nullptr; + rhs.m_owns = false; + } + + unique_lock &operator=(unique_lock &&rhs) noexcept { + if (m_owns) { + this->unlock(); + } + + unique_lock(std::move(rhs)).swap(*this); + + rhs.m_mutex = nullptr; + rhs.m_owns = false; + + return *this; + } + + void lock() noexcept { + AMS_ABORT_UNLESS(m_mutex); + AMS_ABORT_UNLESS(!m_owns); + + m_mutex->lock(); + m_owns = true; + } + + bool try_lock() noexcept { + AMS_ABORT_UNLESS(m_mutex); + AMS_ABORT_UNLESS(!m_owns); + + m_owns = m_mutex->try_lock(); + return m_owns; + } + + template + bool try_lock_until(const std::chrono::time_point<_Clock, _Duration> &time) noexcept { + AMS_ABORT_UNLESS(m_mutex); + AMS_ABORT_UNLESS(!m_owns); + m_owns = m_mutex->try_lock_until(time); + return m_owns; + } + + template + bool try_lock_for(const std::chrono::duration<_Rep, _Period> &time) noexcept { + AMS_ABORT_UNLESS(m_mutex); + AMS_ABORT_UNLESS(!m_owns); + m_owns = m_mutex->try_lock_for(time); + return m_owns; + } + + + void unlock() noexcept { + AMS_ABORT_UNLESS(m_owns); + if (m_mutex) { + m_mutex->unlock(); + m_owns = false; + } + } + + void swap(unique_lock &rhs) noexcept { + std::swap(m_mutex, rhs.m_mutex); + std::swap(m_owns, rhs.m_owns); + } + + mutex_type *release() noexcept { + mutex_type *ret = m_mutex; + m_mutex = nullptr; + m_owns = false; + return ret; + } + + bool owns_lock() const noexcept { + return m_owns; + } + + explicit operator bool() const noexcept { + return this->owns_lock(); + } + + mutex_type *mutex() const noexcept { + return m_mutex; + } + }; + + template + inline void swap(unique_lock<_Mutex> &lhs, unique_lock<_Mutex> &rhs) noexcept { return lhs.swap(rhs); } + +}