mirror of
https://github.com/matrix-construct/construct
synced 2024-11-25 16:22:35 +01:00
ircd: Split runlevel related into header and unit.
This commit is contained in:
parent
6408ac4592
commit
0c0c3b1f41
5 changed files with 239 additions and 190 deletions
|
@ -16,10 +16,6 @@
|
||||||
|
|
||||||
namespace ircd
|
namespace ircd
|
||||||
{
|
{
|
||||||
enum class runlevel :int;
|
|
||||||
|
|
||||||
extern const enum runlevel &runlevel;
|
|
||||||
|
|
||||||
extern bool debugmode; ///< Toggle; available only ifdef RB_DEBUG
|
extern bool debugmode; ///< Toggle; available only ifdef RB_DEBUG
|
||||||
extern bool nolisten; ///< Init option to not bind listener socks.
|
extern bool nolisten; ///< Init option to not bind listener socks.
|
||||||
extern bool noautomod; ///< Option to not load modules on init.
|
extern bool noautomod; ///< Option to not load modules on init.
|
||||||
|
@ -37,6 +33,7 @@ namespace ircd
|
||||||
#include "allocator.h"
|
#include "allocator.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
|
#include "runlevel.h"
|
||||||
#include "fpe.h"
|
#include "fpe.h"
|
||||||
#include "demangle.h"
|
#include "demangle.h"
|
||||||
#include "localee.h"
|
#include "localee.h"
|
||||||
|
@ -82,61 +79,9 @@ namespace ircd
|
||||||
namespace ircd
|
namespace ircd
|
||||||
{
|
{
|
||||||
struct init;
|
struct init;
|
||||||
struct runlevel_changed;
|
|
||||||
|
|
||||||
string_view reflect(const enum runlevel &);
|
|
||||||
|
|
||||||
seconds uptime();
|
seconds uptime();
|
||||||
|
|
||||||
void init(boost::asio::io_context &ios, const string_view &origin, const string_view &hostname);
|
void init(boost::asio::io_context &ios, const string_view &origin, const string_view &hostname);
|
||||||
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
|
|
||||||
/// 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
|
|
||||||
/// similarly by the library and its modules.
|
|
||||||
///
|
|
||||||
/// Primary modes:
|
|
||||||
///
|
|
||||||
/// * HALT is the off mode. Nothing is/will be running in libircd until
|
|
||||||
/// an invocation of ircd::init();
|
|
||||||
///
|
|
||||||
/// * RUN is the service mode. Full client and application functionality
|
|
||||||
/// exists in this mode. Leaving the RUN mode is done with ircd::quit();
|
|
||||||
///
|
|
||||||
/// - Transitional modes: Modes which are working towards the next mode.
|
|
||||||
/// - Interventional modes: Modes which are *not* working towards the next
|
|
||||||
/// mode and may require some user action to continue.
|
|
||||||
///
|
|
||||||
enum class ircd::runlevel
|
|
||||||
:int
|
|
||||||
{
|
|
||||||
HALT = 0, ///< [inter] IRCd Powered off.
|
|
||||||
READY = 1, ///< [inter] Ready for user to run ios event loop.
|
|
||||||
START = 2, ///< [trans] Starting up subsystems for service.
|
|
||||||
RUN = 3, ///< [inter] IRCd in service.
|
|
||||||
QUIT = 4, ///< [trans] Clean shutdown in progress
|
|
||||||
FAULT = -1, ///< [trans] QUIT with exception (dirty shutdown)
|
|
||||||
};
|
|
||||||
|
|
81
include/ircd/runlevel.h
Normal file
81
include/ircd/runlevel.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// Matrix Construct
|
||||||
|
//
|
||||||
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||||
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice is present in all copies. The
|
||||||
|
// full license for this software is available in the LICENSE file.
|
||||||
|
|
||||||
|
#define HAVE_IRCD_IRCD_RUNLEVEL_H
|
||||||
|
|
||||||
|
namespace ircd
|
||||||
|
{
|
||||||
|
enum class runlevel :int;
|
||||||
|
struct runlevel_changed;
|
||||||
|
|
||||||
|
extern const enum runlevel &runlevel;
|
||||||
|
|
||||||
|
string_view reflect(const enum runlevel &);
|
||||||
|
bool runlevel_set(const enum runlevel &);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward declarations for because ctx.h is included after runlevel.h.
|
||||||
|
namespace ircd::ctx
|
||||||
|
{
|
||||||
|
struct dock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 &)>;
|
||||||
|
|
||||||
|
// Users on an ircd::ctx who wish to use the dock interface to wait for
|
||||||
|
// a runlevel change can directly access this static instance.
|
||||||
|
static ctx::dock dock;
|
||||||
|
|
||||||
|
/// The handler function will be called back for any runlevel change while
|
||||||
|
/// this instance remains in scope.
|
||||||
|
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
|
||||||
|
/// similarly by the library and its modules.
|
||||||
|
///
|
||||||
|
/// Primary modes:
|
||||||
|
///
|
||||||
|
/// * HALT is the off mode. Nothing is/will be running in libircd until
|
||||||
|
/// an invocation of ircd::init();
|
||||||
|
///
|
||||||
|
/// * RUN is the service mode. Full client and application functionality
|
||||||
|
/// exists in this mode. Leaving the RUN mode is done with ircd::quit();
|
||||||
|
///
|
||||||
|
/// - Transitional modes: Modes which are working towards the next mode.
|
||||||
|
/// - Interventional modes: Modes which are *not* working towards the next
|
||||||
|
/// mode and may require some user action to continue.
|
||||||
|
///
|
||||||
|
enum class ircd::runlevel
|
||||||
|
:int
|
||||||
|
{
|
||||||
|
HALT = 0, ///< [inter] IRCd Powered off.
|
||||||
|
READY = 1, ///< [inter] Ready for user to run ios event loop.
|
||||||
|
START = 2, ///< [trans] Starting up subsystems for service.
|
||||||
|
RUN = 3, ///< [inter] IRCd in service.
|
||||||
|
QUIT = 4, ///< [trans] Clean shutdown in progress
|
||||||
|
FAULT = -1, ///< [trans] QUIT with exception (dirty shutdown)
|
||||||
|
};
|
|
@ -113,6 +113,7 @@ libircd_la_SOURCES = \
|
||||||
magic.cc \
|
magic.cc \
|
||||||
fs.cc \
|
fs.cc \
|
||||||
ctx.cc \
|
ctx.cc \
|
||||||
|
runlevel.cc \
|
||||||
rfc3986.cc \
|
rfc3986.cc \
|
||||||
rfc1035.cc \
|
rfc1035.cc \
|
||||||
demangle.cc \
|
demangle.cc \
|
||||||
|
|
140
ircd/ircd.cc
140
ircd/ircd.cc
|
@ -10,9 +10,6 @@
|
||||||
|
|
||||||
namespace ircd
|
namespace ircd
|
||||||
{
|
{
|
||||||
enum runlevel _runlevel {runlevel::HALT}; // Current libircd runlevel
|
|
||||||
const enum runlevel &runlevel {_runlevel}; // Observer for current RL
|
|
||||||
|
|
||||||
bool debugmode; // meaningful ifdef RB_DEBUG
|
bool debugmode; // meaningful ifdef RB_DEBUG
|
||||||
bool nolisten; // indicates no listener binding
|
bool nolisten; // indicates no listener binding
|
||||||
bool noautomod; // no module loading on init
|
bool noautomod; // no module loading on init
|
||||||
|
@ -26,7 +23,6 @@ namespace ircd
|
||||||
std::string _hostname; // user's supplied param
|
std::string _hostname; // user's supplied param
|
||||||
ctx::ctx *main_context; // Main program loop
|
ctx::ctx *main_context; // Main program loop
|
||||||
|
|
||||||
bool set_runlevel(const enum runlevel &);
|
|
||||||
void main() noexcept;
|
void main() noexcept;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +87,7 @@ try
|
||||||
// Finally, without prior exception, the commitment to runlevel::READY
|
// Finally, without prior exception, the commitment to runlevel::READY
|
||||||
// is made here. The user can now invoke their ios.run(), or, if they
|
// is made here. The user can now invoke their ios.run(), or, if they
|
||||||
// have already, IRCd will begin main execution shortly...
|
// have already, IRCd will begin main execution shortly...
|
||||||
ircd::set_runlevel(runlevel::READY);
|
ircd::runlevel_set(runlevel::READY);
|
||||||
}
|
}
|
||||||
catch(const std::exception &e)
|
catch(const std::exception &e)
|
||||||
{
|
{
|
||||||
|
@ -127,7 +123,7 @@ noexcept
|
||||||
{
|
{
|
||||||
ctx::terminate(*main_context);
|
ctx::terminate(*main_context);
|
||||||
main_context = nullptr;
|
main_context = nullptr;
|
||||||
ircd::set_runlevel(runlevel::HALT);
|
ircd::runlevel_set(runlevel::HALT);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,12 +177,12 @@ noexcept try
|
||||||
// transitions to HALT.
|
// transitions to HALT.
|
||||||
const unwind halted{[]
|
const unwind halted{[]
|
||||||
{
|
{
|
||||||
set_runlevel(runlevel::HALT);
|
runlevel_set(runlevel::HALT);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// When this function is entered IRCd will transition to START indicating
|
// When this function is entered IRCd will transition to START indicating
|
||||||
// that subsystems are initializing.
|
// that subsystems are initializing.
|
||||||
ircd::set_runlevel(runlevel::START);
|
ircd::runlevel_set(runlevel::START);
|
||||||
|
|
||||||
// These objects are the init()'s and fini()'s for each subsystem.
|
// These objects are the init()'s and fini()'s for each subsystem.
|
||||||
// Appearing here ties their life to the main context. Initialization can
|
// Appearing here ties their life to the main context. Initialization can
|
||||||
|
@ -225,11 +221,11 @@ noexcept try
|
||||||
// When the call to wait() below completes, IRCd exits from the RUN state.
|
// When the call to wait() below completes, IRCd exits from the RUN state.
|
||||||
const unwind nominal
|
const unwind nominal
|
||||||
{
|
{
|
||||||
std::bind(&ircd::set_runlevel, runlevel::QUIT)
|
std::bind(&ircd::runlevel_set, runlevel::QUIT)
|
||||||
};
|
};
|
||||||
|
|
||||||
// IRCd will now transition to the RUN state indicating full functionality.
|
// IRCd will now transition to the RUN state indicating full functionality.
|
||||||
ircd::set_runlevel(runlevel::RUN);
|
ircd::runlevel_set(runlevel::RUN);
|
||||||
|
|
||||||
// This call blocks until the main context is notified or interrupted etc.
|
// This call blocks until the main context is notified or interrupted etc.
|
||||||
// Waiting here will hold open this stack with all of the above objects
|
// Waiting here will hold open this stack with all of the above objects
|
||||||
|
@ -258,127 +254,3 @@ ircd::uptime()
|
||||||
{
|
{
|
||||||
return seconds(ircd::time() - info::startup_time);
|
return seconds(ircd::time() - info::startup_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// runlevel
|
|
||||||
//
|
|
||||||
|
|
||||||
/// 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.
|
|
||||||
///
|
|
||||||
/// 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
|
|
||||||
/// event slice.
|
|
||||||
bool
|
|
||||||
ircd::set_runlevel(const enum runlevel &new_runlevel)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(ircd::runlevel == new_runlevel)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
log::debug
|
|
||||||
{
|
|
||||||
"IRCd runlevel transition from '%s' to '%s' (notifying %zu)",
|
|
||||||
reflect(ircd::runlevel),
|
|
||||||
reflect(new_runlevel),
|
|
||||||
runlevel_changed::list.size()
|
|
||||||
};
|
|
||||||
|
|
||||||
ircd::_runlevel = new_runlevel;
|
|
||||||
ircd::runlevel_changed::dock.notify_all();
|
|
||||||
|
|
||||||
// This latch is used to block this call when setting the runlevel
|
|
||||||
// from an ircd::ctx. If the runlevel is set from the main stack then
|
|
||||||
// the caller will have to do synchronization themselves.
|
|
||||||
ctx::latch latch
|
|
||||||
{
|
|
||||||
bool(ctx::current) // latch has count of 1 if we're on an ircd::ctx
|
|
||||||
};
|
|
||||||
|
|
||||||
// This function will notify the user of the change to IRCd. When there
|
|
||||||
// are listeners, function is posted to the io_context ensuring THERE IS
|
|
||||||
// NO CONTINUATION ON THIS STACK by the user.
|
|
||||||
const auto call_users{[new_runlevel, &latch, latching(!latch.is_ready())]
|
|
||||||
{
|
|
||||||
assert(new_runlevel == ircd::_runlevel);
|
|
||||||
|
|
||||||
log::notice
|
|
||||||
{
|
|
||||||
"IRCd %s", reflect(new_runlevel)
|
|
||||||
};
|
|
||||||
|
|
||||||
if(new_runlevel == runlevel::HALT)
|
|
||||||
ircd::log::fini();
|
|
||||||
else
|
|
||||||
ircd::log::flush();
|
|
||||||
|
|
||||||
for(const auto &handler : ircd::runlevel_changed::list)
|
|
||||||
(*handler)(new_runlevel);
|
|
||||||
|
|
||||||
if(latching)
|
|
||||||
latch.count_down();
|
|
||||||
}};
|
|
||||||
|
|
||||||
if(ircd::runlevel_changed::list.size())
|
|
||||||
ircd::post(call_users);
|
|
||||||
else
|
|
||||||
call_users();
|
|
||||||
|
|
||||||
if(ctx::current)
|
|
||||||
latch.wait();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch(const std::exception &e)
|
|
||||||
{
|
|
||||||
log::critical
|
|
||||||
{
|
|
||||||
"IRCd runlevel change to '%s': %s", reflect(new_runlevel), e.what()
|
|
||||||
};
|
|
||||||
|
|
||||||
ircd::terminate();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ircd::string_view
|
|
||||||
ircd::reflect(const enum runlevel &level)
|
|
||||||
{
|
|
||||||
switch(level)
|
|
||||||
{
|
|
||||||
case runlevel::HALT: return "HALT";
|
|
||||||
case runlevel::READY: return "READY";
|
|
||||||
case runlevel::START: return "START";
|
|
||||||
case runlevel::RUN: return "RUN";
|
|
||||||
case runlevel::QUIT: return "QUIT";
|
|
||||||
case runlevel::FAULT: return "FAULT";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "??????";
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// runlevel_changed
|
|
||||||
//
|
|
||||||
|
|
||||||
template<>
|
|
||||||
decltype(ircd::runlevel_changed::list)
|
|
||||||
ircd::util::instance_list<ircd::runlevel_changed>::list
|
|
||||||
{};
|
|
||||||
|
|
||||||
decltype(ircd::runlevel_changed::dock)
|
|
||||||
ircd::runlevel_changed::dock
|
|
||||||
{};
|
|
||||||
|
|
||||||
//
|
|
||||||
// runlevel_changed::runlevel_changed
|
|
||||||
//
|
|
||||||
|
|
||||||
ircd::runlevel_changed::runlevel_changed(handler function)
|
|
||||||
:handler{std::move(function)}
|
|
||||||
{}
|
|
||||||
|
|
||||||
ircd::runlevel_changed::~runlevel_changed()
|
|
||||||
noexcept
|
|
||||||
{}
|
|
||||||
|
|
150
ircd/runlevel.cc
Normal file
150
ircd/runlevel.cc
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
// Matrix Construct
|
||||||
|
//
|
||||||
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||||
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice is present in all copies. The
|
||||||
|
// full license for this software is available in the LICENSE file.
|
||||||
|
|
||||||
|
namespace ircd
|
||||||
|
{
|
||||||
|
static enum runlevel _runlevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
decltype(ircd::runlevel)
|
||||||
|
ircd::runlevel
|
||||||
|
{
|
||||||
|
_runlevel
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// runlevel_changed
|
||||||
|
//
|
||||||
|
|
||||||
|
template<>
|
||||||
|
decltype(ircd::runlevel_changed::list)
|
||||||
|
ircd::util::instance_list<ircd::runlevel_changed>::list
|
||||||
|
{};
|
||||||
|
|
||||||
|
decltype(ircd::runlevel_changed::dock)
|
||||||
|
ircd::runlevel_changed::dock;
|
||||||
|
|
||||||
|
//
|
||||||
|
// runlevel_changed::runlevel_changed
|
||||||
|
//
|
||||||
|
|
||||||
|
ircd::runlevel_changed::runlevel_changed(handler function)
|
||||||
|
:handler
|
||||||
|
{
|
||||||
|
std::move(function)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::runlevel_changed::~runlevel_changed()
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// util
|
||||||
|
//
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// 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
|
||||||
|
/// event slice.
|
||||||
|
bool
|
||||||
|
ircd::runlevel_set(const enum runlevel &new_runlevel)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(runlevel == new_runlevel)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
log::debug
|
||||||
|
{
|
||||||
|
"IRCd runlevel transition from '%s' to '%s' (notifying %zu)",
|
||||||
|
reflect(runlevel),
|
||||||
|
reflect(new_runlevel),
|
||||||
|
runlevel_changed::list.size()
|
||||||
|
};
|
||||||
|
|
||||||
|
_runlevel = new_runlevel;
|
||||||
|
runlevel_changed::dock.notify_all();
|
||||||
|
|
||||||
|
// This latch is used to block this call when setting the runlevel
|
||||||
|
// from an ircd::ctx. If the runlevel is set from the main stack then
|
||||||
|
// the caller will have to do synchronization themselves.
|
||||||
|
ctx::latch latch
|
||||||
|
{
|
||||||
|
bool(ctx::current) // latch has count of 1 if we're on an ircd::ctx
|
||||||
|
};
|
||||||
|
|
||||||
|
// This function will notify the user of the change to IRCd. When there
|
||||||
|
// are listeners, function is posted to the io_context ensuring THERE IS
|
||||||
|
// NO CONTINUATION ON THIS STACK by the user.
|
||||||
|
const auto call_users{[new_runlevel, &latch, latching(!latch.is_ready())]
|
||||||
|
{
|
||||||
|
assert(new_runlevel == ircd::runlevel);
|
||||||
|
|
||||||
|
log::notice
|
||||||
|
{
|
||||||
|
"IRCd %s", reflect(new_runlevel)
|
||||||
|
};
|
||||||
|
|
||||||
|
if(new_runlevel == runlevel::HALT)
|
||||||
|
log::fini();
|
||||||
|
else
|
||||||
|
log::flush();
|
||||||
|
|
||||||
|
for(const auto &handler : runlevel_changed::list)
|
||||||
|
(*handler)(new_runlevel);
|
||||||
|
|
||||||
|
if(latching)
|
||||||
|
latch.count_down();
|
||||||
|
}};
|
||||||
|
|
||||||
|
if(runlevel_changed::list.size())
|
||||||
|
ircd::post(call_users);
|
||||||
|
else
|
||||||
|
call_users();
|
||||||
|
|
||||||
|
if(ctx::current)
|
||||||
|
latch.wait();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(const std::exception &e)
|
||||||
|
{
|
||||||
|
log::critical
|
||||||
|
{
|
||||||
|
"IRCd runlevel change to '%s': %s",
|
||||||
|
reflect(new_runlevel),
|
||||||
|
e.what()
|
||||||
|
};
|
||||||
|
|
||||||
|
ircd::terminate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::string_view
|
||||||
|
ircd::reflect(const enum runlevel &level)
|
||||||
|
{
|
||||||
|
switch(level)
|
||||||
|
{
|
||||||
|
case runlevel::HALT: return "HALT";
|
||||||
|
case runlevel::READY: return "READY";
|
||||||
|
case runlevel::START: return "START";
|
||||||
|
case runlevel::RUN: return "RUN";
|
||||||
|
case runlevel::QUIT: return "QUIT";
|
||||||
|
case runlevel::FAULT: return "FAULT";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "??????";
|
||||||
|
}
|
Loading…
Reference in a new issue