mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-04 22:19:02 +00:00
[orbis-kernel] Implement shared_cv
Shared (IPC-ready) condition variable. Relicensed and improved from RPCS3.
This commit is contained in:
parent
c269d23665
commit
5bb820084e
5 changed files with 171 additions and 0 deletions
69
orbis-kernel/include/orbis/utils/SharedCV.hpp
Normal file
69
orbis-kernel/include/orbis/utils/SharedCV.hpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <orbis/utils/AtomicOp.hpp>
|
||||
#include <orbis/utils/SharedMutex.hpp>
|
||||
|
||||
namespace orbis {
|
||||
inline namespace utils {
|
||||
// IPC-ready lightweight condition variable
|
||||
class shared_cv {
|
||||
enum : unsigned {
|
||||
c_waiter_mask = 0xffff,
|
||||
c_signal_mask = 0xffffffff & ~c_waiter_mask,
|
||||
};
|
||||
|
||||
std::atomic<unsigned> m_value{0};
|
||||
|
||||
protected:
|
||||
// Increment waiter count
|
||||
unsigned add_waiter() noexcept {
|
||||
return atomic_op(m_value, [](unsigned &value) -> unsigned {
|
||||
if ((value & c_signal_mask) == c_signal_mask ||
|
||||
(value & c_waiter_mask) == c_waiter_mask) {
|
||||
// Signal or waiter overflow, return immediately
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add waiter (c_waiter_mask)
|
||||
value += 1;
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
// Internal waiting function
|
||||
void impl_wait(shared_mutex &mutex, unsigned _old,
|
||||
std::uint64_t usec_timeout) noexcept;
|
||||
|
||||
// Try to notify up to _count threads
|
||||
void impl_wake(shared_mutex &mutex, int _count) noexcept;
|
||||
|
||||
public:
|
||||
constexpr shared_cv() = default;
|
||||
|
||||
void wait(shared_mutex &mutex, std::uint64_t usec_timeout = -1) noexcept {
|
||||
const unsigned _old = add_waiter();
|
||||
if (!_old) {
|
||||
return;
|
||||
}
|
||||
|
||||
mutex.unlock();
|
||||
impl_wait(mutex, _old, usec_timeout);
|
||||
}
|
||||
|
||||
// Wake one thread
|
||||
void notify_one(shared_mutex &mutex) noexcept {
|
||||
if (m_value) {
|
||||
impl_wake(mutex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Wake all threads
|
||||
void notify_all(shared_mutex &mutex) noexcept {
|
||||
if (m_value) {
|
||||
impl_wake(mutex, INT_MAX);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace utils
|
||||
} // namespace orbis
|
||||
|
|
@ -101,6 +101,9 @@ public:
|
|||
|
||||
// Check whether can immediately obtain a shared (reader) lock
|
||||
bool is_lockable() const { return m_value.load() < c_one - 1; }
|
||||
|
||||
// For CV
|
||||
unsigned lock_forced();
|
||||
};
|
||||
|
||||
// Simplified shared (reader) lock implementation.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue