summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
authorMark Rowe <mark@vector35.com>2026-02-27 15:29:11 -0800
committerMark Rowe <mark@vector35.com>2026-03-05 11:20:11 -0500
commit6f4404c36f765714b7474774cc81dc4bf329ee4f (patch)
tree0789af65a495f1786a88e1c06cac4e4cbc2088fe /base
parent82b1b5cb1d0081044800da11bf31d805b50fd80f (diff)
Add mutex and recursive_mutex to bn::base
On Apple platforms these wrap `os_unfair_lock`. On other platforms they're aliases for the std equivalents.
Diffstat (limited to 'base')
-rw-r--r--base/mutex.h134
1 files changed, 134 insertions, 0 deletions
diff --git a/base/mutex.h b/base/mutex.h
new file mode 100644
index 00000000..dea34d4c
--- /dev/null
+++ b/base/mutex.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2026 Vector 35 Inc
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#pragma once
+
+// Mutex types that satisfy the C++ Lockable requirements.
+//
+// On macOS, mutex wraps os_unfair_lock and recursive_mutex wraps
+// os_unfair_recursive_lock. These are faster and significantly smaller than
+// std::mutex / std::recursive_mutex, which wrap the equivalent pthread mutexes.
+//
+// On other platforms, these are type aliases for the std equivalents.
+//
+// Note that `std::mutex` must still be used with `std::condition_variable` as
+// `std::condition_variable` only works with `std::mutex`.
+
+#ifndef __APPLE__
+
+#include <mutex>
+
+namespace bn::base {
+
+using mutex = std::mutex;
+using recursive_mutex = std::recursive_mutex;
+
+} // namespace bn::base
+
+#else
+
+#include <os/lock.h>
+
+namespace bn::base {
+
+class mutex
+{
+ os_unfair_lock m_lock = OS_UNFAIR_LOCK_INIT;
+
+public:
+ mutex() = default;
+
+ mutex(const mutex&) = delete;
+ mutex& operator=(const mutex&) = delete;
+ mutex(mutex&&) = delete;
+ mutex& operator=(mutex&&) = delete;
+
+ void lock()
+ {
+ os_unfair_lock_lock(&m_lock);
+ }
+
+ bool try_lock()
+ {
+ return os_unfair_lock_trylock(&m_lock);
+ }
+
+ void unlock()
+ {
+ os_unfair_lock_unlock(&m_lock);
+ }
+};
+
+// os_unfair_recursive_lock is private API. We provide our own declarations for it here.
+// From https://github.com/apple-oss-distributions/libplatform/blob/libplatform-359.60.3/private/os/lock_private.h#L404-L463
+namespace detail {
+
+struct os_unfair_recursive_lock {
+ os_unfair_lock ourl_lock;
+ uint32_t ourl_count;
+};
+
+extern "C" {
+
+OS_NOTHROW OS_NONNULL_ALL
+void os_unfair_recursive_lock_lock_with_options(os_unfair_recursive_lock* lock,
+ int options);
+
+OS_NOTHROW OS_NONNULL_ALL
+bool os_unfair_recursive_lock_trylock(os_unfair_recursive_lock* lock);
+
+OS_NOTHROW OS_NONNULL_ALL
+void os_unfair_recursive_lock_unlock(os_unfair_recursive_lock* lock);
+
+};
+
+} // namespace bn::base::detail
+
+class recursive_mutex
+{
+ detail::os_unfair_recursive_lock m_lock{OS_UNFAIR_LOCK_INIT, 0};
+
+public:
+ recursive_mutex() = default;
+
+ recursive_mutex(const recursive_mutex&) = delete;
+ recursive_mutex& operator=(const recursive_mutex&) = delete;
+ recursive_mutex(recursive_mutex&&) = delete;
+ recursive_mutex& operator=(recursive_mutex&&) = delete;
+
+ void lock()
+ {
+ os_unfair_recursive_lock_lock_with_options(&m_lock, 0);
+ }
+
+ bool try_lock()
+ {
+ return os_unfair_recursive_lock_trylock(&m_lock);
+ }
+
+ void unlock()
+ {
+ os_unfair_recursive_lock_unlock(&m_lock);
+ }
+};
+
+} // namespace bn::base
+
+#endif