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