mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-07 15:36:26 +00:00
Implement shared_cptr and atomic_cptr
Limited shared_ptr with atomic support. Atomic version is only partially implemented.
This commit is contained in:
parent
3617f12a1e
commit
1e7a02badb
5 changed files with 565 additions and 0 deletions
73
rpcs3/util/shared_cptr.cpp
Normal file
73
rpcs3/util/shared_cptr.cpp
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue