From fbb9cf01966e4fc4ae6e9a05b63573c92c59c7fe Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Thu, 15 Mar 2018 11:45:01 -0700 Subject: [PATCH] ircd::ctx: Cleanup/improve the shared_state states. --- include/ircd/ctx/future.h | 16 ++--- include/ircd/ctx/promise.h | 30 ++++---- include/ircd/ctx/shared_state.h | 118 +++++++++++++++++++------------- include/ircd/ctx/when.h | 10 +-- 4 files changed, 100 insertions(+), 74 deletions(-) diff --git a/include/ircd/ctx/future.h b/include/ircd/ctx/future.h index 4d8e84d7b..8ac2a97a8 100644 --- a/include/ircd/ctx/future.h +++ b/include/ircd/ctx/future.h @@ -39,7 +39,7 @@ struct ircd::ctx::future const shared_state &state() const { return *this; } shared_state &state() { return *this; } - bool valid() const { return !invalid(state()); } + bool valid() const { return !is(state(), future_state::INVALID); } bool operator!() const { return !valid(); } operator bool() const { return valid(); } @@ -72,7 +72,7 @@ struct ircd::ctx::future const shared_state &state() const { return *this; } shared_state &state() { return *this; } - bool valid() const { return !invalid(state()); } + bool valid() const { return !is(state(), future_state::INVALID); } bool operator!() const { return !valid(); } operator bool() const { return valid(); } @@ -150,7 +150,7 @@ ircd::ctx::future::future(promise &promise) inline ircd::ctx::future::future(already_t) { - set_ready(state()); + set(state(), future_state::READY); } template @@ -213,10 +213,10 @@ T ircd::ctx::future::get() { wait(); - if(unlikely(retrieved(state()))) + if(unlikely(is(state(), future_state::RETRIEVED))) throw future_already_retrieved{}; - set_retrieved(state()); + set(state(), future_state::RETRIEVED); if(bool(state().eptr)) std::rethrow_exception(state().eptr); @@ -327,7 +327,7 @@ const const_cast *>(this)->state() }; - set_retrieved(state); + set(state, future_state::RETRIEVED); if(bool(state.eptr)) std::rethrow_exception(state.eptr); } @@ -366,10 +366,10 @@ ircd::ctx::wait_until(const future &f, const auto wfun([&state]() -> bool { - return !pending(state); + return !is(state, future_state::PENDING); }); - if(unlikely(invalid(state))) + if(unlikely(is(state, future_state::INVALID))) throw no_state{}; if(unlikely(!state.cond.wait_until(tp, wfun))) diff --git a/include/ircd/ctx/promise.h b/include/ircd/ctx/promise.h index aba01b7c2..0d460ce1e 100644 --- a/include/ircd/ctx/promise.h +++ b/include/ircd/ctx/promise.h @@ -198,13 +198,13 @@ void ircd::ctx::promise::set_value(T&& val) { assert(valid()); - if(unlikely(ready(state()))) + if(unlikely(!is(state(), future_state::PENDING))) throw promise_already_satisfied{}; st->val = std::move(val); auto *const st{this->st}; invalidate(*st); - set_ready(*st); + set(*st, future_state::READY); notify(*st); assert(!valid()); } @@ -214,13 +214,13 @@ void ircd::ctx::promise::set_value(const T &val) { assert(valid()); - if(unlikely(!pending(state()))) + if(unlikely(!is(state(), future_state::PENDING))) throw promise_already_satisfied{}; st->val = val; auto *const st{this->st}; invalidate(*st); - set_ready(*st); + set(*st, future_state::READY); notify(*st); assert(!valid()); } @@ -229,12 +229,12 @@ inline void ircd::ctx::promise::set_value() { assert(valid()); - if(unlikely(!pending(state()))) + if(unlikely(!is(state(), future_state::PENDING))) throw promise_already_satisfied{}; auto *const st{this->st}; invalidate(*st); - set_ready(*st); + set(*st, future_state::READY); notify(*st); assert(!valid()); } @@ -244,13 +244,13 @@ void ircd::ctx::promise::set_exception(std::exception_ptr eptr) { assert(valid()); - if(unlikely(!pending(state()))) + if(unlikely(!is(state(), future_state::PENDING))) throw promise_already_satisfied{}; st->eptr = std::move(eptr); auto *const st{this->st}; invalidate(*st); - set_ready(*st); + set(*st, future_state::READY); notify(*st); assert(!valid()); } @@ -259,13 +259,13 @@ inline void ircd::ctx::promise::set_exception(std::exception_ptr eptr) { assert(valid()); - if(unlikely(!pending(state()))) + if(unlikely(!is(state(), future_state::PENDING))) throw promise_already_satisfied{}; st->eptr = std::move(eptr); auto *const st{this->st}; invalidate(*st); - set_ready(*st); + set(*st, future_state::READY); notify(*st); assert(!valid()); } @@ -293,7 +293,7 @@ ircd::ctx::update(promise &new_, { assert(old.st); auto &st{*old.st}; - if(!pending(st)) + if(!is(st, future_state::PENDING)) return; if(st.p == &old) @@ -316,7 +316,7 @@ void ircd::ctx::remove(shared_state &st, promise &p) { - if(!pending(st)) + if(!is(st, future_state::PENDING)) return; if(st.p == &p) @@ -338,7 +338,7 @@ template void ircd::ctx::invalidate(shared_state &st) { - if(pending(st)) + if(is(st, future_state::PENDING)) for(promise *p{st.p}; p; p = p->next) p->st = nullptr; } @@ -347,7 +347,7 @@ template void ircd::ctx::update(shared_state &st) { - if(pending(st)) + if(is(st, future_state::PENDING)) for(promise *p{st.p}; p; p = p->next) p->st = &st; } @@ -357,7 +357,7 @@ size_t ircd::ctx::refcount(const shared_state &st) { size_t ret{0}; - if(pending(st)) + if(is(st, future_state::PENDING)) for(const promise *p{st.p}; p; p = p->next) ++ret; diff --git a/include/ircd/ctx/shared_state.h b/include/ircd/ctx/shared_state.h index d7d54a968..c97a7d76f 100644 --- a/include/ircd/ctx/shared_state.h +++ b/include/ircd/ctx/shared_state.h @@ -16,21 +16,32 @@ namespace ircd::ctx struct shared_state_base; template struct shared_state; template<> struct shared_state; - template struct promise; template<> struct promise; + enum class future_state; - template bool invalid(const shared_state &); - template bool pending(const shared_state &); - template bool retrieved(const shared_state &); - template bool ready(const shared_state &); + template future_state state(const shared_state &); + template bool is(const shared_state &, const future_state &); + template void set(shared_state &, const future_state &); + template<> void set(shared_state &, const future_state &); template void notify(shared_state &); - template void set_retrieved(shared_state &); - template void set_ready(shared_state &); - template void set_observed(shared_state &); - template<> void set_observed(shared_state &); } +/// Internal state enumeration for the promise / future / related. These can +/// all be observed through state() or is(); only some can be set(). This is +/// not for public manipulation. +enum class ircd::ctx::future_state +{ + INVALID, ///< Null. + PENDING, ///< Promise is attached and busy. + READY, ///< Result ready; promise is gone. + OBSERVED, ///< Special case for when_*(); not a state; promise is gone. + RETRIEVED, ///< User retrieved future value; promise is gone. +}; + +/// Internal Non-template base of the state object shared by promise and +/// future. It is extended by the appropriate template, and usually resides +/// in the future's instance, where the promise finds it. struct ircd::ctx::shared_state_base { mutable dock cond; @@ -38,6 +49,7 @@ struct ircd::ctx::shared_state_base std::function then; }; +/// Internal shared state between future and promise appropos a future value. template struct ircd::ctx::shared_state :shared_state_base @@ -56,6 +68,8 @@ struct ircd::ctx::shared_state shared_state() = default; }; +/// Internal shared state between future and promise when there is no future +/// value, only a notification of completion or exception. template<> struct ircd::ctx::shared_state :shared_state_base @@ -71,6 +85,7 @@ struct ircd::ctx::shared_state shared_state() = default; }; +/// Internal use template void ircd::ctx::notify(shared_state &st) @@ -89,58 +104,69 @@ ircd::ctx::notify(shared_state &st) }); } +/// Internal use template void -ircd::ctx::set_observed(shared_state &st) +ircd::ctx::set(shared_state &st, + const future_state &state) { - set_ready(st); + switch(state) + { + case future_state::INVALID: assert(0); return; + case future_state::PENDING: assert(0); return; + case future_state::OBSERVED: + case future_state::READY: + reinterpret_cast(st.p) = uintptr_t(0x42); + return; + + case future_state::RETRIEVED: + reinterpret_cast(st.p) = uintptr_t(0x123); + return; + } } +/// Internal use template<> inline void -ircd::ctx::set_observed(shared_state &st) +ircd::ctx::set(shared_state &st, + const future_state &state) { - set_retrieved(st); -} - -template -void -ircd::ctx::set_ready(shared_state &st) -{ - st.p = reinterpret_cast *>(uintptr_t(0x42)); -} - -template -void -ircd::ctx::set_retrieved(shared_state &st) -{ - st.p = reinterpret_cast *>(uintptr_t(0x84)); + switch(state) + { + case future_state::INVALID: assert(0); return; + case future_state::PENDING: assert(0); return; + case future_state::READY: + reinterpret_cast(st.p) = uintptr_t(0x42); + return; + + case future_state::OBSERVED: + case future_state::RETRIEVED: + reinterpret_cast(st.p) = uintptr_t(0x123); + return; + } } +/// Internal; check if the current state is something; safe but unnecessary +/// for public use. template bool -ircd::ctx::ready(const shared_state &st) +ircd::ctx::is(const shared_state &st, + const future_state &state_) { - return st.p == reinterpret_cast *>(uintptr_t(0x42)); + return state(st) == state_; } +/// Internal; get the current state of the shared_state; safe but unnecessary +/// for public use. template -bool -ircd::ctx::retrieved(const shared_state &st) +ircd::ctx::future_state +ircd::ctx::state(const shared_state &st) { - return st.p == reinterpret_cast *>(uintptr_t(0x84)); -} - -template -bool -ircd::ctx::pending(const shared_state &st) -{ - return st.p > reinterpret_cast *>(uintptr_t(0x1000)); -} - -template -bool -ircd::ctx::invalid(const shared_state &st) -{ - return st.p == nullptr; + switch(uintptr_t(st.p)) + { + case 0x00: return future_state::INVALID; + case 0x42: return future_state::READY; + case 0x123: return future_state::RETRIEVED; + default: return future_state::PENDING; + } } diff --git a/include/ircd/ctx/when.h b/include/ircd/ctx/when.h index 508da1877..e78d93008 100644 --- a/include/ircd/ctx/when.h +++ b/include/ircd/ctx/when.h @@ -54,7 +54,7 @@ ircd::ctx::when_all(it first, future ret(p); for(; first != last; ++first) - if(pending(first->state())) + if(is(first->state(), future_state::PENDING)) set_then(*first); if(refcount(p.state()) <= 1) @@ -85,7 +85,7 @@ ircd::ctx::when_any(it first, if(!p.valid()) return; - set_observed(f->state()); + set(f->state(), future_state::OBSERVED); p.set_value(f); } }; @@ -105,15 +105,15 @@ ircd::ctx::when_any(it first, future ret(p); for(auto f(first); f != last; ++f) - if(ready(f->state())) + if(is(f->state(), future_state::READY)) { - set_observed(f->state()); + set(f->state(), future_state::OBSERVED); p.set_value(f); return ret; } for(; first != last; ++first) - if(pending(first->state())) + if(is(first->state(), future_state::PENDING)) set_then(first); if(refcount(p.state()) <= 1)