From 42d56a7bacc5c9297f0d30f182f6f9fc9e4fd8a5 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Sun, 8 Sep 2019 16:34:41 -0700 Subject: [PATCH] ircd::ctx: Fix inconsistent refcount() behavior. --- include/ircd/ctx/when.h | 9 ++++++--- ircd/ctx.cc | 31 ++++++++++++++++++------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/include/ircd/ctx/when.h b/include/ircd/ctx/when.h index 708faca82..71eb46c91 100644 --- a/include/ircd/ctx/when.h +++ b/include/ircd/ctx/when.h @@ -80,7 +80,8 @@ ircd::ctx::when_any(it first, if(is(state(closure(first)), future_state::PENDING)) when::set_any_then(p, first, closure); - if(promise::refcount(p.state()) <= 1) + assert(promise::refcount(p) >= 1); + if(promise::refcount(p) == 1) p.set_value(last); return ret; @@ -118,7 +119,8 @@ ircd::ctx::when_all(it first, if(is(state(closure(first)), future_state::PENDING)) when::set_all_then(p, first, closure); - if(promise::refcount(p.state()) <= 1) + assert(promise::refcount(p) >= 1); + if(promise::refcount(p) == 1) p.set_value(); return ret; @@ -174,7 +176,8 @@ ircd::ctx::when::all_then(promise &p) if(!p.valid()) return; - if(promise::refcount(p.state()) < 2) + assert(promise::refcount(p) >= 1); + if(promise::refcount(p) == 1) return p.set_value(); return p.remove(); diff --git a/ircd/ctx.cc b/ircd/ctx.cc index f14ce4c00..b9e35d313 100644 --- a/ircd/ctx.cc +++ b/ircd/ctx.cc @@ -1989,10 +1989,7 @@ noexcept ircd::ctx::promise_base::~promise_base() noexcept { - if(!valid()) - return; - - if(promise_base::refcount(state()) == 1) + if(promise_base::refcount(*this) == 1) set_exception(make_exception_ptr()); remove(); @@ -2024,10 +2021,18 @@ ircd::ctx::promise_base::remove() void ircd::ctx::promise_base::make_ready() { + const critical_assertion ca; + assert(valid()); + promise_base *p + { + promise_base::head(*this) + }; + + assert(p); shared_state_base *next { - shared_state_base::head(*this) + shared_state_base::head(*p) }; // First we have to chase the linked list of promises reachable @@ -2110,7 +2115,7 @@ ircd::ctx::promise_base::head(const promise_base &p) { return p.st && head(*p.st)? head(*p.st): - nullptr; + std::addressof(p); } const ircd::ctx::promise_base * @@ -2409,11 +2414,10 @@ noexcept shared_state_base::refcount(*this) }; - assert(refcount >= 1); - if(refcount <= 1) + if(refcount == 1) invalidate_promises(*this); - - remove(*this); + else if(refcount > 1) + remove(*this); } // @@ -2425,6 +2429,9 @@ size_t ircd::ctx::shared_state_base::refcount(const shared_state_base &st) { size_t ret{0}; + if(!is(st, future_state::PENDING)) + return ret; + for(const auto *next(head(st)); next; next = next->next) ++ret; @@ -2509,9 +2516,7 @@ ircd::ctx::remove(shared_state_base &st) else invalidate_promises(st); } - - assert(last); - for(auto *next(last->next); next; last = next, next = next->next) + else for(auto *next(last->next); next; last = next, next = next->next) if(next == &st) { last->next = next->next;