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:
parent
8ad264f72d
commit
91c9737f29
4 changed files with 59 additions and 26 deletions
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
47
ircd/ircd.cc
47
ircd/ircd.cc
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue