+ implementation
This commit is contained in:
parent
0e18026fba
commit
87b4bfa795
10 changed files with 1446 additions and 0 deletions
157
src/Refcounted.cpp
Normal file
157
src/Refcounted.cpp
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/* @file Refcounted.cpp */
|
||||
|
||||
#include "Refcounted.hpp"
|
||||
|
||||
namespace xo {
|
||||
namespace ref {
|
||||
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(verbose, self_type, method_name),
|
||||
"enter",
|
||||
xtag("this", this_ptr),
|
||||
xtag("x", x),
|
||||
xtag("n", intrusive_ptr_refcount(x)));
|
||||
} /*intrusive_ptr_log_aux*/
|
||||
} /*namespace*/
|
||||
|
||||
bool
|
||||
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*/
|
||||
|
||||
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 */
|
||||
Loading…
Add table
Add a link
Reference in a new issue