0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-06-20 10:58:20 +02: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()
// 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.
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::FAULT:
@ -135,7 +136,7 @@ try
default:
break;
}
};
}};
// If the user wants to immediately drop to a command line without having to
// send a ctrl-c for it, that is provided here.

View file

@ -23,15 +23,35 @@
namespace ircd
{
struct init;
extern runlevel_handler runlevel_changed;
struct runlevel_changed;
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, runlevel_handler = {});
void init(boost::asio::io_context &ios, const std::string &conf);
void init(boost::asio::io_context &ios);
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
/// 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

View file

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

View file

@ -13,9 +13,8 @@
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
runlevel_handler runlevel_changed; // user's callback
boost::asio::io_context *ios; // user's io service
struct strand *strand; // libircd event serializer
@ -43,10 +42,9 @@ ircd::thread_id
{};
void
ircd::init(boost::asio::io_context &ios,
runlevel_handler function)
ircd::init(boost::asio::io_context &ios)
{
init(ios, std::string{}, std::move(function));
init(ios, std::string{});
}
/// 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
void
ircd::init(boost::asio::io_context &ios,
const std::string &configfile,
runlevel_handler runlevel_changed)
const std::string &configfile)
try
{
if(runlevel != runlevel::HALT)
@ -82,9 +79,6 @@ try
ircd::ios = &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.
log::init();
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
/// manually/directly, as it doesn't trigger a runlevel change itself, it just
/// notifies of one.
@ -280,18 +291,20 @@ try
{
log::debug
{
"IRCd runlevel transition from '%s' to '%s'%s",
"IRCd runlevel transition from '%s' to '%s' (notifying %zu)",
reflect(ircd::runlevel),
reflect(new_runlevel),
ircd::runlevel_changed? " (notifying user)" : ""
runlevel_changed::list.size()
};
ircd::_runlevel = new_runlevel;
ircd::runlevel_changed::dock.notify_all();
// This function will notify the user of the change to IRCd. The
// notification is posted to the io_context ensuring THERE IS NO
// CONTINUATION ON THIS STACK by the user.
if(ircd::runlevel_changed)
if(!ircd::runlevel_changed::list.empty())
{
ios->post([new_runlevel]
{
if(new_runlevel == runlevel::HALT)
@ -301,18 +314,18 @@ try
};
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
{
"IRCd %s", reflect(new_runlevel)
};
ircd::log::flush();
}
ircd::log::flush();
}
catch(const std::exception &e)
{