mirror of
https://github.com/matrix-construct/construct
synced 2024-12-26 15:33:54 +01:00
ircd::mods: Add unloading state; add public interface for loading()/unloading() query.
This commit is contained in:
parent
5fa42b5afd
commit
15b300657f
3 changed files with 49 additions and 11 deletions
|
@ -46,6 +46,8 @@ namespace ircd::mods
|
|||
namespace ircd::mods
|
||||
{
|
||||
bool loaded(const string_view &name);
|
||||
bool loading(const string_view &name);
|
||||
bool unloading(const string_view &name);
|
||||
bool available(const string_view &name);
|
||||
bool is_module(const string_view &fullpath);
|
||||
bool is_module(const string_view &fullpath, std::nothrow_t);
|
||||
|
|
57
ircd/mods.cc
57
ircd/mods.cc
|
@ -191,6 +191,30 @@ ircd::mods::available(const string_view &name)
|
|||
return !search(name, why).empty();
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::mods::unloading(const string_view &name)
|
||||
{
|
||||
const auto &list(mod::unloading);
|
||||
return end(list) != std::find_if(begin(list), end(list), [&name]
|
||||
(const auto *const &mod)
|
||||
{
|
||||
assert(mod);
|
||||
return mod->name() == name;
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::mods::loading(const string_view &name)
|
||||
{
|
||||
const auto &list(mod::loading);
|
||||
return end(list) != std::find_if(begin(list), end(list), [&name]
|
||||
(const auto *const &mod)
|
||||
{
|
||||
assert(mod);
|
||||
return mod->name() == name;
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::mods::loaded(const string_view &name)
|
||||
{
|
||||
|
@ -675,6 +699,10 @@ decltype(ircd::mods::mod::loading)
|
|||
ircd::mods::mod::loading
|
||||
{};
|
||||
|
||||
decltype(ircd::mods::mod::unloading)
|
||||
ircd::mods::mod::unloading
|
||||
{};
|
||||
|
||||
decltype(ircd::mods::mod::loaded)
|
||||
ircd::mods::mod::loaded
|
||||
{};
|
||||
|
@ -818,17 +846,7 @@ bool ircd::mapi::static_destruction;
|
|||
ircd::mods::mod::~mod()
|
||||
noexcept try
|
||||
{
|
||||
log::debug
|
||||
{
|
||||
log, "Attempting unload module '%s' @ `%s'",
|
||||
name(),
|
||||
location()
|
||||
};
|
||||
|
||||
unload();
|
||||
|
||||
const size_t erased(loaded.erase(name()));
|
||||
assert(erased == 1);
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
|
@ -849,6 +867,20 @@ ircd::mods::mod::unload()
|
|||
if(!handle.is_loaded())
|
||||
return false;
|
||||
|
||||
if(mods::unloading(name()))
|
||||
return false;
|
||||
|
||||
// Mark this module in the unloading state.
|
||||
unloading.emplace_front(this);
|
||||
|
||||
log::debug
|
||||
{
|
||||
log, "Attempting unload module '%s' @ `%s'",
|
||||
name(),
|
||||
location()
|
||||
};
|
||||
|
||||
// Call the user's unloading function here.
|
||||
if(header->fini)
|
||||
header->fini();
|
||||
|
||||
|
@ -860,6 +892,8 @@ ircd::mods::mod::unload()
|
|||
std::for_each(rbegin(this->children), rend(this->children), []
|
||||
(mod *const &ptr)
|
||||
{
|
||||
// Only trigger an unload if there is one reference remaining to the module,
|
||||
// in addition to the reference created by invoking shared_from() right here.
|
||||
if(shared_from(*ptr).use_count() <= 2)
|
||||
ptr->unload();
|
||||
});
|
||||
|
@ -874,7 +908,8 @@ ircd::mods::mod::unload()
|
|||
mapi::static_destruction = false;
|
||||
handle.unload();
|
||||
assert(!handle.is_loaded());
|
||||
|
||||
loaded.erase(name());
|
||||
unloading.remove(this);
|
||||
if(!mapi::static_destruction)
|
||||
{
|
||||
log.critical("Module \"%s\" is stuck and failing to unload.", name());
|
||||
|
|
|
@ -41,6 +41,7 @@ struct ircd::mods::mod
|
|||
:std::enable_shared_from_this<mod>
|
||||
{
|
||||
static std::forward_list<mod *> loading; // State of current dlopen() recursion.
|
||||
static std::forward_list<mod *> unloading; // dlclose() is not recursive but we have this
|
||||
static std::map<string_view, mod *, std::less<>> loaded;
|
||||
|
||||
filesystem::path path;
|
||||
|
|
Loading…
Reference in a new issue