src/module.h
branchnew-lib-errors
changeset 217 7728d6ec3abf
parent 216 a10ba529ae39
child 218 5229a5d098b2
--- 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