mirror of
https://github.com/matrix-construct/construct
synced 2024-11-12 04:51:08 +01:00
ircd::mods: Improve/reorg internal interface related.
This commit is contained in:
parent
55a70915a6
commit
84d1749f4d
2 changed files with 106 additions and 94 deletions
189
ircd/mods.cc
189
ircd/mods.cc
|
@ -56,12 +56,6 @@ decltype(ircd::mods::mod::loaded)
|
||||||
ircd::mods::mod::loaded
|
ircd::mods::mod::loaded
|
||||||
{};
|
{};
|
||||||
|
|
||||||
// Allows module to communicate static destruction is taking place when mapi::header
|
|
||||||
// destructs. If dlclose() returns without this being set, dlclose() lied about really
|
|
||||||
// unloading the module. That is considered a "stuck" module.
|
|
||||||
bool
|
|
||||||
ircd::mapi::static_destruction;
|
|
||||||
|
|
||||||
const char *const
|
const char *const
|
||||||
ircd::mapi::import_section_names[]
|
ircd::mapi::import_section_names[]
|
||||||
{
|
{
|
||||||
|
@ -70,6 +64,104 @@ ircd::mapi::import_section_names[]
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Allows module to communicate static destruction is taking place when mapi::header
|
||||||
|
// destructs. If dlclose() returns without this being set, dlclose() lied about really
|
||||||
|
// unloading the module. That is considered a "stuck" module.
|
||||||
|
bool
|
||||||
|
ircd::mapi::static_destruction;
|
||||||
|
|
||||||
|
bool
|
||||||
|
ircd::mods::unload(mod &mod)
|
||||||
|
{
|
||||||
|
if(!mod.handle.is_loaded())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(mods::unloading(mod.name()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Mark this module in the unloading state.
|
||||||
|
mod.unloading.emplace_front(&mod);
|
||||||
|
|
||||||
|
log::debug
|
||||||
|
{
|
||||||
|
log, "Attempting unload module '%s' @ `%s'",
|
||||||
|
mod.name(),
|
||||||
|
mod.location()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Call the user's unloading function here.
|
||||||
|
assert(mod.header);
|
||||||
|
assert(mod.header->meta);
|
||||||
|
if(mod.header->meta->fini)
|
||||||
|
mod.header->meta->fini();
|
||||||
|
|
||||||
|
// Save the children! dlclose() does not like to be called recursively during static
|
||||||
|
// destruction of a module. The mod ctor recorded all of the modules loaded while this
|
||||||
|
// module was loading so we can reverse the record and unload them here.
|
||||||
|
// Note: If the user loaded more modules from inside their module they will have to dtor them
|
||||||
|
// before 'static destruction' does. They can also do that by adding them to this vector.
|
||||||
|
std::for_each(rbegin(mod.children), rend(mod.children), []
|
||||||
|
(auto *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)
|
||||||
|
unload(*ptr);
|
||||||
|
});
|
||||||
|
|
||||||
|
log::debug
|
||||||
|
{
|
||||||
|
log, "Attempting static unload for '%s' @ `%s'",
|
||||||
|
mod.name(),
|
||||||
|
mod.location()
|
||||||
|
};
|
||||||
|
|
||||||
|
mapi::static_destruction = false;
|
||||||
|
mod.handle.unload();
|
||||||
|
assert(!mod.handle.is_loaded());
|
||||||
|
mod.loaded.erase(mod.name());
|
||||||
|
mod.unloading.remove(&mod);
|
||||||
|
if(!mapi::static_destruction)
|
||||||
|
{
|
||||||
|
handle_stuck(mod);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else log::info
|
||||||
|
{
|
||||||
|
log, "Unloaded '%s'", mod.name()
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::mods::handle_stuck(mod &mod)
|
||||||
|
{
|
||||||
|
log::critical
|
||||||
|
{
|
||||||
|
log, "Module \"%s\" is stuck and failing to unload.",
|
||||||
|
mod.name()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::mods::handle_ebadf(const string_view &what)
|
||||||
|
{
|
||||||
|
const auto pos(what.find("undefined symbol: "));
|
||||||
|
if(pos == std::string_view::npos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto msg(what.substr(pos));
|
||||||
|
const auto mangled(between(msg, ": ", ")"));
|
||||||
|
const auto demangled(demangle(mangled));
|
||||||
|
throw undefined_symbol
|
||||||
|
{
|
||||||
|
"undefined symbol '%s' (%s)",
|
||||||
|
demangled,
|
||||||
|
mangled
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// mods::mod::mod
|
// mods::mod::mod
|
||||||
//
|
//
|
||||||
|
@ -225,7 +317,7 @@ catch(const boost::system::system_error &e)
|
||||||
ircd::mods::mod::~mod()
|
ircd::mods::mod::~mod()
|
||||||
noexcept try
|
noexcept try
|
||||||
{
|
{
|
||||||
unload();
|
unload(*this);
|
||||||
}
|
}
|
||||||
catch(const std::exception &e)
|
catch(const std::exception &e)
|
||||||
{
|
{
|
||||||
|
@ -240,71 +332,6 @@ catch(const std::exception &e)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
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.
|
|
||||||
assert(header);
|
|
||||||
assert(header->meta);
|
|
||||||
if(header->meta->fini)
|
|
||||||
header->meta->fini();
|
|
||||||
|
|
||||||
// Save the children! dlclose() does not like to be called recursively during static
|
|
||||||
// destruction of a module. The mod ctor recorded all of the modules loaded while this
|
|
||||||
// module was loading so we can reverse the record and unload them here.
|
|
||||||
// Note: If the user loaded more modules from inside their module they will have to dtor them
|
|
||||||
// before 'static destruction' does. They can also do that by adding them to this vector.
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
|
|
||||||
log::debug
|
|
||||||
{
|
|
||||||
log, "Attempting static unload for '%s' @ `%s'",
|
|
||||||
name(),
|
|
||||||
location()
|
|
||||||
};
|
|
||||||
|
|
||||||
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()
|
|
||||||
};
|
|
||||||
else
|
|
||||||
log::info
|
|
||||||
{
|
|
||||||
log, "Unloaded '%s'", name()
|
|
||||||
};
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ircd::string_view &
|
ircd::string_view &
|
||||||
ircd::mods::mod::operator[](const string_view &key)
|
ircd::mods::mod::operator[](const string_view &key)
|
||||||
{
|
{
|
||||||
|
@ -320,24 +347,6 @@ const
|
||||||
return header->operator[](key);
|
return header->operator[](key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ircd::mods::handle_ebadf(const string_view &what)
|
|
||||||
{
|
|
||||||
const auto pos(what.find("undefined symbol: "));
|
|
||||||
if(pos == std::string_view::npos)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto msg(what.substr(pos));
|
|
||||||
const auto mangled(between(msg, ": ", ")"));
|
|
||||||
const auto demangled(demangle(mangled));
|
|
||||||
throw undefined_symbol
|
|
||||||
{
|
|
||||||
"undefined symbol '%s' (%s)",
|
|
||||||
demangled,
|
|
||||||
mangled
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// mods/mapi.h
|
// mods/mapi.h
|
||||||
|
|
11
ircd/mods.h
11
ircd/mods.h
|
@ -10,12 +10,16 @@
|
||||||
|
|
||||||
namespace ircd::mods
|
namespace ircd::mods
|
||||||
{
|
{
|
||||||
extern const std::string prefix;
|
struct mod;
|
||||||
extern const std::string suffix;
|
|
||||||
|
|
||||||
template<class R, class F> R info(const string_view &, F&& closure);
|
template<class R, class F> R info(const string_view &, F&& closure);
|
||||||
|
|
||||||
void handle_ebadf(const string_view &what);
|
void handle_ebadf(const string_view &what);
|
||||||
|
void handle_stuck(mod &);
|
||||||
|
bool unload(mod &);
|
||||||
|
|
||||||
|
extern const std::string prefix;
|
||||||
|
extern const std::string suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal module representation. This object closely wraps the dlopen()
|
/// Internal module representation. This object closely wraps the dlopen()
|
||||||
|
@ -45,6 +49,7 @@ struct ircd::mods::mod
|
||||||
const std::string _location;
|
const std::string _location;
|
||||||
mapi::header *header;
|
mapi::header *header;
|
||||||
|
|
||||||
|
public:
|
||||||
// Metadata
|
// Metadata
|
||||||
const string_view &operator[](const string_view &s) const;
|
const string_view &operator[](const string_view &s) const;
|
||||||
string_view &operator[](const string_view &s);
|
string_view &operator[](const string_view &s);
|
||||||
|
@ -55,8 +60,6 @@ struct ircd::mods::mod
|
||||||
auto &version() const { return header->version; }
|
auto &version() const { return header->version; }
|
||||||
auto &description() const { return (*this)["description"]; }
|
auto &description() const { return (*this)["description"]; }
|
||||||
|
|
||||||
bool unload();
|
|
||||||
|
|
||||||
explicit mod(std::string path, const load_mode::type &);
|
explicit mod(std::string path, const load_mode::type &);
|
||||||
|
|
||||||
mod(mod &&) = delete;
|
mod(mod &&) = delete;
|
||||||
|
|
Loading…
Reference in a new issue