fix refcount semantics for module_load and have module_unload call module_unloaded on module_desc::unload errors
authorTero Marttila <terom@fixme.fi>
Thu, 02 Apr 2009 02:55:32 +0300
changeset 111 5a1ebffca81a
parent 110 43e9a7984955
child 112 10ada0d1c7d7
fix refcount semantics for module_load and have module_unload call module_unloaded on module_desc::unload errors
src/module.c
src/module.h
src/nexus.c
--- a/src/module.c	Thu Apr 02 02:25:35 2009 +0300
+++ b/src/module.c	Thu Apr 02 02:55:32 2009 +0300
@@ -238,8 +238,10 @@
         goto error;
 
     // ok
-    if (module_ptr)
+    if (module_ptr) {
+        module->refcount++;
         *module_ptr = module;
+    }
 
     return SUCCESS;
 
@@ -304,8 +306,9 @@
 {
     err_t err;
     
-    // sanity-check
-    assert(!module->unloading);
+    // wrong state
+    if (module->unloading)
+        return ERR_MODULE_STATE;
 
     // remove from modules list
     TAILQ_REMOVE(&module->modules->list, module, modules_list);
@@ -315,8 +318,12 @@
 
     // invoke the unload func, passing it our reference
     // note that the module might not exist anymore after calling this
-    if ((err = module->desc->unload(module->ctx, module)))
+    if ((err = module->desc->unload(module->ctx, module))) {
+        // mark it as "unloaded"
+        module_unloaded(module);
+
         return err;
+    }
 
     // ok
     return SUCCESS;
@@ -364,7 +371,7 @@
         TAILQ_REMOVE(&module->modules->list, module, modules_list);
 
     // run the destroy hook
-    if (module->desc->destroy)
+    if (module->desc && module->desc->destroy)
         module->desc->destroy(module->ctx);
 
     // unload the dl handle
--- a/src/module.h	Thu Apr 02 02:25:35 2009 +0300
+++ b/src/module.h	Thu Apr 02 02:55:32 2009 +0300
@@ -85,9 +85,14 @@
      * 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 mandatory.
      *
      * @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);
 
@@ -162,6 +167,7 @@
     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
 };
 
 
@@ -232,10 +238,13 @@
  *
  * 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 return the new module via this, if not NULL
+ * @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 return error info
+ * @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);
 
@@ -263,6 +272,9 @@
  * 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);
 
--- a/src/nexus.c	Thu Apr 02 02:25:35 2009 +0300
+++ b/src/nexus.c	Thu Apr 02 02:55:32 2009 +0300
@@ -216,7 +216,6 @@
         .name       = NULL,
         .path       = NULL,
     };
-    struct module *module;
 
     // parse the required fields
     if ((info.name = strsep(&opt, ":")) == NULL)
@@ -232,7 +231,7 @@
     // load it
     log_info("loading module '%s' from path '%s'", info.name, info.path);
 
-    if (module_load(nexus->modules, &module, &info, err))
+    if (module_load(nexus->modules, NULL, &info, err))
         return ERROR_CODE(err);
 
     // ok