0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-26 15:33:54 +01:00

ircd::ctx: Improve promise / future behaviors; cleanup.

This commit is contained in:
Jason Volk 2018-03-10 17:32:54 -08:00
parent 30700b2ad8
commit 07c1356dae
3 changed files with 99 additions and 22 deletions

View file

@ -20,9 +20,6 @@ namespace ircd::ctx
template<class... T> struct scoped_future;
enum class future_status;
template<class T,
class time_point>
future_status wait_until(const future<T> &, const time_point &);
}
enum class ircd::ctx::future_status
@ -35,7 +32,7 @@ enum class ircd::ctx::future_status
template<class T>
struct ircd::ctx::future
{
shared_state<T> st;
mutable shared_state<T> st;
public:
using value_type = typename shared_state<T>::value_type;
@ -69,7 +66,7 @@ struct ircd::ctx::future
template<>
struct ircd::ctx::future<void>
{
shared_state<void> st;
mutable shared_state<void> st;
public:
using value_type = typename shared_state<void>::value_type;
@ -95,6 +92,13 @@ struct ircd::ctx::future<void>
~future() noexcept;
};
namespace ircd::ctx
{
template<class T,
class time_point>
future_status wait_until(const future<T> &, const time_point &, std::nothrow_t);
}
template<class... T>
struct ircd::ctx::scoped_future
:future<T...>
@ -199,8 +203,11 @@ T
ircd::ctx::future<T>::get()
{
wait();
if(unlikely(retrieved(st)))
throw future_already_retrieved{};
if(unlikely(bool(st.eptr)))
set_retrieved(st);
if(bool(st.eptr))
std::rethrow_exception(st.eptr);
return st.val;
@ -271,7 +278,15 @@ ircd::ctx::future_status
ircd::ctx::future<void>::wait_until(const time_point &tp)
const
{
return ircd::ctx::wait_until(*this, tp);
const auto status
{
this->wait_until(tp, std::nothrow)
};
if(status == future_status::timeout)
throw timeout{};
return status;
}
template<class T>
@ -290,7 +305,19 @@ ircd::ctx::future<void>::wait_until(const time_point &tp,
std::nothrow_t)
const
{
return ircd::ctx::wait_until(*this, tp, std::nothrow);
const auto status
{
ircd::ctx::wait_until(*this, tp, std::nothrow)
};
if(status == future_status::ready)
{
set_retrieved(st);
if(bool(st.eptr))
std::rethrow_exception(st.eptr);
}
return status;
}
template<class T,

View file

@ -24,13 +24,6 @@ namespace ircd::ctx
IRCD_EXCEPTION(future_error, broken_promise)
IRCD_EXCEPTION(future_error, future_already_retrieved)
IRCD_EXCEPTION(future_error, promise_already_satisfied)
template<class T> size_t refcount(const shared_state<T> &);
template<class T> void update(shared_state<T> &s);
template<class T> void invalidate(shared_state<T> &);
template<class T> void remove(shared_state<T> &, promise<T> &);
template<class T> void update(promise<T> &new_, promise<T> &old);
template<class T> void append(promise<T> &new_, promise<T> &old);
}
template<class T>
@ -90,6 +83,16 @@ struct ircd::ctx::promise<void>
~promise() noexcept;
};
namespace ircd::ctx
{
template<class T> size_t refcount(const shared_state<T> &);
template<class T> void update(shared_state<T> &s);
template<class T> void invalidate(shared_state<T> &);
template<class T> void remove(shared_state<T> &, promise<T> &);
template<class T> void update(promise<T> &new_, promise<T> &old);
template<class T> void append(promise<T> &new_, promise<T> &old);
}
template<class T>
ircd::ctx::promise<T>::promise(promise<T> &&o)
noexcept
@ -195,12 +198,15 @@ void
ircd::ctx::promise<T>::set_value(T&& val)
{
assert(valid());
assert(pending(*st));
if(unlikely(ready(*st)))
throw promise_already_satisfied{};
st->val = std::move(val);
auto *const st{this->st};
invalidate(*st);
set_ready(*st);
notify(*st);
assert(!valid());
}
template<class T>
@ -208,23 +214,29 @@ void
ircd::ctx::promise<T>::set_value(const T &val)
{
assert(valid());
assert(pending(*st));
if(unlikely(!pending(*st)))
throw promise_already_satisfied{};
st->val = val;
auto *const st{this->st};
invalidate(*st);
set_ready(*st);
notify(*st);
assert(!valid());
}
inline void
ircd::ctx::promise<void>::set_value()
{
assert(valid());
assert(pending(*st));
if(unlikely(!pending(*st)))
throw promise_already_satisfied{};
auto *const st{this->st};
invalidate(*st);
set_ready(*st);
notify(*st);
assert(!valid());
}
template<class T>
@ -232,24 +244,30 @@ void
ircd::ctx::promise<T>::set_exception(std::exception_ptr eptr)
{
assert(valid());
assert(pending(*st));
if(unlikely(!pending(*st)))
throw promise_already_satisfied{};
st->eptr = std::move(eptr);
auto *const st{this->st};
invalidate(*st);
set_ready(*st);
notify(*st);
assert(!valid());
}
inline void
ircd::ctx::promise<void>::set_exception(std::exception_ptr eptr)
{
assert(valid());
assert(pending(*st));
if(unlikely(!pending(*st)))
throw promise_already_satisfied{};
st->eptr = std::move(eptr);
auto *const st{this->st};
invalidate(*st);
set_ready(*st);
notify(*st);
assert(!valid());
}
template<class T>

View file

@ -22,9 +22,13 @@ namespace ircd::ctx
template<class T> bool invalid(const shared_state<T> &);
template<class T> bool pending(const shared_state<T> &);
template<class T> bool retrieved(const shared_state<T> &);
template<class T> bool ready(const shared_state<T> &);
template<class T> void set_ready(shared_state<T> &);
template<class T> void notify(shared_state<T> &);
template<class T> void set_retrieved(shared_state<T> &);
template<class T> void set_ready(shared_state<T> &);
template<class T> void set_observed(shared_state<T> &);
template<> void set_observed(shared_state<void> &);
}
struct ircd::ctx::shared_state_base
@ -73,6 +77,20 @@ ircd::ctx::notify(shared_state<T> &st)
});
}
template<class T>
void
ircd::ctx::set_observed(shared_state<T> &st)
{
set_ready(st);
}
template<>
inline void
ircd::ctx::set_observed(shared_state<void> &st)
{
set_retrieved(st);
}
template<class T>
void
ircd::ctx::set_ready(shared_state<T> &st)
@ -80,6 +98,13 @@ ircd::ctx::set_ready(shared_state<T> &st)
st.p = reinterpret_cast<promise<T> *>(uintptr_t(0x42));
}
template<class T>
void
ircd::ctx::set_retrieved(shared_state<T> &st)
{
st.p = reinterpret_cast<promise<T> *>(uintptr_t(0x84));
}
template<class T>
bool
ircd::ctx::ready(const shared_state<T> &st)
@ -87,11 +112,18 @@ ircd::ctx::ready(const shared_state<T> &st)
return st.p == reinterpret_cast<const promise<T> *>(uintptr_t(0x42));
}
template<class T>
bool
ircd::ctx::retrieved(const shared_state<T> &st)
{
return st.p == reinterpret_cast<const promise<T> *>(uintptr_t(0x84));
}
template<class T>
bool
ircd::ctx::pending(const shared_state<T> &st)
{
return st.p > reinterpret_cast<const promise<T> *>(uintptr_t(0x42));
return st.p > reinterpret_cast<const promise<T> *>(uintptr_t(0x1000));
}
template<class T>