2017-01-24 20:19:52 +00:00
|
|
|
#include "mutex.h"
|
|
|
|
#include "sync.h"
|
|
|
|
|
2017-10-05 12:09:08 +00:00
|
|
|
#include <climits>
|
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
void shared_mutex::imp_lock_shared(u32 val)
|
2017-01-24 20:19:52 +00:00
|
|
|
{
|
2018-09-21 17:17:16 +00:00
|
|
|
verify("shared_mutex underflow" HERE), val < c_err;
|
2017-01-24 20:19:52 +00:00
|
|
|
|
2017-02-15 15:07:42 +00:00
|
|
|
for (int i = 0; i < 10; i++)
|
2017-01-24 20:19:52 +00:00
|
|
|
{
|
2017-02-15 15:07:42 +00:00
|
|
|
busy_wait();
|
2017-01-24 20:19:52 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
if (try_lock_shared())
|
2017-01-24 20:19:52 +00:00
|
|
|
{
|
2017-02-15 15:07:42 +00:00
|
|
|
return;
|
2017-01-24 20:19:52 +00:00
|
|
|
}
|
2017-02-15 15:07:42 +00:00
|
|
|
}
|
2017-01-24 20:19:52 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
// Acquire writer lock and downgrade
|
|
|
|
const u32 old = m_value.fetch_add(c_one);
|
2017-01-24 20:19:52 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
if (old == 0)
|
2017-01-24 20:19:52 +00:00
|
|
|
{
|
2018-09-21 17:17:16 +00:00
|
|
|
lock_downgrade();
|
|
|
|
return;
|
2017-01-24 20:19:52 +00:00
|
|
|
}
|
2018-03-11 16:28:32 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one < c_sig;
|
|
|
|
imp_wait();
|
|
|
|
lock_downgrade();
|
2017-01-24 20:19:52 +00:00
|
|
|
}
|
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
void shared_mutex::imp_unlock_shared(u32 old)
|
2017-01-24 20:19:52 +00:00
|
|
|
{
|
2018-09-21 17:17:16 +00:00
|
|
|
verify("shared_mutex underflow" HERE), old - 1 < c_err;
|
2017-01-24 20:19:52 +00:00
|
|
|
|
2017-02-15 15:07:42 +00:00
|
|
|
// Check reader count, notify the writer if necessary
|
2018-09-21 17:17:16 +00:00
|
|
|
if ((old - 1) % c_one == 0)
|
2017-01-24 20:19:52 +00:00
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr);
|
|
|
|
#else
|
2018-09-21 17:17:16 +00:00
|
|
|
m_value += c_sig;
|
2017-02-24 15:48:53 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, 1, nullptr, nullptr, c_sig);
|
2017-01-24 20:19:52 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
void shared_mutex::imp_wait()
|
2017-01-24 20:19:52 +00:00
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
2018-09-21 17:17:16 +00:00
|
|
|
NtWaitForKeyedEvent(nullptr, &m_value, false, nullptr);
|
2017-01-24 20:19:52 +00:00
|
|
|
#else
|
2017-02-24 15:48:53 +00:00
|
|
|
while (true)
|
2017-01-24 20:19:52 +00:00
|
|
|
{
|
2017-02-24 15:48:53 +00:00
|
|
|
// Load new value, try to acquire c_sig
|
2018-09-21 17:17:16 +00:00
|
|
|
auto [value, ok] = m_value.fetch_op([](u32& value)
|
2017-02-24 15:48:53 +00:00
|
|
|
{
|
2018-09-21 17:17:16 +00:00
|
|
|
if (value >= c_sig)
|
2017-02-24 15:48:53 +00:00
|
|
|
{
|
2018-09-21 17:17:16 +00:00
|
|
|
value -= c_sig;
|
|
|
|
return true;
|
2017-02-24 15:48:53 +00:00
|
|
|
}
|
2018-09-21 17:17:16 +00:00
|
|
|
|
|
|
|
return false;
|
2017-02-24 15:48:53 +00:00
|
|
|
});
|
2017-02-15 15:07:42 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
if (ok)
|
2017-01-24 20:19:52 +00:00
|
|
|
{
|
2017-02-15 15:07:42 +00:00
|
|
|
return;
|
2017-01-24 20:19:52 +00:00
|
|
|
}
|
2017-02-15 15:07:42 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAIT_BITSET_PRIVATE, value, nullptr, nullptr, c_sig);
|
2017-01-24 20:19:52 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
void shared_mutex::imp_lock(u32 val)
|
2017-02-15 15:07:42 +00:00
|
|
|
{
|
2018-09-21 17:17:16 +00:00
|
|
|
verify("shared_mutex underflow" HERE), val < c_err;
|
2017-02-15 15:07:42 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
busy_wait();
|
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
if (try_lock())
|
2017-02-15 15:07:42 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
const u32 old = m_value.fetch_add(c_one);
|
|
|
|
|
|
|
|
if (old == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one < c_sig;
|
|
|
|
imp_wait();
|
2017-02-15 15:07:42 +00:00
|
|
|
}
|
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
void shared_mutex::imp_unlock(u32 old)
|
2017-01-24 20:19:52 +00:00
|
|
|
{
|
2018-09-21 17:17:16 +00:00
|
|
|
verify("shared_mutex underflow" HERE), old - c_one < c_err;
|
2017-01-24 20:19:52 +00:00
|
|
|
|
2017-02-15 15:07:42 +00:00
|
|
|
// 1) Notify the next writer if necessary
|
2018-09-21 17:17:16 +00:00
|
|
|
// 2) Notify all readers otherwise if necessary (currently indistinguishable from writers)
|
2017-02-15 15:07:42 +00:00
|
|
|
#ifdef _WIN32
|
2018-09-21 17:17:16 +00:00
|
|
|
if (old - c_one)
|
2017-01-24 20:19:52 +00:00
|
|
|
{
|
|
|
|
NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr);
|
|
|
|
}
|
|
|
|
#else
|
2018-09-21 17:17:16 +00:00
|
|
|
if (old - c_one)
|
2017-02-15 15:07:42 +00:00
|
|
|
{
|
2018-09-21 17:17:16 +00:00
|
|
|
m_value += c_sig;
|
2017-02-24 15:48:53 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
futex(reinterpret_cast<int*>(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, 1, nullptr, nullptr, c_sig);
|
2017-02-15 15:07:42 +00:00
|
|
|
}
|
|
|
|
#endif
|
2017-01-24 20:19:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void shared_mutex::imp_lock_upgrade()
|
|
|
|
{
|
2018-09-21 17:17:16 +00:00
|
|
|
for (int i = 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
busy_wait();
|
2017-01-24 20:19:52 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
if (try_lock_upgrade())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2017-01-24 20:19:52 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
// Convert to writer lock
|
|
|
|
const u32 old = m_value.fetch_add(c_one - 1);
|
2017-01-24 20:19:52 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
verify("shared_mutex overflow" HERE), (old % c_sig) + c_one - 1 < c_sig;
|
2017-01-24 20:19:52 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
if (old % c_one == 1)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2017-01-24 20:19:52 +00:00
|
|
|
|
2018-09-21 17:17:16 +00:00
|
|
|
imp_wait();
|
2017-01-24 20:19:52 +00:00
|
|
|
}
|