0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-16 06:51:08 +01:00

ircd: Improve runlevel changed callback related.

This commit is contained in:
Jason Volk 2018-03-23 12:05:40 -07:00
parent 8ad264f72d
commit 91c9737f29
4 changed files with 59 additions and 26 deletions

View file

@ -123,9 +123,10 @@ try
// is now shared between those handlers and libircd. This means the run() // is now shared between those handlers and libircd. This means the run()
// won't return even if we call ircd::quit(). We use the callback to then // won't return even if we call ircd::quit(). We use the callback to then
// cancel the handlers so run() can return and the program can exit. // cancel the handlers so run() can return and the program can exit.
ircd::runlevel_changed = [](const enum ircd::runlevel &mode) const ircd::runlevel_changed handler{[]
(const auto &runlevel)
{ {
switch(mode) switch(runlevel)
{ {
case ircd::runlevel::HALT: case ircd::runlevel::HALT:
case ircd::runlevel::FAULT: case ircd::runlevel::FAULT:
@ -135,7 +136,7 @@ try
default: default:
break; break;
} }
}; }};
// If the user wants to immediately drop to a command line without having to // If the user wants to immediately drop to a command line without having to
// send a ctrl-c for it, that is provided here. // send a ctrl-c for it, that is provided here.

View file

@ -23,15 +23,35 @@
namespace ircd namespace ircd
{ {
struct init; struct init;
struct runlevel_changed;
extern runlevel_handler runlevel_changed;
string_view reflect(const enum runlevel &); string_view reflect(const enum runlevel &);
void init(boost::asio::io_context &ios, const std::string &conf, runlevel_handler = {}); void init(boost::asio::io_context &ios, const std::string &conf);
void init(boost::asio::io_context &ios, runlevel_handler = {}); void init(boost::asio::io_context &ios);
bool quit() noexcept; bool quit() noexcept;
} }
/// An instance of this class registers itself to be called back when
/// the ircd::runlevel has changed.
///
/// Note: Its destructor will access a list in libircd; after a callback
/// for a HALT do not unload libircd.so until destructing this object.
///
/// A static ctx::dock is also available for contexts to wait for a runlevel
/// change notification.
///
struct ircd::runlevel_changed
:instance_list<ircd::runlevel_changed>
,std::function<void (const enum runlevel &)>
{
using handler = std::function<void (const enum runlevel &)>;
static ctx::dock dock;
runlevel_changed(handler function);
~runlevel_changed() noexcept;
};
/// The runlevel allows all observers to know the coarse state of IRCd and to /// The runlevel allows all observers to know the coarse state of IRCd and to
/// react accordingly. This can be used by the embedder of libircd to know /// react accordingly. This can be used by the embedder of libircd to know
/// when it's safe to use or delete libircd resources. It is also used /// when it's safe to use or delete libircd resources. It is also used

View file

@ -179,7 +179,6 @@ namespace ircd
namespace ircd namespace ircd
{ {
enum class runlevel :int; enum class runlevel :int;
using runlevel_handler = std::function<void (const enum runlevel &)>;
constexpr size_t BUFSIZE { 512 }; constexpr size_t BUFSIZE { 512 };
extern const enum runlevel &runlevel; extern const enum runlevel &runlevel;

View file

@ -13,9 +13,8 @@
namespace ircd namespace ircd
{ {
enum runlevel _runlevel; // Current libircd runlevel enum runlevel _runlevel {runlevel::HALT}; // Current libircd runlevel
const enum runlevel &runlevel{_runlevel}; // Observer for current RL const enum runlevel &runlevel{_runlevel}; // Observer for current RL
runlevel_handler runlevel_changed; // user's callback
boost::asio::io_context *ios; // user's io service boost::asio::io_context *ios; // user's io service
struct strand *strand; // libircd event serializer struct strand *strand; // libircd event serializer
@ -43,10 +42,9 @@ ircd::thread_id
{}; {};
void void
ircd::init(boost::asio::io_context &ios, ircd::init(boost::asio::io_context &ios)
runlevel_handler function)
{ {
init(ios, std::string{}, std::move(function)); init(ios, std::string{});
} }
/// Sets up the IRCd and its main context, then returns without blocking. /// Sets up the IRCd and its main context, then returns without blocking.
@ -60,8 +58,7 @@ ircd::init(boost::asio::io_context &ios,
/// init() can only be called from a runlevel::HALT state /// init() can only be called from a runlevel::HALT state
void void
ircd::init(boost::asio::io_context &ios, ircd::init(boost::asio::io_context &ios,
const std::string &configfile, const std::string &configfile)
runlevel_handler runlevel_changed)
try try
{ {
if(runlevel != runlevel::HALT) if(runlevel != runlevel::HALT)
@ -82,9 +79,6 @@ try
ircd::ios = &ios; ircd::ios = &ios;
ircd::strand = new struct strand(ios); ircd::strand = new struct strand(ios);
// Saves the user's runlevel_changed callback which we invoke.
ircd::runlevel_changed = std::move(runlevel_changed);
// The log is available. but it is console-only until conf opens files. // The log is available. but it is console-only until conf opens files.
log::init(); log::init();
log::mark("READY"); log::mark("READY");
@ -266,6 +260,23 @@ noexcept
}); });
} }
template<>
decltype(ircd::runlevel_changed::list)
ircd::util::instance_list<ircd::runlevel_changed>::list
{};
decltype(ircd::runlevel_changed::dock)
ircd::runlevel_changed::dock
{};
ircd::runlevel_changed::runlevel_changed(handler function)
:handler{std::move(function)}
{}
ircd::runlevel_changed::~runlevel_changed()
noexcept
{}
/// Sets the runlevel of IRCd and notifies users. This should never be called /// Sets the runlevel of IRCd and notifies users. This should never be called
/// manually/directly, as it doesn't trigger a runlevel change itself, it just /// manually/directly, as it doesn't trigger a runlevel change itself, it just
/// notifies of one. /// notifies of one.
@ -280,18 +291,20 @@ try
{ {
log::debug log::debug
{ {
"IRCd runlevel transition from '%s' to '%s'%s", "IRCd runlevel transition from '%s' to '%s' (notifying %zu)",
reflect(ircd::runlevel), reflect(ircd::runlevel),
reflect(new_runlevel), reflect(new_runlevel),
ircd::runlevel_changed? " (notifying user)" : "" runlevel_changed::list.size()
}; };
ircd::_runlevel = new_runlevel; ircd::_runlevel = new_runlevel;
ircd::runlevel_changed::dock.notify_all();
// This function will notify the user of the change to IRCd. The // This function will notify the user of the change to IRCd. The
// notification is posted to the io_context ensuring THERE IS NO // notification is posted to the io_context ensuring THERE IS NO
// CONTINUATION ON THIS STACK by the user. // CONTINUATION ON THIS STACK by the user.
if(ircd::runlevel_changed) if(!ircd::runlevel_changed::list.empty())
{
ios->post([new_runlevel] ios->post([new_runlevel]
{ {
if(new_runlevel == runlevel::HALT) if(new_runlevel == runlevel::HALT)
@ -301,11 +314,12 @@ try
}; };
ircd::log::fini(); ircd::log::fini();
ircd::runlevel_changed(new_runlevel); for(const auto &handler : ircd::runlevel_changed::list)
(*handler)(new_runlevel);
}); });
}
if(!ircd::runlevel_changed || new_runlevel != runlevel::HALT) if(new_runlevel != runlevel::HALT)
{
log::notice log::notice
{ {
"IRCd %s", reflect(new_runlevel) "IRCd %s", reflect(new_runlevel)
@ -313,7 +327,6 @@ try
ircd::log::flush(); ircd::log::flush();
} }
}
catch(const std::exception &e) catch(const std::exception &e)
{ {
log::critical log::critical