mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
74 lines
1.3 KiB
C++
74 lines
1.3 KiB
C++
#include "shared_cptr.hpp"
|
|
|
|
#include <thread>
|
|
|
|
stx::atomic_base::ptr_type stx::atomic_base::ref_halve() const noexcept
|
|
{
|
|
ptr_type v = val_load();
|
|
|
|
while (true)
|
|
{
|
|
if (!(v & c_ref_mask))
|
|
{
|
|
// Nullptr or depleted reference pool
|
|
return 0;
|
|
}
|
|
else if (val_compare_exchange(v, (v & ~c_ref_mask) | (v & c_ref_mask) >> 1))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return acquired references (rounded towards zero)
|
|
return (v & ~c_ref_mask) | ((v & c_ref_mask) - ((v & c_ref_mask) >> 1) - 1);
|
|
}
|
|
|
|
stx::atomic_base::ptr_type stx::atomic_base::ref_load() const noexcept
|
|
{
|
|
ptr_type v = val_load();
|
|
|
|
while (true)
|
|
{
|
|
if (!(v & c_ref_mask))
|
|
{
|
|
if (v == 0)
|
|
{
|
|
// Null pointer
|
|
return 0;
|
|
}
|
|
|
|
// Busy wait
|
|
std::this_thread::yield();
|
|
v = val_load();
|
|
}
|
|
else if (val_compare_exchange(v, v - 1))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Obtained 1 reference from the atomic pointer
|
|
return v & ~c_ref_mask;
|
|
}
|
|
|
|
void stx::atomic_base::ref_fix(stx::atomic_base::ptr_type& _old) const noexcept
|
|
{
|
|
ptr_type old = _old & ~c_ref_mask;
|
|
ptr_type v = val_load();
|
|
|
|
while (true)
|
|
{
|
|
if ((v & ~c_ref_mask) != old || (v & c_ref_mask) == c_ref_mask)
|
|
{
|
|
// Can't return a reference to the original atomic pointer, so keep it
|
|
_old += 1;
|
|
return;
|
|
}
|
|
|
|
if (val_compare_exchange(v, v + 1))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|