diff options
author | kleines Filmröllchen <malu.bertsch@gmail.com> | 2022-01-02 14:49:53 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-01-23 15:21:10 +0100 |
commit | 3d6e08156d9ceff0f76d878f0f900a78c36685b6 (patch) | |
tree | ff6df52b4a223410974f8f80dce33ccd5c1aea2f /Userland | |
parent | a7ce0c2297e316963100babeb462bcc41c550de9 (diff) | |
download | serenity-3d6e08156d9ceff0f76d878f0f900a78c36685b6.zip |
LibThreading: Introduce MutexProtected generic synchronization primitive
MutexProtected mirrors the identically-named Kernel primitive and can be
used to synchronize access to any object that might not be thread safe
on its own. Synchronization is done with a simple mutex, so access to a
MutexProtected object is potentially blocking.
Mutex now has an internal nesting variable which is there to harden it
against lock-unlock ordering issues (e.g. double unlocking).
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibThreading/Mutex.h | 21 | ||||
-rw-r--r-- | Userland/Libraries/LibThreading/MutexProtected.h | 56 |
2 files changed, 75 insertions, 2 deletions
diff --git a/Userland/Libraries/LibThreading/Mutex.h b/Userland/Libraries/LibThreading/Mutex.h index 44921eab61..9ffb061306 100644 --- a/Userland/Libraries/LibThreading/Mutex.h +++ b/Userland/Libraries/LibThreading/Mutex.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2021, kleines Filmröllchen <malu.bertsch@gmail.com> * * SPDX-License-Identifier: BSD-2-Clause */ @@ -7,6 +8,7 @@ #pragma once #include <AK/Assertions.h> +#include <AK/Format.h> #include <AK/Noncopyable.h> #include <AK/Types.h> #include <pthread.h> @@ -20,6 +22,7 @@ class Mutex { public: Mutex() + : m_lock_count(0) { #ifndef __serenity__ pthread_mutexattr_t attr; @@ -28,7 +31,11 @@ public: pthread_mutex_init(&m_mutex, &attr); #endif } - ~Mutex() = default; + ~Mutex() + { + VERIFY(m_lock_count == 0); + // FIXME: pthread_mutex_destroy() is not implemented. + } void lock(); void unlock(); @@ -39,6 +46,7 @@ private: #else pthread_mutex_t m_mutex; #endif + unsigned m_lock_count { 0 }; }; class MutexLocker { @@ -51,7 +59,10 @@ public: { lock(); } - ALWAYS_INLINE ~MutexLocker() { unlock(); } + ALWAYS_INLINE ~MutexLocker() + { + unlock(); + } ALWAYS_INLINE void unlock() { m_mutex.unlock(); } ALWAYS_INLINE void lock() { m_mutex.lock(); } @@ -62,10 +73,16 @@ private: ALWAYS_INLINE void Mutex::lock() { pthread_mutex_lock(&m_mutex); + m_lock_count++; } ALWAYS_INLINE void Mutex::unlock() { + VERIFY(m_lock_count > 0); + // FIXME: We need to protect the lock count with the mutex itself. + // This may be bad because we're not *technically* unlocked yet, + // but we're not handling any errors from pthread_mutex_unlock anyways. + m_lock_count--; pthread_mutex_unlock(&m_mutex); } diff --git a/Userland/Libraries/LibThreading/MutexProtected.h b/Userland/Libraries/LibThreading/MutexProtected.h new file mode 100644 index 0000000000..f12d2fea41 --- /dev/null +++ b/Userland/Libraries/LibThreading/MutexProtected.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022, kleines Filmröllchen <malu.bertsch@gmail.com>. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Concepts.h> +#include <AK/Noncopyable.h> +#include <LibThreading/Mutex.h> + +namespace Threading { + +template<typename T> +class MutexProtected { + AK_MAKE_NONCOPYABLE(MutexProtected); + AK_MAKE_NONMOVABLE(MutexProtected); + using ProtectedType = T; + +public: + ALWAYS_INLINE MutexProtected() = default; + ALWAYS_INLINE MutexProtected(T&& value) + : m_value(move(value)) + { + } + ALWAYS_INLINE explicit MutexProtected(T& value) + : m_value(value) + { + } + + template<typename Callback> + decltype(auto) with_locked(Callback callback) + { + auto lock = this->lock(); + // This allows users to get a copy, but if we don't allow references through &m_value, it's even more complex. + return callback(m_value); + } + + template<VoidFunction<T> Callback> + void for_each_locked(Callback callback) + { + with_locked([&](auto& value) { + for (auto& item : value) + callback(item); + }); + } + +private: + [[nodiscard]] ALWAYS_INLINE MutexLocker lock() { return MutexLocker(m_lock); } + + T m_value; + Mutex m_lock {}; +}; + +} |