mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-02 21:11:25 +12:00
New shared_mutex
Experimental sync utils New semaphore<> New cond_variable New owned_mutex
This commit is contained in:
parent
98fc131d47
commit
1c14d872a8
20 changed files with 940 additions and 543 deletions
218
Utilities/mutex.h
Normal file
218
Utilities/mutex.h
Normal file
|
@ -0,0 +1,218 @@
|
|||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "Atomic.h"
|
||||
|
||||
// Shared mutex.
|
||||
class shared_mutex final
|
||||
{
|
||||
enum : s64
|
||||
{
|
||||
c_one = 1ull << 31, // Fixed-point 1.0 value (one writer)
|
||||
c_min = 0x00000002, // Fixed-point 1.0/max_readers value
|
||||
c_sig = 0x00000001,
|
||||
c_max = c_one
|
||||
};
|
||||
|
||||
atomic_t<s64> m_value{c_one}; // Semaphore-alike counter
|
||||
|
||||
void imp_lock_shared(s64 _old);
|
||||
void imp_unlock_shared(s64 _old);
|
||||
|
||||
void imp_lock(s64 _old);
|
||||
void imp_unlock(s64 _old);
|
||||
|
||||
void imp_lock_upgrade();
|
||||
void imp_lock_degrade();
|
||||
|
||||
public:
|
||||
constexpr shared_mutex() = default;
|
||||
|
||||
bool try_lock_shared();
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
const s64 value = m_value.load();
|
||||
|
||||
// Fast path: decrement if positive
|
||||
if (UNLIKELY(value < c_min || value > c_one || !m_value.compare_and_swap_test(value, value - c_min)))
|
||||
{
|
||||
imp_lock_shared(value);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
// Unconditional increment
|
||||
const s64 value = m_value.fetch_add(c_min);
|
||||
|
||||
if (value < 0 || value > c_one - c_min)
|
||||
{
|
||||
imp_unlock_shared(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock();
|
||||
|
||||
void lock()
|
||||
{
|
||||
// Unconditional decrement
|
||||
const s64 value = m_value.fetch_sub(c_one);
|
||||
|
||||
if (value != c_one)
|
||||
{
|
||||
imp_lock(value);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
// Unconditional increment
|
||||
const s64 value = m_value.fetch_add(c_one);
|
||||
|
||||
if (value != 0)
|
||||
{
|
||||
imp_unlock(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_upgrade();
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
// TODO
|
||||
if (!m_value.compare_and_swap_test(c_one - c_min, 0))
|
||||
{
|
||||
imp_lock_upgrade();
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_degrade();
|
||||
|
||||
void lock_degrade()
|
||||
{
|
||||
// TODO
|
||||
if (!m_value.compare_and_swap_test(0, c_one - c_min))
|
||||
{
|
||||
imp_lock_degrade();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Simplified shared (reader) lock implementation, std::shared_lock compatible.
|
||||
class reader_lock final
|
||||
{
|
||||
shared_mutex& m_mutex;
|
||||
|
||||
public:
|
||||
reader_lock(const reader_lock&) = delete;
|
||||
|
||||
explicit reader_lock(shared_mutex& mutex)
|
||||
: m_mutex(mutex)
|
||||
{
|
||||
m_mutex.lock_shared();
|
||||
}
|
||||
|
||||
~reader_lock()
|
||||
{
|
||||
m_mutex.unlock_shared();
|
||||
}
|
||||
};
|
||||
|
||||
// Simplified exclusive (writer) lock implementation, std::lock_guard compatible.
|
||||
class writer_lock final
|
||||
{
|
||||
shared_mutex& m_mutex;
|
||||
|
||||
public:
|
||||
writer_lock(const writer_lock&) = delete;
|
||||
|
||||
explicit writer_lock(shared_mutex& mutex)
|
||||
: m_mutex(mutex)
|
||||
{
|
||||
m_mutex.lock();
|
||||
}
|
||||
|
||||
~writer_lock()
|
||||
{
|
||||
m_mutex.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
// Exclusive (writer) lock in the scope of shared (reader) lock (experimental).
|
||||
class upgraded_lock final
|
||||
{
|
||||
shared_mutex& m_mutex;
|
||||
|
||||
public:
|
||||
upgraded_lock(const writer_lock&) = delete;
|
||||
|
||||
explicit upgraded_lock(shared_mutex& mutex)
|
||||
: m_mutex(mutex)
|
||||
{
|
||||
m_mutex.lock_upgrade();
|
||||
}
|
||||
|
||||
~upgraded_lock()
|
||||
{
|
||||
m_mutex.lock_degrade();
|
||||
}
|
||||
};
|
||||
|
||||
// Normal mutex with owner registration.
|
||||
class owned_mutex
|
||||
{
|
||||
atomic_t<u32> m_value{0};
|
||||
atomic_t<u32> m_owner{0};
|
||||
|
||||
protected:
|
||||
// Thread id
|
||||
static thread_local const u32 g_tid;
|
||||
|
||||
public:
|
||||
constexpr owned_mutex() = default;
|
||||
|
||||
// Returns false if current thread already owns the mutex.
|
||||
bool lock() noexcept;
|
||||
|
||||
// Returns false if locked by any thread.
|
||||
bool try_lock() noexcept;
|
||||
|
||||
// Returns false if current thread doesn't own the mutex.
|
||||
bool unlock() noexcept;
|
||||
|
||||
// Check state.
|
||||
bool is_locked() const { return m_value != 0; }
|
||||
|
||||
// Check owner.
|
||||
bool is_owned() const { return m_owner == g_tid; }
|
||||
};
|
||||
|
||||
// Recursive lock for owned_mutex (experimental).
|
||||
class recursive_lock final
|
||||
{
|
||||
owned_mutex& m_mutex;
|
||||
const bool m_first;
|
||||
|
||||
public:
|
||||
recursive_lock(const recursive_lock&) = delete;
|
||||
|
||||
explicit recursive_lock(owned_mutex& mutex)
|
||||
: m_mutex(mutex)
|
||||
, m_first(mutex.lock())
|
||||
{
|
||||
}
|
||||
|
||||
// Check whether the lock "owns" the mutex
|
||||
explicit operator bool() const
|
||||
{
|
||||
return m_first;
|
||||
}
|
||||
|
||||
~recursive_lock()
|
||||
{
|
||||
if (m_first && !m_mutex.unlock())
|
||||
{
|
||||
}
|
||||
}
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue