/* @file Refcounted.cpp */ #include "Refcounted.hpp" #include "pretty_refcnt.hpp" namespace xo { namespace ref { #ifdef XO_INTRUSIVE_PTR_ENABLE_LOGGING namespace { /* verbose logging for intrusive_ptr */ static bool s_logging_enabled = false; void intrusive_ptr_log_aux(std::string_view const & self_type, std::string_view const & method_name, void * this_ptr, Refcount * x) { scope lscope(XO_LITERAL(log_level::verbose, self_type, method_name), "enter", xtag("this", this_ptr), xtag("x", x), xtag("n", intrusive_ptr_refcount(x))); } /*intrusive_ptr_log_aux*/ } /*namespace*/ void intrusive_ptr_set_debug(bool debug_flag) { s_logging_enabled = debug_flag; } /*intrusive_ptr_set_debug*/ void intrusive_ptr_log_ctor(std::string_view const & self_type, void * this_ptr, Refcount * x) { if (s_logging_enabled) intrusive_ptr_log_aux(self_type, "::ctor", this_ptr, x); } /*intrusive_ptr_log_ctor*/ void intrusive_ptr_log_actor(std::string_view const & self_type, void * this_ptr, Refcount * x) { if (s_logging_enabled) intrusive_ptr_log_aux(self_type, "::actor", this_ptr, x); } /*intrusive_ptr_log_actor*/ void intrusive_ptr_log_cctor(std::string_view const & self_type, void * this_ptr, Refcount * x) { if (s_logging_enabled) intrusive_ptr_log_aux(self_type, "::cctor", this_ptr, x); } /*intrusive_ptr_log_cctor*/ void intrusive_ptr_log_mctor(std::string_view const & self_type, void * this_ptr, Refcount * x) { if (s_logging_enabled) intrusive_ptr_log_aux(self_type, "::mctor", this_ptr, x); } /*intrusive_ptr_log_mctor*/ void intrusive_ptr_log_dtor(std::string_view const & self_type, void * this_ptr, Refcount * x) { if (s_logging_enabled) intrusive_ptr_log_aux(self_type, "::dtor", this_ptr, x); } /*intrusive_ptr_log_dtor*/ void intrusive_ptr_log_assign(std::string_view const & self_type, void * this_ptr, Refcount * x) { if (s_logging_enabled) intrusive_ptr_log_aux(self_type, "::=", this_ptr, x); } /*intrusive_ptr_log_assign*/ void intrusive_ptr_log_massign(std::string_view const & self_type, void * this_ptr, Refcount * x) { if (s_logging_enabled) intrusive_ptr_log_aux(self_type, "::m=", this_ptr, x); } /*intrusive_ptr_log_massign*/ #endif void intrusive_ptr_add_ref(Refcount * x) { /* for adding reference -- can use relaxed order, * since any reordering of a set of intrusive_ptr_add_ref() * calls is ok, provided no intervening intrusive_ptr_release() * calls. */ bool success = (x == nullptr); while(!success) { uint32_t n = x->reference_counter_.load(std::memory_order_relaxed); success = x->reference_counter_.compare_exchange_strong(n, n+1, std::memory_order_relaxed); } } /*intrusive_ptr_add_ref*/ void intrusive_ptr_release(Refcount * x) { using xo::scope; using xo::xtag; scope log(XO_ENTER0(verbose), "enter", xtag("x", x), xtag("n", x ? x->reference_counter_.load() : 0)); /* for decrement, need acq_rel ordering */ bool success = (x == nullptr); uint32_t n = 0; while(!success) { n = x->reference_counter_.load(std::memory_order_acquire); if(n == static_cast(-1)) { log && log("detected double-delete attempt", xtag("x", x), xtag("n", n)); assert(false); } success = x->reference_counter_.compare_exchange_strong(n, n-1, std::memory_order_acq_rel); } if(n == 1) { /* just deleted the last reference, so recover the object */ log && log("delete object with 0 refs"); /* for good measure: replace refcount with -1, * in hope of detecting a double-delete attempt */ x->reference_counter_.store(static_cast(-1)); delete x; } } /*intrusive_ptr_release*/ } /*namespace ref*/ } /*namespace xo*/ /* end Refcounted.cpp */