rpcs3/rpcs3/util/fifo_mutex.hpp
Ivan Chikish d34287b2cc Linux: use futex_waitv syscall for atomic waiting
In order to make this possible, some unnecessary features were removed.
2023-08-02 21:46:06 +03:00

71 lines
1.2 KiB
C++

#pragma once
#include "util/types.hpp"
#include "util/atomic.hpp"
// Mutex that tries to maintain the order of acquisition
class fifo_mutex
{
// Low 16 bits are incremented on acquisition, high 16 bits are incremented on release
atomic_t<u32> m_value{0};
public:
constexpr fifo_mutex() noexcept = default;
void lock() noexcept
{
// clang-format off
const u32 val = m_value.fetch_op([](u32& val)
{
val = (val & 0xffff0000) | ((val + 1) & 0xffff);
});
// clang-format on
if (val >> 16 != (val & 0xffff)) [[unlikely]]
{
// TODO: implement busy waiting along with moving to cpp file
m_value.wait((val & 0xffff0000) | ((val + 1) & 0xffff));
}
}
bool try_lock() noexcept
{
const u32 val = m_value.load();
if (val >> 16 == (val & 0xffff))
{
if (m_value.compare_and_swap(val, ((val + 1) & 0xffff) | (val & 0xffff0000)))
{
return true;
}
}
return false;
}
void unlock() noexcept
{
const u32 val = m_value.add_fetch(0x10000);
if (val >> 16 != (val & 0xffff))
{
m_value.notify_one();
}
}
bool is_free() const noexcept
{
const u32 val = m_value.load();
return (val >> 16) == (val & 0xffff);
}
void lock_unlock() noexcept
{
if (!is_free())
{
lock();
unlock();
}
}
};