160 lines
5.5 KiB
C++
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 */
|