diff --git a/include/ircd/run.h b/include/ircd/run.h index 9e68ffda9..ec79a5d6b 100644 --- a/include/ircd/run.h +++ b/include/ircd/run.h @@ -23,6 +23,7 @@ namespace ircd::ctx namespace ircd::run { enum class level :int; + template struct barrier; struct changed; string_view reflect(const enum level &); @@ -124,4 +125,26 @@ struct ircd::run::changed /// Default construction for no-op changed() noexcept; ~changed() noexcept; + + // convenience to wait on the dock for the levels + static void wait(const std::initializer_list &); +}; + +/// Tool to yield a context until the run::level is RUN or QUIT. Once either is +/// satisfied (or if already satisfied) the run::level is checked to be RUN +/// otherwise an exception is thrown. +/// +template +struct ircd::run::barrier +{ + template + barrier(args&&... a) + { + changed::wait({level::RUN, level::QUIT}); + if(unlikely(level != level::RUN)) + throw exception + { + std::forward(a)... + }; + } }; diff --git a/ircd/run.cc b/ircd/run.cc index 3b7ef5749..9df30a774 100644 --- a/ircd/run.cc +++ b/ircd/run.cc @@ -64,6 +64,23 @@ noexcept { } +void +ircd::run::changed::wait(const std::initializer_list &levels) +{ + changed::dock.wait([&levels] + { + return std::any_of(begin(levels), end(levels), [] + (const auto &level) + { + return run::level == level; + }); + }); +} + +// +// ircd::run +// + /// The notification will be posted to the io_context. This is important to /// prevent the callback from continuing execution on some ircd::ctx stack and /// instead invoke their function on the main stack in their own io_context