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

ircd::ctx::dock: Add options for waiters; support queuing strategies.

This commit is contained in:
Jason Volk 2023-02-20 12:12:55 -08:00
parent 96d5b6fe57
commit e961b23d1e
2 changed files with 65 additions and 28 deletions

View file

@ -23,11 +23,13 @@ namespace ircd::ctx
/// dock is a condition variable which has no requirement for locking because
/// the context system does not require mutual exclusion for coherence.
///
class ircd::ctx::dock
struct ircd::ctx::dock
{
enum opts :uint;
struct continuation;
using predicate = std::function<bool ()>;
private:
list q;
public:
@ -35,14 +37,14 @@ class ircd::ctx::dock
size_t size() const noexcept;
bool waiting(const ctx &) const noexcept;
bool wait_until(const system_point, const predicate &);
bool wait_until(const system_point);
bool wait_until(const system_point, const predicate &, const opts = (opts)0);
bool wait_until(const system_point, const opts = (opts)0);
template<class duration> bool wait_for(const duration, const predicate &);
template<class duration> bool wait_for(const duration);
template<class duration> bool wait_for(const duration, const predicate &, const opts = (opts)0);
template<class duration> bool wait_for(const duration, const opts = (opts)0);
void wait(const predicate &);
void wait();
void wait(const predicate &, const opts = (opts)0);
void wait(const opts = (opts)0);
void terminate_all() noexcept;
void interrupt_all() noexcept;
@ -53,19 +55,40 @@ class ircd::ctx::dock
namespace ircd::ctx
{
template<> bool dock::wait_for(const microseconds, const predicate &);
template<> bool dock::wait_for(const microseconds);
template<> bool dock::wait_for(const microseconds, const predicate &, const opts);
template<> bool dock::wait_for(const microseconds, const opts);
}
struct [[gnu::visibility("internal")]]
ircd::ctx::dock::continuation
{
dock *const d;
const opts *const o;
continuation(dock *);
continuation(dock *, const opts &opts);
~continuation() noexcept;
};
/// Options. These are bitflags for forward compatibility with unrelated opts
/// even though some flags are exclusive to others.
enum ircd::ctx::dock::opts
:uint
{
/// No options.
NONE = 0x00,
/// Waiting context will add itself to back of queue. This is the default.
FIFO = 0x01,
/// Waiting context will add itself to front of queue. The default is FIFO
/// for fair queuing preventing starvation.
LIFO = 0x02,
/// Waiting context will add itself to front if its ID is lower than the
/// front, otherwise back.
SORT = 0x04,
};
/// Wake up the next context waiting on the dock
inline void
ircd::ctx::dock::notify_one()
@ -80,18 +103,20 @@ noexcept
template<class duration>
inline bool
ircd::ctx::dock::wait_for(const duration dur,
const predicate &pred)
const predicate &pred,
const opts opts)
{
static_assert(!std::is_same<duration, microseconds>());
return wait_for(duration_cast<microseconds>(dur), pred);
return wait_for(duration_cast<microseconds>(dur), pred, opts);
}
template<class duration>
inline bool
ircd::ctx::dock::wait_for(const duration dur)
ircd::ctx::dock::wait_for(const duration dur,
const opts opts)
{
static_assert(!std::is_same<duration, microseconds>());
return wait_for(duration_cast<microseconds>(dur));
return wait_for(duration_cast<microseconds>(dur), opts);
}

View file

@ -2853,19 +2853,20 @@ noexcept
}
void
ircd::ctx::dock::wait()
ircd::ctx::dock::wait(const opts opts)
{
const continuation c{this};
const continuation c{this, opts};
this_ctx::wait();
}
void
ircd::ctx::dock::wait(const predicate &pred)
ircd::ctx::dock::wait(const predicate &pred,
const opts opts)
{
if(pred())
return;
const continuation c{this}; do
const continuation c{this, opts}; do
{
this_ctx::wait();
}
@ -2874,25 +2875,27 @@ ircd::ctx::dock::wait(const predicate &pred)
template<>
bool
ircd::ctx::dock::wait_for(const microseconds dur)
ircd::ctx::dock::wait_for(const microseconds dur,
const opts opts)
{
static const microseconds zero {0};
const continuation c{this};
const continuation c{this, opts};
return ircd::ctx::wait<std::nothrow_t>(dur) > zero;
}
template<>
bool
ircd::ctx::dock::wait_for(const microseconds dur,
const predicate &pred)
const predicate &pred,
const opts opts)
{
static const microseconds zero {0};
if(pred())
return true;
const continuation c{this}; do
const continuation c{this, opts}; do
{
const bool expired
{
@ -2909,21 +2912,23 @@ ircd::ctx::dock::wait_for(const microseconds dur,
}
bool
ircd::ctx::dock::wait_until(const system_point tp)
ircd::ctx::dock::wait_until(const system_point tp,
const opts opts)
{
const continuation c{this};
const continuation c{this, opts};
return !ircd::ctx::wait_until<std::nothrow_t>(tp);
}
/// Returns true if predicate passed; false if timed out
bool
ircd::ctx::dock::wait_until(const system_point tp,
const predicate &pred)
const predicate &pred,
const opts opts)
{
if(pred())
return true;
const continuation c{this}; do
const continuation c{this, opts}; do
{
const bool expired
{
@ -2957,13 +2962,20 @@ const noexcept
// dock::continuation
//
ircd::ctx::dock::continuation::continuation(dock *const d)
ircd::ctx::dock::continuation::continuation(dock *const d,
const opts &opts)
:d{d}
,o{&opts}
{
assert(d);
assert(current);
d->q.push_back(current);
if(opts & opts::LIFO)
d->q.push_front(current);
else if(opts & opts::SORT)
d->q.push_sort(current);
else
d->q.push_back(current);
}
ircd::ctx::dock::continuation::~continuation()