--- a/src/module.h Wed May 27 23:07:00 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,297 +0,0 @@
-#ifndef MODULE_H
-#define MODULE_H
-
-/**
- * @file
- *
- * Dynamically loadable modules for use with nexus.
- *
- * The modules are loaded using dlopen(), and hence should be standard dynamic libraries. Modules are then "loaded" by
- * resolving a `struct module_funcs` symbol called "<modname>_funcs", and then using the init func to construct a
- * "context", which is then further manipulated by various other module functions.
- *
- * Modules are also reference counted, mainly for implementing module_unload(). When a module is first loaded, it has
- * a reference count of one - the entry in struct modules. Later, modules can be referenced using module_get(), and
- * returned with module_put() once done. The module should never be destroyed during its lifetime, until a
- * module_unload() occurs. At this point, the module is removed from the modules_list, and the one reference is
- * 'passed on' to the module itself. Once it has finished unloading, it can call module_unloaded() on the reference it was
- * given by module_desc::unload, which may then result in a deferred module_destroy().
- *
- * Module destroying itself is an interesting issue, since modules effectively need to be able to destroy themselves
- * (as they must be able to perform cleanup, and then notify completion from inside an event loop callback). This means
- * that they cannot directly execute a module_destroy() on themselves - if we call dlclose() with dlopen-mapped code
- * pages on the stack, a segfault ensues. Hence, they must call module_unloaded() on themselves, which then executes a
- * deferred module_destroy() if there are no references left. Otherwise, the module should be safe from external code,
- * as module_put() should never cause a module to be destroyed before module_unloaded() is executed, due to the primary
- * reference.
- *
- * Ugh, it's compliated, I need to write a clearer explenation once it's implemented :)
- */
-
-struct module;
-
-#include "nexus.h"
-#include "config.h"
-#include "error.h"
-
-#include <sys/queue.h>
-#include <stdbool.h>
-
-/**
- * Information required to load/identify a module.
- */
-struct module_info {
- /** Human-readable name */
- const char *name;
-
- /** Filesystem path to the .so */
- const char *path;
-};
-
-/**
- * A table of (function/other) pointers defining a module's behaviour. This is dynamically resolved from the module DSO
- * using the "<mod_name>_module" symbol.
- */
-struct module_desc {
- /**
- * Initialize the module, returning an opaque context pointer that is stored in the module state, and supplied for
- * subsequent calls. The supplied nexus arg can be used to access the global state.
- *
- * Implementing this is mandatory.
- *
- * @param nexus a pointer to the nexus struct containing the global state
- * @param ctx_ptr the context pointer should be returned via this
- * @param err returned error info
- */
- err_t (*init) (struct nexus *nexus, void **ctx_ptr, struct error_info *err);
-
- /**
- * A module may define a set of available configuration parameters for use by module_conf, by setting this to an
- * array of config_option's.
- *
- * The handler functions will recieve the module's context pointer as their ctx argument.
- *
- * Implementing this is optional, but recommended.
- */
- const struct config_option *config_options;
-
- /**
- * Unload the module, removing all handlers/callbacks added to the nexus' irc_client. This does not have to act
- * immediately, and will still have access to all irc_* resources it had earlier, and may perform I/O to unload
- * cleanly. But the unloading should complete reasonably quickly, after which all event handlers added by the
- * module to the nexus' ev_base should have been removed, and resources released.
- *
- * The module given as an argument is the module itself - which has been removed from the modules_list - the
- * primary reference is passed on to the module. Once the module has finished unloading, it may call module_put(),
- * which may then call module_destroy(), if no other references were left.
- *
- * If the unload operation fails (returns an error code), then the module is considered as unloaded (as if
- * module_unloaded() was called - don't call this if you return an error).
- *
- * Implementing this is optional, if all of this can be implemented in destroy.
- *
- * @param ctx the module's context pointer as returned by init
- * @param module the hanging module reference, that must be passed to module_unloaded()
- * @return error code
- */
- err_t (*unload) (void *ctx, struct module *module);
-
- /**
- * Destroy the module now. No later chances, the module's code will be unloaded directly after this, which means
- * that attempts to execute the module's code (even on the stack...) after this will segfault.
- *
- * The module code /should/ garuntee that this is never called from *inside* the module code - calls to
- * module_destroy() will be deferred via the event loop if needed.
- *
- * Implementing this is optional.
- */
- void (*destroy) (void *ctx);
-};
-
-/**
- * A loaded module.
- */
-struct module {
- /** The identifying info for the module */
- struct module_info info;
-
- /** Possible dynamically allocated path */
- char *path_buf;
-
- /** The dlopen handle */
- void *handle;
-
- /** The module entry point */
- struct module_desc *desc;
-
- /** The module context object */
- void *ctx;
-
- /** Reference back to modules struct used to load this module */
- struct modules *modules;
-
- /** Reference count for destroy() */
- size_t refcount;
-
- /** Is the module currently being unloaded? */
- bool unloading;
-
- /** Our entry in the list of modules */
- TAILQ_ENTRY(module) modules_list;
-};
-
-/**
- * A set of loaded modules, and functionality to load more
- */
-struct modules {
- /** The nexus in use */
- struct nexus *nexus;
-
- /** Module search path */
- const char *path;
-
- /** List of loaded modules */
- TAILQ_HEAD(module_ctx_modules, module) list;
-};
-
-/**
- * Possible error codes
- */
-enum module_error_code {
- _ERR_MODULE_BEGIN = _ERR_MODULE,
-
- ERR_MODULE_NAME, ///< invalid module_info.name
- ERR_MODULE_DUP, ///< module already opened
- ERR_MODULE_PATH, ///< resolving the path failed
- ERR_MODULE_OPEN, ///< dlopen() failed
- ERR_MODULE_SYM, ///< invalid symbol
- ERR_MODULE_INIT_FUNC, ///< invalid module_init_func_t
- ERR_MODULE_CONF, ///< value error in configuration data
- ERR_MODULE_STATE, ///< module in wrong state for operation
-};
-
-
-/**
- * Maximum length of a module name
- */
-#define MODULE_NAME_MAX 24
-
-/**
- * Maximum length of module symbol suffix
- */
-#define MODULE_SUFFIX_MAX 16
-
-/**
- * Maximum length of symbol name name, including terminating NUL
- */
-#define MODULE_SYMBOL_MAX (MODULE_NAME_MAX + 1 + MODULE_SUFFIX_MAX + 1)
-
-/**
- * Create a new modules state
- */
-err_t modules_create (struct modules **modules_ptr, struct nexus *nexus);
-
-/**
- * Set a search path for finding modules by name. The given string won't be copied.
- *
- * A module called "<name>" will be searched for at "<path>/mod_<name>.so"
- *
- * If path is NULL, this doesn't change anything. This returns the old path, which may be NULL.
- *
- * @param modules the modules state
- * @param path the new search path, or NULL to just get the old one
- * @return the old search path
- */
-const char* modules_path (struct modules *modules, const char *path);
-
-/**
- * Get a reference to the module, which must be returned using module_put
- *
- * @param modules the modules state
- * @param name the module name to get
- * @return the module struct, or NULL if not found
- */
-struct module* modules_get (struct modules *modules, const char *name);
-
-/**
- * Unload all modules, this just calls module_unload for each module, logging errors as warnings.
- */
-err_t modules_unload (struct modules *modules);
-
-/**
- * Destroy all modules immediately.
- */
-void modules_destroy (struct modules *modules);
-
-
-
-/*******************************************/
-
-
-/**
- * Return a module's name
- */
-const char* module_name (struct module *module);
-
-/**
- * Load a new module, as named by info.
- *
- * If info->path is not given, the module will be searched for using the path set by modules_path().
- *
- * If module_ptr is given, a reference (that must be module_put'd) is returned, that must be returned using
- * module_put().
- *
- * @param modules the module-loading context
- * @param module_ptr retuturned new module struct, as a new reference, if not NULL.
- * @param info the info required to identify and load the module
- * @param err returned error info
- */
-err_t module_load (struct modules *modules, struct module **module_ptr, const struct module_info *info, struct error_info *err);
-
-/**
- * Return a module retrieved using module_get
- */
-void module_put (struct module *module);
-
-/**
- * Look up a module configuration option by name
- */
-const struct config_option* module_conf_lookup (struct module *module, const char *name, struct error_info *err);
-
-/**
- * Apply a module configuration option using a structured value
- */
-err_t module_conf (struct module *module, const struct config_option *opt, const struct config_value *value, struct error_info *err);
-
-/**
- * Set a module configuration option using a raw value
- */
-err_t module_conf_raw (struct module *module, const char *name, char *value, struct error_info *err);
-
-/**
- * Unload a module. This removes the module from the modules_list, marks it as unloading, and then calls the module's
- * \p unload function, passing it the primary reference. The module's unload code will then go about shutting down the
- * module, and once that is done, it may module_put() the primary reference, which may then lead to module_destroy().
- *
- * This returns ERR_MODULE_STATE if the module is already being unloaded, or other errors from the module's own unload
- * functionality.
- */
-err_t module_unload (struct module *module);
-
-/**
- * Used by a module itself to indicate that an module_desc::unload() operation has completed. This will execute a
- * deferred module_destroy() if there are no more references left on the module.
- *
- * Note: this is not intended to be called from outside the given module itself...
- */
-void module_unloaded (struct module *module);
-
-/**
- * Destroy a module, releasing as many resources as possible, but not stopping for errors.
- *
- * This does not enforce the correct refcount - 'tis the caller's responsibility. Prints out a warning if
- * refcount > 0.
- */
-void module_destroy (struct module *module);
-
-#endif