Re: revised patch for glib compilation



Hi Tim,

Please excuse the mangled Reference:s, I lost my mail archive along with most 
of the contents of my hard drive a few weeks ago, so I replied to the oldest 
message I have left in the thread...

Anyway, I redid my implementation of gmodule as a wrapper for libltdl to take 
advantage of the thread locking hooks just committed to libtool CVS, so that 
we can hopefully unify the two code bases.  The last few months have occupied 
me with pushing features gmodule had down into libltdl to make this possible, 
so the wrapper is actually very thin.

The purpose of this mail is mainly to get some feedback -- I haven't actually 
tested the code at all.  In fact, I have never programmed with threads in C 
before, so some pointers to a small threaded gmodule using project would be a 
huge help!

Let me know what you think and if you approve I will incorporate any 
suggestions you have, clean the whole thing up and resubmit.

Cheers,
	Gary.
-- 
  ___              _   ___   __              _         mailto: gvv techie com
 / __|__ _ _ ___ _| | / / | / /_ _ _  _ __ _| |_  __ _ ___       gary gnu org
| (_ / _` | '_|// / |/ /| |/ / _` | || / _` | ' \/ _` | _ \
 \___\__,_|_|\_, /|___(_)___/\__,_|\_,_\__, |_||_\__,_|//_/
home page:  /___/                      /___/                  gpg public key:
http://www.oranda.demon.co.uk           http://www.oranda.demon.co.uk/key.asc
/* GMODULE - GLIB wrapper code for dynamic module loading
 * Copyright (C) 1998 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GLib Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GLib at ftp://ftp.gtk.org/pub/gtk/. 
 */

#include	"gmodule.h"
#include	"gmoduleconf.h"
#include	"ltdl.h"
#include	<errno.h>
#include	<string.h>


#define G_CALLERID_UNDEFINED	((lt_dlcaller_id) -1)
#define G_MODULE_INI_STRING	"g_module_check_init"
#define G_MODULE_FINI_STRING	"g_module_unload"


/* --- prototypes --- */
static	inline gboolean	g_module_init_once	(void);
static	inline void	g_module_set_error	(const gchar *error);
static	const gchar    *g_module_get_error	(void);
static	void		g_module_mutex_lock	(void);
static	void		g_module_mutex_unlock	(void);

/* --- variables --- */
G_LOCK_DEFINE_STATIC (GModule);
const char           *g_log_domain_gmodule = "GModule";
static GStaticPrivate module_error_private = G_STATIC_PRIVATE_INIT;


/* --- inline functions --- */
static inline void
g_module_set_error (const gchar *error)
{
  g_static_private_set (&module_error_private, error, NULL);
  errno = 0;
}

/* For orthogonality only:  g_module_error already does exactly what
   is required, but is named according to the supported API. */
#define g_module_get_error	g_module_error

static inline gboolean
g_module_init_once (void)
{
  static gint initialized = 0;

  /* Clear error message for this thread.  */
  g_module_set_error (NULL);

  G_LOCK (GModule);
  if (++initialized == 1)
    {
      gint errors = 0;		/* Number of errors from libltdl calls.  */

      /* Make sure libltdl is using our memory managment API. */
      lt_dlmalloc = (lt_ptr(*)(size_t)) g_malloc;
      lt_dlfree	  = (void  (*)(lt_ptr)) g_free;

      /* Register the callbacks to make all lt_*() functions MT safe.  */
      lt_dlmutex_register (g_module_mutex_lock, g_module_mutex_unlock,
			   g_module_set_error,  g_module_get_error);

      /* Initialise ltdl library.  */
      errors = lt_dlinit ();
      if (!errors)
	{
	  gchar *path = g_getenv ("GMODULE_PATH");

	  /* Create a gmodule specific key for subsequent access to
	     per-module data stored by gmodule functions.  */
	  g_module_caller_id = lt_dlcaller_register ();

	  /* Initialise libltdl module search directory list.  */
	  if (path != NULL)
	    errors = lt_dladdsearchdir (path);
	}
      
      G_UNLOCK (GModule);
      return (errors == 0);
    }

  G_UNLOCK (GModule);
  return TRUE;
}

/* --- static functions --- */
static void
g_module_mutex_lock (void)
{
  G_LOCK (GModule);
}

static void
g_module_mutex_unlock (void)
{
  G_UNLOCK (GModule);
}


/* --- exported functions --- */

/**
 * g_module_supported:
 *
 * This function is deprecated.
 * Check if modules are supported on the current platform.  Now that
 * the gmodule API is a wrapper for libltdl, this function will always
 * return %TRUE.
 *
 * Return value: %TRUE if modules are supported.
 **/
gboolean
g_module_supported (void)
{
#if G_ENABLE_DEBUG
  static gboolean first_call = TRUE;

  if (first_call)
    {
      g_warning ("g_module_supported is deprecated.");
      g_warning ("modules are always supported by the underlying libltdl.");
      first_call = FALSE;
    }
#endif /* G_ENABLE_DEBUG */
  
  return TRUE;
}

/**
 * g_module_open:
 * @filename: the name of the file containing the module to be opened.
 * @flags: not used.
 *
 * Opens a module.  If the module has already been opened, its reference
 * count is incremented.
 *
 * First of all g_module_open() tries to open @file_name as a module.  If
 * that fails and @file_name has the ".la"-suffix (and is a libtool archive)
 * it tries to open the corresponding module.  If that fails and @file_name
 * doesn't have the proper module suffix for the host platform, this suffix
 * will be appended and any corresponding module opened.  If that fails and
 * @file_name doesn't have the ".la"-suffix, it is appended and
 * g_module_open() tries to open the corresponding module.  If ultimately
 * that fails as well, %NULL is returned.
 *
 * Return value: a #GModule on success, or %NULL on failure.
 **/
GModule*
g_module_open (const gchar    *file_name,
	       GModuleFlags    flags)
{
  lt_dlhandle  handle = (lt_dlhandle) 0;
  
  g_module_init_once ();

  /* open the module */
  handle = lt_dlopenext (file_name);
  
  if (handle)
    {
      gchar *error = NULL;
      GModuleCheckInit check_init;
      GModuleUnload unload;
      const gchar *check_failed_error = NULL;
      
      /* check initialization */
      if (g_module_symbol ((GModule *) handle, G_MODULE_INI_STRING,
			   (gpointer) &check_init))
	{
	  check_failed_error = check_init ((GModule *) handle);
	}
      
      if (check_failed_error != NULL)
	{
	  error = g_strconcat ("GModule initialization check failed: ",
			       check_failed_error, NULL);
	}

      /* Register error diagnostic generated above, if any. */
      if (error)
	{
	  g_module_close ((GModule *) handle);
	  module = NULL;
	  g_module_set_error (error);
	  g_free (error);
	}
    }
  
  return module;
}

/**
 * g_module_close:
 * @module: the module to be closed.
 *
 * Closes an open module.
 *
 * Return value: %TRUE on success.
 **/
gboolean
g_module_close (GModule	*module)
{
  lt_dlinfo *info;
  gboolean success = TRUE;

  g_return_val_if_fail (module != NULL, FALSE);

  g_module_init_once ();	/* Is this really neccessary? */

  info = lt_dlgetinfo ((lt_dlhandle) module);

  g_return_val_if_fail (info->ref_count > 1, FALSE);
  
  if ((info->ref_count == 1) && !lt_dlisresident ((lt_dlhandle) module))
    {
      GModuleUnload unload;
      lt_ptr stale = NULL;

      unload = g_module_symbol (module, G_MODULE_FINI_STRING,
				(gpointer) &unload);

      if (unload)
	unload (module);
      
      if (lt_dlclose ((lt_dlhandle) module) != 0)
	success = FALSE;

      g_free (module);
    }
  
  return success;
}

/**
 * g_module_make_resident:
 * @module: the module to make permenantly resident.
 *
 * Ensures that a module can never be unloaded.  Any future g_module_close()
 * calls on the module will have no effect.  If you open the entire process
 * as a reflexive module, then it is always made resident by default -- there
 * is no need to call this function manually.
 **/
void
g_module_make_resident (GModule *module)
{
  g_return_if_fail (module != NULL);

  lt_dlmakeresident ((lt_dlhandle) module);
}

/**
 * g_module_error:
 *
 * Get a string describing the last error that occured in the gmodule
 * subsystem.
 *
 * Return value: a string describing the last module error.
 **/
gchar*
g_module_error (void)
{
  return g_static_private_get (&module_error_private);
}

/**
 * g_module_symbol:
 * @module: the module.
 * @symbol_name: the name of the symbol to find.
 * @symbol: returns the pointer to the symbol value.
 *
 * Gets a symbol pointer from a module.
 *
 * Return value: %TRUE on success.
 **/
gboolean
g_module_symbol (GModule	*module,
		 const gchar	*symbol_name,
		 gpointer	*symbol)
{
  if (symbol)
    *symbol = NULL;

  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);
  
  *symbol = lt_dlsym ((lt_dlhandle) module, symbol_name);
  
  if (*symbol == NULL)
    {
      gchar *module_error = lt_dlerror ();
      gchar *error;

      error = g_strconcat ("`", symbol_name, "': ", module_error, NULL);
      g_module_set_error (error);
      g_free (error);

      return FALSE;
    }
  
  return TRUE;
}

/**
 * g_module_name:
 * @module: the module.
 *
 * Gets the file name from a #GModule.
 *
 * Return value: the file name of the module, or "main" if the module
 * is the main program itself.
 **/
gchar*
g_module_name (GModule *module)
{
  lt_dlinfo  *info;
  
  g_return_val_if_fail (module != NULL, NULL);
  
  info   = lt_dlgetinfo ((lt_dlhandle) module);

  return g_strdup (info->filename ? info->filename : "main");
}

/**
 * g_module_set_search_path:
 * @path: a colon delimited list of directories.
 *
 * Set the paths of the directories to be searced when trying to
 * locate a module opened using a relative path.
 *
 * Return value: %TRUE if successful.
 **/
gboolean
g_module_set_search_path (gchar *path)
{
  return (lt_dlsetsearchpath (path) == 0);
}

/**
 * g_module_add_search_path:
 * @path: a colon delimited list of directories.
 *
 * Append to the list of user paths, the additional @path of directories
 * to be searched when trying to locate a module opened using a
 * relative path.
 *
 * Return value: %TRUE if successful.
 **/
gboolean
g_module_add_search_path (gchar *path)
{
  return (lt_dladdsearchdir (path) == 0);
}

/**
 * g_module_build_path:
 * @directory: the directory where the module is.
 * @module_name: the name of the module.
 *
 * This function is deprecated.
 **/
gchar*
g_module_build_path (const gchar *directory,
		     const gchar *module_name)
{
#if G_ENABLE_DEBUG
  static gboolean first_call = TRUE;

  if (first_call)
    {
      g_warning ("g_module_build_path is deprecated.");
      g_warning ("Use g_module_set_search_path or g_module_add_search_path.");
      first_call = FALSE;
    }
#endif /* G_ENABLE_DEBUG */

#if (G_MODULE_IMPL == G_MODULE_IMPL_DL)

  if (directory && *directory) {
    if (strncmp (module_name, "lib", 3) == 0)
      return g_strconcat (directory, "/", module_name, NULL);
    else
      return g_strconcat (directory, "/lib", module_name, ".so", NULL);
  } else if (strncmp (module_name, "lib", 3) == 0)
    return g_strdup (module_name);
  else
    return g_strconcat ("lib", module_name, ".so", NULL);

#elif (G_MODULE_IMPL == G_MODULE_IMPL_DLD)

  if (directory && *directory)
    if (strncmp (module_name, "lib", 3) == 0)
      return g_strconcat (directory, "/", module_name, NULL);
    else
      return g_strconcat (directory, "/lib", module_name, ".sl", NULL);
  else if (strncmp (module_name, "lib", 3) == 0)
    return g_strdup (module_name);
  else
    return g_strconcat ("lib", module_name, ".sl", NULL);

#elif (G_MODULE_IMPL == G_MODULE_IMPL_BEOS)

  g_warning ("g_module_build_path() untested for BeOS!");
  
  if (directory && *directory)
    {
      if (strncmp (module_name, "lib", 3) == 0)
        return g_strconcat (directory, "/", module_name, NULL);
      else
        return g_strconcat (directory, "/lib", module_name, ".so", NULL);
    }
  else if (strncmp (module_name, "lib", 3) == 0)
    return g_strdup (module_name);
  else
    return g_strconcat ("lib", module_name, ".so", NULL);

#elif (G_MODULE_IMPL == G_MODULE_IMPL_WIN32)

  {
    gint k = strlen (module_name);
    if (directory && *directory)
      if (k > 4 && g_strcasecmp (module_name + k - 4, ".dll") == 0)
	return g_strconcat (directory, "\\", module_name, NULL);
      else
	return g_strconcat (directory, "\\", module_name, ".dll", NULL);
    else if (k > 4 && g_strcasecmp (module_name + k - 4, ".dll") == 0)
      return g_strdup (module_name);
    else
      return g_strconcat (module_name, ".dll", NULL);
  }
  
#elif (G_MODULE_IMPL == G_MODULE_IMPL_OS2)

  {
    gchar *suffix = strrchr(module_name, '.');
    if (directory && *directory)
      if (suffix && (stricmp (suffix, ".dll") == 0))
	return g_strconcat (directory, "/", module_name, NULL);
      else
	return g_strconcat (directory, "/", module_name, ".dll", NULL);
    else if (suffix && (stricmp (suffix, ".dll") == 0))
      return g_strdup (module_name);
    else
      return g_strconcat (module_name, ".dll", NULL);
  }
  
#endif

  return NULL;
}
/* GMODULE - GLIB wrapper code for dynamic module loading
 * Copyright (C) 1998 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GLib Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GLib at ftp://ftp.gtk.org/pub/gtk/. 
 */

#ifndef __GMODULE_H__
#define __GMODULE_H__

extern const char      *g_log_domain_gmodule;
#include <glib.h>

G_BEGIN_DECLS

/* exporting and importing functions, this is special cased
 * to feature Windows dll stubs.
 */
#define	G_MODULE_IMPORT		extern
#if defined (G_OS_WIN32)
#  define	G_MODULE_EXPORT		__declspec(dllexport)
#else /* !G_OS_WIN32 */
#  define	G_MODULE_EXPORT
#endif /* !G_OS_WIN32 */

/* No longer used.  These remain for interface compatibility only.  */
typedef enum
{
  G_MODULE_BIND_LAZY	= 1 << 0,
  G_MODULE_BIND_MASK	= 0x01
} GModuleFlags;

typedef	gpointer GModule;
typedef const gchar* (*GModuleCheckInit) (GModule	*module);
typedef void	     (*GModuleUnload)	 (GModule	*module);

/* open a module `file_name' and return handle, which is NULL on error */
GModule*	g_module_open		   (const gchar		*file_name,
					    GModuleFlags	 flags);

/* close a previously opened module, returns TRUE on success */
gboolean	g_module_close		   (GModule		*module);

/* make a module resident so g_module_close on it will be ignored */
void		g_module_make_resident	   (GModule		*module);

/* query the last module error as a string */
gchar*		g_module_error		   (void);

/* retrive a symbol pointer from `module', returns TRUE on success */
gboolean	g_module_symbol		   (GModule		*module,
					    const gchar		*symbol_name,
					    gpointer		*symbol);

/* retrive the file name from an existing module */
gchar*		g_module_name		   (GModule		*module);

/* Reset the list of colon separated module search directories. */
gchar*		g_module_set_search_path   (gchar		*path);

/* Add a new search directory to the list.  */
gchar*		g_module_add_search_path   (gchar		*path);



/* --- deprecated functions --- */
gboolean	g_module_supported	   (void) G_GNUC_CONST;
gchar*		g_module_build_path	   (const gchar		*directory,
					    const gchar		*module_name);

G_END_DECLS

#endif /* __GMODULE_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]