Loading...
Searching...
No Matches
ml::PluginManager Class Reference

Loads, manages, and safely unloads dynamically linked plugins. More...

#include <PluginManager.h>

Inheritance diagram for ml::PluginManager:

Public Member Functions

 PluginManager (const std::string &pluginPath="")
 Construct a PluginManager with a default plugin search path.
std::vector< Plugin * > getPlugins ()
 Return all currently loaded plugins.
PluginloadPlugin (const std::string &path)
 Load a single plugin from a shared library path.
void loadPluginsFromDirectory (const std::string &dir)
 Load all plugin libraries found in a directory.
std::vector< PluginInfoscanPlugins (const std::string &dir)
 Probe a directory for plugins without keeping them loaded.
void unloadPlugin (Plugin *plugin)
 Unload a plugin and close its shared library.

Static Public Member Functions

static void clearPending ()
 Discard all pending operations without executing them.
static bool isBusy ()
 Return true if the manager is currently iterating.
static void processPending ()
 Flush all pending operations immediately.

Static Protected Member Functions

static void beginBusy ()
 Signal that iteration has begun.
static void deferOrExecute (std::function< void()> operation)
 Execute operation now if safe, otherwise queue it.
static void endBusy ()
 Signal that iteration has ended; flush pending operations.

Static Protected Attributes

static int busyDepth
 Iteration nesting depth. Operations are deferred while this is > 0.
static std::vector< std::function< void()> > pendingOperations
 Queue of operations pending until the current iteration completes.

Detailed Description

Loads, manages, and safely unloads dynamically linked plugins.

PluginManager handles the full plugin lifecycle:

  1. LoadloadPlugin opens a shared library, locates the createPlugin factory (exported by REGISTER_PLUGIN), constructs the plugin, and calls Plugin::onLoad().
  2. QuerygetPlugins returns all active plugins; type-safe interface queries should use Plugin::getIf<T>().
  3. ScanscanPlugins probes a directory for plugin libraries without keeping them loaded, returning PluginInfo records (including CPU-side thumbnail copies) for display in a carousel.
  4. UnloadunloadPlugin calls Plugin::onUnload(), force-unsubscribes all event and message subscriptions, deletes the plugin, and closes the library handle.

Deferred unloading

PluginManager inherits DeferredOperationsManager<PluginManager>. Calling unloadPlugin from within a message or event callback is safe — the actual unload is deferred until the current iteration completes, preventing use-after-free crashes.

Cross-platform support

The LOAD_LIB, GET_FUNC, and CLOSE_LIB macros abstract the platform differences between dlopen (macOS/Linux) and LoadLibraryA (Windows).

Typical use

// Load all plugins from a directory
pluginManager.loadPluginsFromDirectory("path/to/plugins");
// Query each plugin for an optional interface
for (auto* plugin : pluginManager.getPlugins()) {
if (auto* ui = plugin->getIf<ml::UIComponent>()) {
addComponent(*ui);
}
}
// Unload a specific plugin (safe even from a callback)
pluginManager.unloadPlugin(myPlugin);
See also
Plugin, PluginWith, PluginInfo, DeferredOperationsManager, REGISTER_PLUGIN

Definition at line 78 of file PluginManager.h.

Constructor & Destructor Documentation

◆ PluginManager()

ml::PluginManager::PluginManager ( const std::string & pluginPath = "")

Construct a PluginManager with a default plugin search path.

Parameters
pluginPathDefault directory used by loadPluginsFromDirectory when no path is provided. Can be overridden per-call.

Member Function Documentation

◆ beginBusy()

void ml::DeferredOperationsManager< PluginManager >::beginBusy ( )
staticprotectedinherited

Signal that iteration has begun.

Increments the busy-depth counter. Multiple nested calls are safe — operations remain deferred until the outermost endBusy() is reached.

◆ clearPending()

void ml::DeferredOperationsManager< PluginManager >::clearPending ( )
staticinherited

Discard all pending operations without executing them.

Use during application shutdown or full reset when executing the queued operations would be unsafe (e.g., the objects they reference have already been destroyed).

◆ deferOrExecute()

void ml::DeferredOperationsManager< PluginManager >::deferOrExecute ( std::function< void()> operation)
staticprotectedinherited

Execute operation now if safe, otherwise queue it.

If busyDepth > 0 the operation is appended to pendingOperations and will run when the current iteration completes. If the manager is idle the operation executes immediately.

Parameters
operationThe callable to execute or defer.

◆ endBusy()

void ml::DeferredOperationsManager< PluginManager >::endBusy ( )
staticprotectedinherited

Signal that iteration has ended; flush pending operations.

Decrements the busy-depth counter. When the counter reaches zero, all operations in pendingOperations are executed in FIFO order and the queue is cleared.

◆ getPlugins()

std::vector< Plugin * > ml::PluginManager::getPlugins ( )

Return all currently loaded plugins.

Processes any pending deferred unloads before returning, so the vector is always consistent with the current manager state.

Returns
Vector of pointers to all active Plugin instances. Do not store these pointers across calls to unloadPlugin.

◆ isBusy()

bool ml::DeferredOperationsManager< PluginManager >::isBusy ( )
staticinherited

Return true if the manager is currently iterating.

Can be used by external code that needs to know whether a destructive operation will be deferred.

Returns
true when busyDepth > 0.

◆ loadPlugin()

Plugin * ml::PluginManager::loadPlugin ( const std::string & path)

Load a single plugin from a shared library path.

Opens the library at path, calls the createPlugin factory function (exported by REGISTER_PLUGIN), and calls Plugin::onLoad() on the result. Returns nullptr if the library cannot be opened or the factory symbol is not found.

Parameters
pathAbsolute or relative path to the plugin shared library (.dylib, .so, or .dll).
Returns
Pointer to the loaded plugin, or nullptr on failure.

◆ loadPluginsFromDirectory()

void ml::PluginManager::loadPluginsFromDirectory ( const std::string & dir)

Load all plugin libraries found in a directory.

Scans dir for files with the platform plugin extension and calls loadPlugin for each one. Silently skips files that fail to load.

Parameters
dirPath to the directory to scan.

◆ processPending()

void ml::DeferredOperationsManager< PluginManager >::processPending ( )
staticinherited

Flush all pending operations immediately.

Normally called automatically by endBusy(). Provided as a public escape hatch for unusual teardown sequences.

Warning
Calling this while isBusy() is true can cause iterator invalidation in the currently running loop. Only call manually when you are certain it is safe.

◆ scanPlugins()

std::vector< PluginInfo > ml::PluginManager::scanPlugins ( const std::string & dir)

Probe a directory for plugins without keeping them loaded.

Temporarily loads each plugin library, reads its name, version, and thumbnail, copies the thumbnail texture to CPU memory, then immediately unloads the library. The resulting PluginInfo records contain everything needed to populate a game-selection carousel.

Parameters
dirPath to the directory to scan.
Returns
Vector of PluginInfo records, one per successfully probed plugin.

◆ unloadPlugin()

void ml::PluginManager::unloadPlugin ( Plugin * plugin)

Unload a plugin and close its shared library.

Queues the following sequence for deferred execution:

  1. EventsManager::forceUnsubscribeAll and MessageManager::forceUnsubscribeAll — removes all subscriptions immediately so no callbacks fire after the plugin is gone.
  2. Plugin::onUnload() — gives the plugin a chance to clean up.
  3. delete plugin — destroys the plugin object.
  4. CLOSE_LIB(handle) — unloads the shared library.

If called from within an event or message callback, all of the above is deferred until the active iteration completes.

Parameters
pluginPointer to the plugin to unload. Must have been returned by loadPlugin or getPlugins. Passing nullptr is safe.

Member Data Documentation

◆ busyDepth

int ml::DeferredOperationsManager< PluginManager >::busyDepth
inlinestaticprotectedinherited

Iteration nesting depth. Operations are deferred while this is > 0.

Definition at line 69 of file DeferredOperationsManager.h.

◆ pendingOperations

std::vector<std::function<void()> > ml::DeferredOperationsManager< PluginManager >::pendingOperations
inlinestaticprotectedinherited

Queue of operations pending until the current iteration completes.

Definition at line 72 of file DeferredOperationsManager.h.


The documentation for this class was generated from the following file: