1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 10:42:36 +01:00

Implement shared_mutex::lock_unlock

Minor fix for shared_mutex::try_lock - don't optimize for pessimistic case
This commit is contained in:
Nekotekina 2018-10-01 20:03:40 +03:00
parent 8a1b5abee1
commit 7a024f3355
2 changed files with 82 additions and 19 deletions

View File

@ -38,13 +38,7 @@ void shared_mutex::imp_unlock_shared(u32 old)
// Check reader count, notify the writer if necessary // Check reader count, notify the writer if necessary
if ((old - 1) % c_one == 0) if ((old - 1) % c_one == 0)
{ {
#ifdef _WIN32 imp_signal();
NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr);
#else
m_value += c_sig;
futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, 1, nullptr, nullptr, c_sig);
#endif
} }
} }
@ -77,6 +71,17 @@ void shared_mutex::imp_wait()
#endif #endif
} }
void shared_mutex::imp_signal()
{
#ifdef _WIN32
NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr);
#else
m_value += c_sig;
futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, 1, nullptr, nullptr, c_sig);
//futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, c_one, nullptr, nullptr, c_sig - 1);
#endif
}
void shared_mutex::imp_lock(u32 val) void shared_mutex::imp_lock(u32 val)
{ {
verify("shared_mutex underflow" HERE), val < c_err; verify("shared_mutex underflow" HERE), val < c_err;
@ -85,7 +90,7 @@ void shared_mutex::imp_lock(u32 val)
{ {
busy_wait(); busy_wait();
if (try_lock()) if (!m_value && try_lock())
{ {
return; return;
} }
@ -108,19 +113,10 @@ void shared_mutex::imp_unlock(u32 old)
// 1) Notify the next writer if necessary // 1) Notify the next writer if necessary
// 2) Notify all readers otherwise if necessary (currently indistinguishable from writers) // 2) Notify all readers otherwise if necessary (currently indistinguishable from writers)
#ifdef _WIN32
if (old - c_one) if (old - c_one)
{ {
NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr); imp_signal();
} }
#else
if (old - c_one)
{
m_value += c_sig;
futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, 1, nullptr, nullptr, c_sig);
}
#endif
} }
void shared_mutex::imp_lock_upgrade() void shared_mutex::imp_lock_upgrade()
@ -147,3 +143,59 @@ void shared_mutex::imp_lock_upgrade()
imp_wait(); imp_wait();
} }
void shared_mutex::imp_lock_unlock()
{
u32 _max = 1;
for (int i = 0; i < 30; i++)
{
const u32 val = m_value;
if (val % c_one == 0 && (val / c_one < _max || val >= c_sig))
{
// Return if have cought a state where:
// 1) Mutex is free
// 2) Total number of waiters decreased since last check
// 3) Signal bit is set (if used on the platform)
return;
}
_max = val / c_one;
busy_wait(1500);
}
#ifndef _WIN32
while (false)
{
const u32 val = m_value;
if (val % c_one == 0 && (val / c_one < _max || val >= c_sig))
{
return;
}
if (val <= c_one)
{
// Can't expect a signal
break;
}
_max = val / c_one;
// Monitor all bits except c_sig
futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAIT_BITSET_PRIVATE, val, nullptr, nullptr, c_sig - 1);
}
#endif
// Lock and unlock
if (!m_value.fetch_add(c_one))
{
unlock();
return;
}
imp_wait();
unlock();
}

View File

@ -19,9 +19,11 @@ class shared_mutex final
void imp_lock_shared(u32 val); void imp_lock_shared(u32 val);
void imp_unlock_shared(u32 old); void imp_unlock_shared(u32 old);
void imp_wait(); void imp_wait();
void imp_signal();
void imp_lock(u32 val); void imp_lock(u32 val);
void imp_unlock(u32 old); void imp_unlock(u32 old);
void imp_lock_upgrade(); void imp_lock_upgrade();
void imp_lock_unlock();
public: public:
constexpr shared_mutex() = default; constexpr shared_mutex() = default;
@ -57,7 +59,7 @@ public:
bool try_lock() bool try_lock()
{ {
return m_value == 0 && m_value.compare_and_swap_test(0, c_one); return m_value.compare_and_swap_test(0, c_one);
} }
void lock() void lock()
@ -103,6 +105,15 @@ public:
m_value -= c_one - 1; m_value -= c_one - 1;
} }
// Optimized wait for lockability without locking, relaxed
void lock_unlock()
{
if (UNLIKELY(m_value != 0))
{
imp_lock_unlock();
}
}
// Check whether can immediately obtain an exclusive (writer) lock // Check whether can immediately obtain an exclusive (writer) lock
bool is_free() const bool is_free() const
{ {