Skip to content

Commit 6f4404c

Browse files
committed
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.
1 parent 82b1b5c commit 6f4404c

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

base/mutex.h

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright (c) 2026 Vector 35 Inc
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to
5+
// deal in the Software without restriction, including without limitation the
6+
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7+
// sell copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19+
// IN THE SOFTWARE.
20+
21+
#pragma once
22+
23+
// Mutex types that satisfy the C++ Lockable requirements.
24+
//
25+
// On macOS, mutex wraps os_unfair_lock and recursive_mutex wraps
26+
// os_unfair_recursive_lock. These are faster and significantly smaller than
27+
// std::mutex / std::recursive_mutex, which wrap the equivalent pthread mutexes.
28+
//
29+
// On other platforms, these are type aliases for the std equivalents.
30+
//
31+
// Note that `std::mutex` must still be used with `std::condition_variable` as
32+
// `std::condition_variable` only works with `std::mutex`.
33+
34+
#ifndef __APPLE__
35+
36+
#include <mutex>
37+
38+
namespace bn::base {
39+
40+
using mutex = std::mutex;
41+
using recursive_mutex = std::recursive_mutex;
42+
43+
} // namespace bn::base
44+
45+
#else
46+
47+
#include <os/lock.h>
48+
49+
namespace bn::base {
50+
51+
class mutex
52+
{
53+
os_unfair_lock m_lock = OS_UNFAIR_LOCK_INIT;
54+
55+
public:
56+
mutex() = default;
57+
58+
mutex(const mutex&) = delete;
59+
mutex& operator=(const mutex&) = delete;
60+
mutex(mutex&&) = delete;
61+
mutex& operator=(mutex&&) = delete;
62+
63+
void lock()
64+
{
65+
os_unfair_lock_lock(&m_lock);
66+
}
67+
68+
bool try_lock()
69+
{
70+
return os_unfair_lock_trylock(&m_lock);
71+
}
72+
73+
void unlock()
74+
{
75+
os_unfair_lock_unlock(&m_lock);
76+
}
77+
};
78+
79+
// os_unfair_recursive_lock is private API. We provide our own declarations for it here.
80+
// From https://github.com/apple-oss-distributions/libplatform/blob/libplatform-359.60.3/private/os/lock_private.h#L404-L463
81+
namespace detail {
82+
83+
struct os_unfair_recursive_lock {
84+
os_unfair_lock ourl_lock;
85+
uint32_t ourl_count;
86+
};
87+
88+
extern "C" {
89+
90+
OS_NOTHROW OS_NONNULL_ALL
91+
void os_unfair_recursive_lock_lock_with_options(os_unfair_recursive_lock* lock,
92+
int options);
93+
94+
OS_NOTHROW OS_NONNULL_ALL
95+
bool os_unfair_recursive_lock_trylock(os_unfair_recursive_lock* lock);
96+
97+
OS_NOTHROW OS_NONNULL_ALL
98+
void os_unfair_recursive_lock_unlock(os_unfair_recursive_lock* lock);
99+
100+
};
101+
102+
} // namespace bn::base::detail
103+
104+
class recursive_mutex
105+
{
106+
detail::os_unfair_recursive_lock m_lock{OS_UNFAIR_LOCK_INIT, 0};
107+
108+
public:
109+
recursive_mutex() = default;
110+
111+
recursive_mutex(const recursive_mutex&) = delete;
112+
recursive_mutex& operator=(const recursive_mutex&) = delete;
113+
recursive_mutex(recursive_mutex&&) = delete;
114+
recursive_mutex& operator=(recursive_mutex&&) = delete;
115+
116+
void lock()
117+
{
118+
os_unfair_recursive_lock_lock_with_options(&m_lock, 0);
119+
}
120+
121+
bool try_lock()
122+
{
123+
return os_unfair_recursive_lock_trylock(&m_lock);
124+
}
125+
126+
void unlock()
127+
{
128+
os_unfair_recursive_lock_unlock(&m_lock);
129+
}
130+
};
131+
132+
} // namespace bn::base
133+
134+
#endif

0 commit comments

Comments
 (0)