xo-expression2/xo-refcnt/src/Refcounted.cpp

160 lines
5.5 KiB
C++

/* @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<uint32_t>(-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<uint32_t>(-1));
delete x;
}
} /*intrusive_ptr_release*/
} /*namespace ref*/
} /*namespace xo*/
/* end Refcounted.cpp */