Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions src/hx/atomic/AtomicInt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#include "hx/atomic/AtomicInt.hpp"
#include <atomic>

// Atomic operations never block, so they don't enter a GC free zone. Each one is still a GC
// safe point, so that a loop which spins on atomics without allocating can't stall a collection.

struct hx::atomic::AtomicInt_obj::Impl
{
std::atomic_int atomic;
Expand All @@ -14,42 +17,42 @@ hx::atomic::AtomicInt_obj::AtomicInt_obj(int val) : impl(new Impl())

int hx::atomic::AtomicInt_obj::fetchAdd(int val)
{
hx::AutoGCFreeZone _;
__hxcpp_gc_safe_point();

return impl->atomic.fetch_add(val);
}

int hx::atomic::AtomicInt_obj::fetchSub(int val)
{
hx::AutoGCFreeZone _;
__hxcpp_gc_safe_point();

return impl->atomic.fetch_sub(val);
}

int hx::atomic::AtomicInt_obj::fetchAnd(int val)
{
hx::AutoGCFreeZone _;
__hxcpp_gc_safe_point();

return impl->atomic.fetch_and(val);
}

int hx::atomic::AtomicInt_obj::fetchXor(int val)
{
hx::AutoGCFreeZone _;
__hxcpp_gc_safe_point();

return impl->atomic.fetch_xor(val);
}

int hx::atomic::AtomicInt_obj::fetchOr(int val)
{
hx::AutoGCFreeZone _;
__hxcpp_gc_safe_point();

return impl->atomic.fetch_or(val);
}

int hx::atomic::AtomicInt_obj::store(int val)
{
hx::AutoGCFreeZone _;
__hxcpp_gc_safe_point();

impl->atomic.store(val);

Expand All @@ -58,21 +61,21 @@ int hx::atomic::AtomicInt_obj::store(int val)

int hx::atomic::AtomicInt_obj::load()
{
hx::AutoGCFreeZone _;
__hxcpp_gc_safe_point();

return impl->atomic.load();
}

int hx::atomic::AtomicInt_obj::exchange(int val)
{
hx::AutoGCFreeZone _;
__hxcpp_gc_safe_point();

return impl->atomic.exchange(val);
}

int hx::atomic::AtomicInt_obj::compareExchange(int expected, int replacement)
{
hx::AutoGCFreeZone _;
__hxcpp_gc_safe_point();

// On failure, compare_exchange_strong stores the current value in `original`.
int original{ expected };
Expand Down
23 changes: 10 additions & 13 deletions src/hx/atomic/AtomicObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#include "hx/atomic/AtomicObject.hpp"
#include <atomic>

// Atomic operations never block, so they don't enter a GC free zone. Each one is still a GC
// safe point, so that a loop which spins on atomics without allocating can't stall a collection.

struct hx::atomic::AtomicObject_obj::Impl
{
std::atomic<hx::Object*> atomic;
Expand Down Expand Up @@ -34,9 +37,9 @@ void hx::atomic::AtomicObject_obj::__Visit(HX_VISIT_PARAMS)

Dynamic hx::atomic::AtomicObject_obj::store(Dynamic val)
{
hx::EnterGCFreeZone();
__hxcpp_gc_safe_point();

impl->atomic.store(val);
hx::ExitGCFreeZone();

HX_OBJ_WB_GET(this, val.mPtr);

Expand All @@ -45,16 +48,16 @@ Dynamic hx::atomic::AtomicObject_obj::store(Dynamic val)

Dynamic hx::atomic::AtomicObject_obj::load()
{
hx::AutoGCFreeZone _;
__hxcpp_gc_safe_point();

return impl->atomic.load();
}

Dynamic hx::atomic::AtomicObject_obj::exchange(Dynamic val)
{
hx::EnterGCFreeZone();
__hxcpp_gc_safe_point();

Dynamic old{ impl->atomic.exchange(val) };
hx::ExitGCFreeZone();

HX_OBJ_WB_GET(this, val.mPtr);

Expand All @@ -63,25 +66,19 @@ Dynamic hx::atomic::AtomicObject_obj::exchange(Dynamic val)

Dynamic hx::atomic::AtomicObject_obj::compareExchange(Dynamic expected, Dynamic replacement)
{
__hxcpp_gc_safe_point();

// Note: using Dynamic instead of hx::Object* is important
// Dynamic has an overloaded == operator, a raw pointer to hx::Object does not.
Dynamic original{ impl->atomic.load() };
while (original == expected)
{
hx::EnterGCFreeZone();
Comment thread
Simn marked this conversation as resolved.
Resolved
if (impl->atomic.compare_exchange_strong(original.mPtr, replacement.mPtr))
{
hx::ExitGCFreeZone();

HX_OBJ_WB_GET(this, replacement.mPtr);

return original;
}
else
{
hx::ExitGCFreeZone();
continue;
}
}

return original;
Expand Down
Loading