src/spbot/module.h
branchnew-lib-errors
changeset 217 7728d6ec3abf
parent 134 978041c1c04d
child 218 5229a5d098b2
equal deleted inserted replaced
216:a10ba529ae39 217:7728d6ec3abf
       
     1 #ifndef MODULE_H
       
     2 #define MODULE_H
       
     3 
       
     4 /**
       
     5  * @file
       
     6  *
       
     7  * Dynamically loadable modules for use with nexus.
       
     8  *
       
     9  * The modules are loaded using dlopen(), and hence should be standard dynamic libraries. Modules are then "loaded" by
       
    10  * resolving a `struct module_funcs` symbol called "<modname>_funcs", and then using the init func to construct a
       
    11  * "context", which is then further manipulated by various other module functions.
       
    12  *
       
    13  * Modules are also reference counted, mainly for implementing module_unload(). When a module is first loaded, it has
       
    14  * a reference count of one - the entry in struct modules. Later, modules can be referenced using module_get(), and
       
    15  * returned with module_put() once done. The module should never be destroyed during its lifetime, until a
       
    16  * module_unload() occurs. At this point, the module is removed from the modules_list, and the one reference is
       
    17  * 'passed on' to the module itself. Once it has finished unloading, it can call module_unloaded() on the reference it was
       
    18  * given by module_desc::unload, which may then result in a deferred module_destroy().
       
    19  *
       
    20  * Module destroying itself is an interesting issue, since modules effectively need to be able to destroy themselves
       
    21  * (as they must be able to perform cleanup, and then notify completion from inside an event loop callback). This means
       
    22  * that they cannot directly execute a module_destroy() on themselves - if we call dlclose() with dlopen-mapped code
       
    23  * pages on the stack, a segfault ensues. Hence, they must call module_unloaded() on themselves, which then executes a
       
    24  * deferred module_destroy() if there are no references left. Otherwise, the module should be safe from external code,
       
    25  * as module_put() should never cause a module to be destroyed before module_unloaded() is executed, due to the primary
       
    26  * reference.
       
    27  *
       
    28  * Ugh, it's compliated, I need to write a clearer explenation once it's implemented :)
       
    29  */
       
    30 
       
    31 struct module;
       
    32 
       
    33 #include "nexus.h"
       
    34 #include "config.h"
       
    35 #include <lib/error.h>
       
    36 
       
    37 #include <sys/queue.h>
       
    38 #include <stdbool.h>
       
    39 
       
    40 enum module_error_code {
       
    41     ERR_MODULE_NONE, 
       
    42     ERR_MODULE_NAME,        ///< invalid module_info.name
       
    43     ERR_MODULE_DUP,         ///< module already opened
       
    44     ERR_MODULE_PATH,        ///< resolving the path failed
       
    45     ERR_MODULE_OPEN,        ///< dlopen() failed
       
    46     ERR_MODULE_SYM,         ///< invalid symbol
       
    47     ERR_MODULE_INIT_FUNC,   ///< invalid module_init_func_t
       
    48     ERR_MODULE_CONF,        ///< value error in configuration data
       
    49     ERR_MODULE_STATE,       ///< module in wrong state for operation
       
    50 };
       
    51 
       
    52 const struct error_list module_errors;
       
    53 
       
    54 /**
       
    55  * Information required to load/identify a module.
       
    56  */
       
    57 struct module_info {
       
    58     /** Human-readable name */
       
    59     const char *name;
       
    60     
       
    61     /** Filesystem path to the .so */
       
    62     const char *path;
       
    63 };
       
    64 
       
    65 /**
       
    66  * A table of (function/other) pointers defining a module's behaviour. This is dynamically resolved from the module DSO
       
    67  * using the "<mod_name>_module" symbol.
       
    68  */
       
    69 struct module_desc {
       
    70     /**
       
    71      * Initialize the module, returning an opaque context pointer that is stored in the module state, and supplied for
       
    72      * subsequent calls. The supplied nexus arg can be used to access the global state.
       
    73      *
       
    74      * Implementing this is mandatory.
       
    75      *
       
    76      * @param nexus a pointer to the nexus struct containing the global state
       
    77      * @param ctx_ptr the context pointer should be returned via this
       
    78      * @param err returned error info
       
    79      */
       
    80     err_t (*init) (struct nexus *nexus, void **ctx_ptr, error_t *err);
       
    81 
       
    82     /**
       
    83      * A module may define a set of available configuration parameters for use by module_conf, by setting this to an
       
    84      * array of config_option's.
       
    85      *
       
    86      * The handler functions will recieve the module's context pointer as their ctx argument.
       
    87      *
       
    88      * Implementing this is optional, but recommended.
       
    89      */
       
    90     const struct config_option *config_options;
       
    91 
       
    92     /**
       
    93      * Unload the module, removing all handlers/callbacks added to the nexus' irc_client. This does not have to act
       
    94      * immediately, and will still have access to all irc_* resources it had earlier, and may perform I/O to unload
       
    95      * cleanly. But the unloading should complete reasonably quickly, after which all event handlers added by the
       
    96      * module to the nexus' ev_base should have been removed, and resources released.
       
    97      *
       
    98      * The module given as an argument is the module itself - which has been removed from the modules_list - the
       
    99      * primary reference is passed on to the module. Once the module has finished unloading, it may call module_put(),
       
   100      * which may then call module_destroy(), if no other references were left.
       
   101      *
       
   102      * If the unload operation fails (returns an error code), then the module is considered as unloaded (as if
       
   103      * module_unloaded() was called - don't call this if you return an error).
       
   104      *
       
   105      * Implementing this is optional, if all of this can be implemented in destroy.
       
   106      *
       
   107      * @param ctx the module's context pointer as returned by init
       
   108      * @param module the hanging module reference, that must be passed to module_unloaded()
       
   109      * @return error code
       
   110      */
       
   111     err_t (*unload) (void *ctx, struct module *module);
       
   112 
       
   113     /**
       
   114      * Destroy the module now. No later chances, the module's code will be unloaded directly after this, which means
       
   115      * that attempts to execute the module's code (even on the stack...) after this will segfault.
       
   116      *
       
   117      * The module code /should/ garuntee that this is never called from *inside* the module code - calls to
       
   118      * module_destroy() will be deferred via the event loop if needed.
       
   119      *
       
   120      * Implementing this is optional.
       
   121      */
       
   122     void (*destroy) (void *ctx);
       
   123 };
       
   124 
       
   125 /**
       
   126  * A loaded module.
       
   127  */
       
   128 struct module {
       
   129     /** The identifying info for the module */
       
   130     struct module_info info;
       
   131 
       
   132     /** Possible dynamically allocated path */
       
   133     char *path_buf;
       
   134 
       
   135     /** The dlopen handle */
       
   136     void *handle;
       
   137 
       
   138     /** The module entry point */
       
   139     struct module_desc *desc;
       
   140 
       
   141     /** The module context object */
       
   142     void *ctx;
       
   143 
       
   144     /** Reference back to modules struct used to load this module */
       
   145     struct modules *modules;
       
   146 
       
   147     /** Reference count for destroy() */
       
   148     size_t refcount;
       
   149     
       
   150     /** Is the module currently being unloaded? */
       
   151     bool unloading;
       
   152 
       
   153     /** Our entry in the list of modules */
       
   154     TAILQ_ENTRY(module) modules_list;
       
   155 };
       
   156 
       
   157 /**
       
   158  * A set of loaded modules, and functionality to load more
       
   159  */
       
   160 struct modules {
       
   161     /** The nexus in use */
       
   162     struct nexus *nexus;
       
   163 
       
   164     /** Module search path */
       
   165     const char *path;
       
   166 
       
   167     /** List of loaded modules */
       
   168     TAILQ_HEAD(module_ctx_modules, module) list;
       
   169 };
       
   170 
       
   171 
       
   172 /**
       
   173  * Maximum length of a module name
       
   174  */
       
   175 #define MODULE_NAME_MAX 24
       
   176 
       
   177 /**
       
   178  * Maximum length of module symbol suffix
       
   179  */
       
   180 #define MODULE_SUFFIX_MAX 16
       
   181 
       
   182 /**
       
   183  * Maximum length of symbol name name, including terminating NUL
       
   184  */
       
   185 #define MODULE_SYMBOL_MAX (MODULE_NAME_MAX + 1 + MODULE_SUFFIX_MAX + 1)
       
   186 
       
   187 /**
       
   188  * Create a new modules state
       
   189  */
       
   190 err_t modules_create (struct modules **modules_ptr, struct nexus *nexus);
       
   191 
       
   192 /**
       
   193  * Set a search path for finding modules by name. The given string won't be copied.
       
   194  *
       
   195  * A module called "<name>" will be searched for at "<path>/mod_<name>.so"
       
   196  *
       
   197  * If path is NULL, this doesn't change anything. This returns the old path, which may be NULL.
       
   198  *
       
   199  * @param modules the modules state
       
   200  * @param path the new search path, or NULL to just get the old one
       
   201  * @return the old search path
       
   202  */
       
   203 const char* modules_path (struct modules *modules, const char *path);
       
   204 
       
   205 /**
       
   206  * Get a reference to the module, which must be returned using module_put
       
   207  *
       
   208  * @param modules the modules state
       
   209  * @param name the module name to get
       
   210  * @return the module struct, or NULL if not found
       
   211  */
       
   212 struct module* modules_get (struct modules *modules, const char *name);
       
   213 
       
   214 /**
       
   215  * Unload all modules, this just calls module_unload for each module, logging errors as warnings.
       
   216  */
       
   217 err_t modules_unload (struct modules *modules);
       
   218 
       
   219 /**
       
   220  * Destroy all modules immediately.
       
   221  */
       
   222 void modules_destroy (struct modules *modules);
       
   223 
       
   224 
       
   225 
       
   226 /*******************************************/
       
   227 
       
   228 
       
   229 /**
       
   230  * Return a module's name
       
   231  */
       
   232 const char* module_name (struct module *module);
       
   233 
       
   234 /**
       
   235  * Load a new module, as named by info.
       
   236  *
       
   237  * If info->path is not given, the module will be searched for using the path set by modules_path().
       
   238  *
       
   239  * If module_ptr is given, a reference (that must be module_put'd) is returned, that must be returned using 
       
   240  * module_put().
       
   241  *
       
   242  * @param modules the module-loading context
       
   243  * @param module_ptr retuturned new module struct, as a new reference, if not NULL.
       
   244  * @param info the info required to identify and load the module
       
   245  * @param err returned error info
       
   246  */
       
   247 err_t module_load (struct modules *modules, struct module **module_ptr, const struct module_info *info, error_t *err);
       
   248 
       
   249 /**
       
   250  * Return a module retrieved using module_get
       
   251  */
       
   252 void module_put (struct module *module);
       
   253 
       
   254 /**
       
   255  * Look up a module configuration option by name
       
   256  */
       
   257 const struct config_option* module_conf_lookup (struct module *module, const char *name, error_t *err);
       
   258 
       
   259 /**
       
   260  * Apply a module configuration option using a structured value
       
   261  */
       
   262 err_t module_conf (struct module *module, const struct config_option *opt, const struct config_value *value, error_t *err);
       
   263 
       
   264 /**
       
   265  * Set a module configuration option using a raw value
       
   266  */
       
   267 err_t module_conf_raw (struct module *module, const char *name, char *value, error_t *err);
       
   268 
       
   269 /**
       
   270  * Unload a module. This removes the module from the modules_list, marks it as unloading, and then calls the module's
       
   271  * \p unload function, passing it the primary reference. The module's unload code will then go about shutting down the
       
   272  * module, and once that is done, it may module_put() the primary reference, which may then lead to module_destroy().
       
   273  *
       
   274  * This returns ERR_MODULE_STATE if the module is already being unloaded, or other errors from the module's own unload
       
   275  * functionality.
       
   276  */
       
   277 err_t module_unload (struct module *module);
       
   278 
       
   279 /**
       
   280  * Used by a module itself to indicate that an module_desc::unload() operation has completed. This will execute a
       
   281  * deferred module_destroy() if there are no more references left on the module.
       
   282  *
       
   283  * Note: this is not intended to be called from outside the given module itself...
       
   284  */
       
   285 void module_unloaded (struct module *module);
       
   286 
       
   287 /**
       
   288  * Destroy a module, releasing as many resources as possible, but not stopping for errors.
       
   289  *
       
   290  * This does not enforce the correct refcount - 'tis the caller's responsibility. Prints out a warning if
       
   291  * refcount > 0.
       
   292  */
       
   293 void module_destroy (struct module *module);
       
   294 
       
   295 #endif