diff --git a/include/ircd/ctx/dock.h b/include/ircd/ctx/dock.h index 882b3817f..fcd1bb748 100644 --- a/include/ircd/ctx/dock.h +++ b/include/ircd/ctx/dock.h @@ -21,6 +21,8 @@ namespace ircd::ctx /// class ircd::ctx::dock { + using predicate = std::function; + list q; void notify(ctx &) noexcept; @@ -29,13 +31,13 @@ class ircd::ctx::dock bool empty() const; size_t size() const; - template bool wait_until(time_point&& tp, predicate&& pred); - template bool wait_until(time_point&& tp); + template bool wait_until(time_point&&, const predicate &); + template bool wait_until(time_point&&); - template bool wait_for(const duration &dur, predicate&& pred); - template bool wait_for(const duration &dur); + template bool wait_for(const duration &, const predicate &); + template bool wait_for(const duration &); - template void wait(predicate&& pred); + void wait(const predicate &); void wait(); void notify_all() noexcept; @@ -43,89 +45,6 @@ class ircd::ctx::dock void notify() noexcept; }; -/// Wake up the next context waiting on the dock -/// -/// Unlike notify_one(), the next context in the queue is repositioned in the -/// back before being woken up for fairness. -inline void -ircd::ctx::dock::notify() -noexcept -{ - ctx *c; - if(!(c = q.pop_front())) - return; - - q.push_back(c); - notify(*c); -} - -/// Wake up the next context waiting on the dock -inline void -ircd::ctx::dock::notify_one() -noexcept -{ - if(!q.empty()) - notify(*q.front()); -} - -/// Wake up all contexts waiting on the dock. -/// -/// We post all notifications without requesting direct context -/// switches. This ensures everyone gets notified in a single -/// transaction without any interleaving during this process. -inline void -ircd::ctx::dock::notify_all() -noexcept -{ - q.for_each([this](ctx &c) - { - notify(c); - }); -} - -inline void -ircd::ctx::dock::wait() -{ - assert(current); - const unwind::exceptional renotify{[this] - { - notify_one(); - }}; - - const unwind remove{[this] - { - q.remove(current); - }}; - - q.push_back(current); - ircd::ctx::wait(); -} - -template -void -ircd::ctx::dock::wait(predicate&& pred) -{ - if(pred()) - return; - - assert(current); - const unwind::exceptional renotify{[this] - { - notify_one(); - }}; - - const unwind remove{[this] - { - q.remove(current); - }}; - - q.push_back(current); do - { - ircd::ctx::wait(); - } - while(!pred()); -} - /// Returns true if notified; false if timed out template bool @@ -149,11 +68,10 @@ ircd::ctx::dock::wait_for(const duration &dur) } /// Returns true if predicate passed; false if timed out -template +template bool ircd::ctx::dock::wait_for(const duration &dur, - predicate&& pred) + const predicate &pred) { static const duration zero(0); @@ -208,11 +126,10 @@ ircd::ctx::dock::wait_until(time_point&& tp) } /// Returns true if predicate passed; false if timed out -template +template bool ircd::ctx::dock::wait_until(time_point&& tp, - predicate&& pred) + const predicate &pred) { if(pred()) return true; @@ -243,26 +160,3 @@ ircd::ctx::dock::wait_until(time_point&& tp, } while(1); } - -inline void -ircd::ctx::dock::notify(ctx &ctx) -noexcept -{ - ircd::ctx::notify(ctx); -} - -/// The number of contexts waiting in the queue. -inline size_t -ircd::ctx::dock::size() -const -{ - return q.size(); -} - -/// The number of contexts waiting in the queue. -inline bool -ircd::ctx::dock::empty() -const -{ - return q.empty(); -} diff --git a/ircd/ctx.cc b/ircd/ctx.cc index 10e012906..1048876fe 100644 --- a/ircd/ctx.cc +++ b/ircd/ctx.cc @@ -2349,6 +2349,116 @@ noexcept then = {}; } +/////////////////////////////////////////////////////////////////////////////// +// +// dock.h +// + +/// Wake up the next context waiting on the dock +/// +/// Unlike notify_one(), the next context in the queue is repositioned in the +/// back before being woken up for fairness. +void +ircd::ctx::dock::notify() +noexcept +{ + ctx *c; + if(!(c = q.pop_front())) + return; + + q.push_back(c); + notify(*c); +} + +/// Wake up the next context waiting on the dock +void +ircd::ctx::dock::notify_one() +noexcept +{ + if(!q.empty()) + notify(*q.front()); +} + +/// Wake up all contexts waiting on the dock. +/// +/// We post all notifications without requesting direct context +/// switches. This ensures everyone gets notified in a single +/// transaction without any interleaving during this process. +void +ircd::ctx::dock::notify_all() +noexcept +{ + q.for_each([this](ctx &c) + { + notify(c); + }); +} + +void +ircd::ctx::dock::wait() +{ + assert(current); + const unwind::exceptional renotify{[this] + { + notify_one(); + }}; + + const unwind remove{[this] + { + q.remove(current); + }}; + + q.push_back(current); + ircd::ctx::wait(); +} + +void +ircd::ctx::dock::wait(const predicate &pred) +{ + if(pred()) + return; + + assert(current); + const unwind::exceptional renotify{[this] + { + notify_one(); + }}; + + const unwind remove{[this] + { + q.remove(current); + }}; + + q.push_back(current); do + { + ircd::ctx::wait(); + } + while(!pred()); +} + +void +ircd::ctx::dock::notify(ctx &ctx) +noexcept +{ + ircd::ctx::notify(ctx); +} + +/// The number of contexts waiting in the queue. +size_t +ircd::ctx::dock::size() +const +{ + return q.size(); +} + +/// The number of contexts waiting in the queue. +bool +ircd::ctx::dock::empty() +const +{ + return q.empty(); +} + /////////////////////////////////////////////////////////////////////////////// // // ctx_list.h