version bump to 1.1.8, binary age 0, interface age 0.
[platform/upstream/glib.git] / gmodule / gmodule.c
index a883ace..99f38a6 100644 (file)
@@ -8,7 +8,7 @@
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/* 
+ * MT safe
+ */
+
 #include       "gmodule.h"
 #include       "gmoduleconf.h"
 #include       <errno.h>
 
 /* We maintain a list of modules, so we can reference count them.
  * That's needed because some platforms don't support refernce counts on
- * modules (http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html).
+ * modules e.g. the shl_* implementation of HP-UX
+ * (http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html).
  * Also, the module for the program itself is kept seperatedly for
- * faster access.
+ * faster access and because it has special semantics.
  */
 
 
@@ -35,8 +41,9 @@ struct _GModule
 {
   gchar        *file_name;
   gpointer handle;
-  guint ref_count;
-  GModuleDeInit de_init;
+  guint ref_count : 31;
+  guint is_resident : 1;
+  GModuleUnload unload;
   GModule *next;
 };
 
@@ -44,20 +51,24 @@ struct _GModule
 /* --- prototypes --- */
 static gpointer                _g_module_open          (const gchar    *file_name,
                                                 gboolean        bind_lazy);
-static void            _g_module_close         (gpointer       *handle_p,
+static void            _g_module_close         (gpointer        handle,
                                                 gboolean        is_unref);
 static gpointer                _g_module_self          (void);
-static gpointer                _g_module_symbol        (gpointer       *handle_p,
+static gpointer                _g_module_symbol        (gpointer        handle,
                                                 const gchar    *symbol_name);
+static gchar*          _g_module_build_path    (const gchar    *directory,
+                                                const gchar    *module_name);
 static inline void     g_module_set_error      (const gchar    *error);
 static inline GModule* g_module_find_by_handle (gpointer        handle);
 static inline GModule* g_module_find_by_name   (const gchar    *name);
 
 
 /* --- variables --- */
-static GModule *modules = NULL;
-static GModule *main_module = NULL;
-static gchar   *module_error = NULL;
+G_LOCK_DECLARE_STATIC (GModule);
+const char           *g_log_domain_gmodule = "GModule";
+static GModule      *modules = NULL;
+static GModule      *main_module = NULL;
+static GStaticPrivate module_error_private = G_STATIC_PRIVATE_INIT;
 
 
 /* --- inline functions --- */
@@ -65,30 +76,45 @@ static inline GModule*
 g_module_find_by_handle (gpointer handle)
 {
   GModule *module;
-
+  GModule *retval = NULL;
+  
+  G_LOCK (GModule);
   if (main_module && main_module->handle == handle)
-    return main_module;
+    retval = main_module;
+  else
+    for (module = modules; module; module = module->next)
+      if (handle == module->handle)
+       {
+         retval = module;
+         break;
+       }
+  G_UNLOCK (GModule);
 
-  for (module = modules; module; module = module->next)
-    if (handle == module->handle)
-      return module;
-  return NULL;
+  return retval;
 }
 
 static inline GModule*
 g_module_find_by_name (const gchar *name)
 {
   GModule *module;
-
+  GModule *retval = NULL;
+  
+  G_LOCK (GModule);
   for (module = modules; module; module = module->next)
     if (strcmp (name, module->file_name) == 0)
-      return module;
-  return NULL;
+       {
+         retval = module;
+         break;
+       }
+  G_UNLOCK (GModule);
+
+  return retval;
 }
 
 static inline void
 g_module_set_error (const gchar *error)
 {
+  gchar* module_error = g_static_private_get (&module_error_private);
   if (module_error)
     g_free (module_error);
   if (error)
@@ -96,6 +122,7 @@ g_module_set_error (const gchar *error)
   else
     module_error = NULL;
   errno = 0;
+  g_static_private_set (&module_error_private, module_error, g_free);
 }
 
 
@@ -105,18 +132,58 @@ g_module_set_error (const gchar *error)
 #include "gmodule-dl.c"
 #elif  (G_MODULE_IMPL == G_MODULE_IMPL_DLD)
 #include "gmodule-dld.c"
+#elif  (G_MODULE_IMPL == G_MODULE_IMPL_WIN32)
+#include "gmodule-win32.c"
 #else
 #undef CHECK_ERROR
 #define        CHECK_ERROR(rv) { g_module_set_error ("unsupported"); return rv; }
+static gpointer
+_g_module_open (const gchar    *file_name,
+               gboolean         bind_lazy)
+{
+  return NULL;
+}
+static void
+_g_module_close        (gpointer        handle,
+                gboolean        is_unref)
+{
+}
+static gpointer
+_g_module_self (void)
+{
+  return NULL;
+}
+static gpointer
+_g_module_symbol (gpointer      handle,
+                 const gchar   *symbol_name)
+{
+  return NULL;
+}
+static gchar*
+_g_module_build_path (const gchar *directory,
+                     const gchar *module_name)
+{
+  return NULL;
+}
 #endif /* no implementation */
 
+#if defined (NATIVE_WIN32) && defined (__LCC__)
+int __stdcall 
+LibMain (void         *hinstDll,
+        unsigned long dwReason,
+        void         *reserved)
+{
+  return 1;
+}
+#endif /* NATIVE_WIN32 && __LCC__ */
+
 
 /* --- functions --- */
 gboolean
 g_module_supported (void)
 {
   CHECK_ERROR (FALSE);
-
+  
   return TRUE;
 }
 
@@ -126,11 +193,12 @@ g_module_open (const gchar    *file_name,
 {
   GModule *module;
   gpointer handle;
-
+  
   CHECK_ERROR (NULL);
-
+  
   if (!file_name)
-    {
+    {      
+      G_LOCK (GModule);
       if (!main_module)
        {
          handle = _g_module_self ();
@@ -140,95 +208,112 @@ g_module_open (const gchar    *file_name,
              main_module->file_name = NULL;
              main_module->handle = handle;
              main_module->ref_count = 1;
-             main_module->de_init = NULL;
+             main_module->is_resident = TRUE;
+             main_module->unload = NULL;
              main_module->next = NULL;
            }
        }
+      G_UNLOCK (GModule);
 
       return main_module;
     }
-
+  
   /* we first search the module list by name */
   module = g_module_find_by_name (file_name);
   if (module)
     {
       module->ref_count++;
-
+      
       return module;
     }
-
+  
   /* open the module */
   handle = _g_module_open (file_name, (flags & G_MODULE_BIND_LAZY) != 0);
   if (handle)
     {
       gchar *saved_error;
       GModuleCheckInit check_init;
-      gboolean check_failed = FALSE;
-
+      const gchar *check_failed = NULL;
+      
       /* search the module list by handle, since file names are not unique */
       module = g_module_find_by_handle (handle);
       if (module)
        {
-         _g_module_close (&module->handle, TRUE);
+         _g_module_close (module->handle, TRUE);
          module->ref_count++;
          g_module_set_error (NULL);
-
+         
          return module;
        }
-
-      saved_error = module_error;
-      module_error = NULL;
+      
+      saved_error = g_module_error();
+      g_static_private_set (&module_error_private, NULL, NULL);
       g_module_set_error (NULL);
-
+      
       module = g_new (GModule, 1);
       module->file_name = g_strdup (file_name);
       module->handle = handle;
       module->ref_count = 1;
-      module->de_init = NULL;
+      module->is_resident = FALSE;
+      module->unload = NULL;
+      G_LOCK (GModule);
       module->next = modules;
       modules = module;
-
+      G_UNLOCK (GModule);
+      
       /* check initialization */
-      if (g_module_symbol (module, "g_module_check_init", &check_init))
+      if (g_module_symbol (module, "g_module_check_init", (gpointer) &check_init))
        check_failed = check_init (module);
-
-      /* we don't call de_init() if the initialization check failed. */
+      
+      /* we don't call unload() if the initialization check failed. */
       if (!check_failed)
-       g_module_symbol (module, "g_module_de_init", &module->de_init);
-
+       g_module_symbol (module, "g_module_unload", (gpointer) &module->unload);
+      
       if (check_failed)
        {
+         gchar *error;
+
+         error = g_strconcat ("GModule initialization check failed: ", check_failed, NULL);
          g_module_close (module);
          module = NULL;
-         g_module_set_error ("GModule initialization check failed");
+         g_module_set_error (error);
+         g_free (error);
        }
       else
        g_module_set_error (saved_error);
       g_free (saved_error);
     }
-
+  
   return module;
 }
 
 gboolean
-g_module_close (GModule        *module)
+g_module_close (GModule               *module)
 {
   CHECK_ERROR (FALSE);
   
   g_return_val_if_fail (module != NULL, FALSE);
   g_return_val_if_fail (module->ref_count > 0, FALSE);
   
-  if (module != main_module)
-    module->ref_count--;
+  module->ref_count--;
   
-  if (!module->ref_count && module->de_init)
-    module->de_init (module);
-  if (!module->ref_count)
+  if (!module->ref_count && !module->is_resident && module->unload)
+    {
+      GModuleUnload unload;
+
+      unload = module->unload;
+      module->unload = NULL;
+      unload (module);
+    }
+
+  if (!module->ref_count && !module->is_resident)
     {
       GModule *last;
       GModule *node;
-
+      
       last = NULL;
+      
+      G_LOCK (GModule);
       node = modules;
       while (node)
        {
@@ -244,49 +329,68 @@ g_module_close (GModule        *module)
          node = last->next;
        }
       module->next = NULL;
-
-      _g_module_close (&module->handle, FALSE);
+      G_UNLOCK (GModule);
+      
+      _g_module_close (module->handle, FALSE);
       g_free (module->file_name);
-
+      
       g_free (module);
     }
+  
+  return g_module_error() == NULL;
+}
 
-  return module_error == NULL;
+void
+g_module_make_resident (GModule *module)
+{
+  g_return_if_fail (module != NULL);
+
+  module->is_resident = TRUE;
 }
 
 gchar*
 g_module_error (void)
 {
-  return module_error;
+  return g_static_private_get (&module_error_private);
 }
 
 gboolean
-g_module_symbol (GModule        *module,
-                const gchar    *symbol_name,
-                gconstpointer  *symbol)
+g_module_symbol (GModule       *module,
+                const gchar    *symbol_name,
+                gpointer       *symbol)
 {
+  gchar *module_error;
   if (symbol)
     *symbol = NULL;
   CHECK_ERROR (FALSE);
-
+  
   g_return_val_if_fail (module != NULL, FALSE);
   g_return_val_if_fail (symbol_name != NULL, FALSE);
   g_return_val_if_fail (symbol != NULL, FALSE);
-
+  
 #ifdef G_MODULE_NEED_USCORE
-  symbol_name = g_strconcat ("_", symbol_name, NULL);
-  *symbol = _g_module_symbol (&module->handle, symbol_name);
-  g_free (symbol_name);
+  {
+    gchar *name;
+
+    name = g_strconcat ("_", symbol_name, NULL);
+    *symbol = _g_module_symbol (module->handle, name);
+    g_free (name);
+  }
 #else  /* !G_MODULE_NEED_USCORE */
-  *symbol = _g_module_symbol (&module->handle, symbol_name);
+  *symbol = _g_module_symbol (module->handle, symbol_name);
 #endif /* !G_MODULE_NEED_USCORE */
-
-  if (module_error)
+  
+  if ((module_error = g_module_error()))
     {
+      gchar *error;
+
+      error = g_strconcat ("`", symbol_name, "': ", module_error, NULL);
+      g_module_set_error (error);
+      g_free (error);
       *symbol = NULL;
       return FALSE;
     }
-
+  
   return TRUE;
 }
 
@@ -294,9 +398,18 @@ gchar*
 g_module_name (GModule *module)
 {
   g_return_val_if_fail (module != NULL, NULL);
-
+  
   if (module == main_module)
     return "main";
-
+  
   return module->file_name;
 }
+
+gchar*
+g_module_build_path (const gchar *directory,
+                    const gchar *module_name)
+{
+  g_return_val_if_fail (module_name != NULL, NULL);
+  
+  return _g_module_build_path (directory, module_name);
+}