File:  [gforth] / gforth / libltdl / lt_dlloader.c
Revision 1.1: download - view: text, annotated - select for diffs
Sat Apr 19 19:28:51 2008 UTC (16 years ago) by anton
Branches: MAIN
CVS tags: v0-7-0, HEAD
added libltdl (no integration yet)

    1: /* lt_dlloader.c -- dynamic library loader interface
    2: 
    3:    Copyright (C) 2004, 2007 Free Software Foundation, Inc.
    4:    Written by Gary V. Vaughan, 2004
    5: 
    6:    NOTE: The canonical source of this file is maintained with the
    7:    GNU Libtool package.  Report bugs to bug-libtool@gnu.org.
    8: 
    9: GNU Libltdl is free software; you can redistribute it and/or
   10: modify it under the terms of the GNU Lesser General Public
   11: License as published by the Free Software Foundation; either
   12: version 2 of the License, or (at your option) any later version.
   13: 
   14: As a special exception to the GNU Lesser General Public License,
   15: if you distribute this file as part of a program or library that
   16: is built using GNU Libtool, you may include this file under the
   17: same distribution terms that you use for the rest of that program.
   18: 
   19: GNU Libltdl is distributed in the hope that it will be useful,
   20: but WITHOUT ANY WARRANTY; without even the implied warranty of
   21: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   22: GNU Lesser General Public License for more details.
   23: 
   24: You should have received a copy of the GNU Lesser General Public
   25: License along with GNU Libltdl; see the file COPYING.LIB.  If not, a
   26: copy can be downloaded from  http://www.gnu.org/licenses/lgpl.html,
   27: or obtained by writing to the Free Software Foundation, Inc.,
   28: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   29: */
   30: 
   31: #include "lt__private.h"
   32: #include "lt_dlloader.h"
   33: 
   34: #define RETURN_SUCCESS 0
   35: #define RETURN_FAILURE 1
   36: 
   37: static void *	loader_callback (SList *item, void *userdata);
   38: 
   39: /* A list of all the dlloaders we know about, each stored as a boxed
   40:    SList item:  */
   41: static	SList    *loaders		= 0;
   42: 
   43: 
   44: /* Return NULL, unless the loader in this ITEM has a matching name,
   45:    in which case we return the matching item so that its address is
   46:    passed back out (for possible freeing) by slist_remove.  */
   47: static void *
   48: loader_callback (SList *item, void *userdata)
   49: {
   50:   const lt_dlvtable *vtable = (const lt_dlvtable *) item->userdata;
   51:   const char *	    name    = (const char *) userdata;
   52: 
   53:   assert (vtable);
   54: 
   55:   return streq (vtable->name, name) ? (void *) item : NULL;
   56: }
   57: 
   58: 
   59: /* Hook VTABLE into our global LOADERS list according to its own
   60:    PRIORITY field value.  */
   61: int
   62: lt_dlloader_add (const lt_dlvtable *vtable)
   63: {
   64:   SList *item;
   65: 
   66:   if ((vtable == 0)	/* diagnose invalid vtable fields */
   67:       || (vtable->module_open == 0)
   68:       || (vtable->module_close == 0)
   69:       || (vtable->find_sym == 0)
   70:       || ((vtable->priority != LT_DLLOADER_PREPEND) &&
   71: 	  (vtable->priority != LT_DLLOADER_APPEND)))
   72:     {
   73:       LT__SETERROR (INVALID_LOADER);
   74:       return RETURN_FAILURE;
   75:     }
   76: 
   77:   item = slist_box (vtable);
   78:   if (!item)
   79:     {
   80:       (*lt__alloc_die) ();
   81: 
   82:       /* Let the caller know something went wrong if lt__alloc_die
   83: 	 doesn't abort.  */
   84:       return RETURN_FAILURE;
   85:     }
   86: 
   87:   if (vtable->priority == LT_DLLOADER_PREPEND)
   88:     {
   89:       loaders = slist_cons (item, loaders);
   90:     }
   91:   else
   92:     {
   93:       assert (vtable->priority == LT_DLLOADER_APPEND);
   94:       loaders = slist_concat (loaders, item);
   95:     }
   96: 
   97:   return RETURN_SUCCESS;
   98: }
   99: 
  100: #ifdef LT_DEBUG_LOADERS
  101: static void *
  102: loader_dump_callback (SList *item, void *userdata)
  103: {
  104:   const lt_dlvtable *vtable = (const lt_dlvtable *) item->userdata;
  105:   fprintf (stderr, ", %s", (vtable && vtable->name) ? vtable->name : "(null)");
  106:   return 0;
  107: }
  108: 
  109: void
  110: lt_dlloader_dump (void)
  111: {
  112:   fprintf (stderr, "loaders: ");
  113:   if (!loaders)
  114:     {
  115:       fprintf (stderr, "(empty)");
  116:     }
  117:   else
  118:     {
  119:       const lt_dlvtable *head = (const lt_dlvtable *) loaders->userdata;
  120:       fprintf (stderr, "%s", (head && head->name) ? head->name : "(null)");
  121:       if (slist_tail (loaders))
  122: 	slist_foreach (slist_tail (loaders), loader_dump_callback, NULL);
  123:     }
  124:   fprintf (stderr, "\n");
  125: }
  126: #endif
  127: 
  128: /* An iterator for the global loader list: if LOADER is NULL, then
  129:    return the first element, otherwise the following element.  */
  130: lt_dlloader
  131: lt_dlloader_next (lt_dlloader loader)
  132: {
  133:   SList *item = (SList *) loader;
  134:   return (lt_dlloader) (item ? item->next : loaders);
  135: }
  136: 
  137: 
  138: /* Non-destructive unboxing of a loader.  */
  139: const lt_dlvtable *
  140: lt_dlloader_get	(lt_dlloader loader)
  141: {
  142:   return (const lt_dlvtable *) (loader ? ((SList *) loader)->userdata : NULL);
  143: }
  144: 
  145: 
  146: /* Return the contents of the first item in the global loader list
  147:    with a matching NAME after removing it from that list.  If there
  148:    was no match, return NULL; if there is an error, return NULL and
  149:    set an error for lt_dlerror; do not set an error if only resident
  150:    modules need this loader; in either case, the loader list is not
  151:    changed if NULL is returned.  */
  152: lt_dlvtable *
  153: lt_dlloader_remove (char *name)
  154: {
  155:   const lt_dlvtable *	vtable	= lt_dlloader_find (name);
  156:   static const char	id_string[] = "lt_dlloader_remove";
  157:   lt_dlinterface_id	iface;
  158:   lt_dlhandle		handle = 0;
  159:   int			in_use = 0;
  160:   int			in_use_by_resident = 0;
  161: 
  162:   if (!vtable)
  163:     {
  164:       LT__SETERROR (INVALID_LOADER);
  165:       return 0;
  166:     }
  167: 
  168:   /* Fail if there are any open modules which use this loader.  */
  169:   iface = lt_dlinterface_register (id_string, NULL);
  170:   while ((handle = lt_dlhandle_iterate (iface, handle)))
  171:     {
  172:       lt__handle *cur = (lt__handle *) handle;
  173:       if (cur->vtable == vtable)
  174: 	{
  175: 	  in_use = 1;
  176: 	  if (lt_dlisresident (handle))
  177: 	    in_use_by_resident = 1;
  178: 	}
  179:     }
  180:   lt_dlinterface_free (iface);
  181:   if (in_use)
  182:     {
  183:       if (!in_use_by_resident)
  184: 	LT__SETERROR (REMOVE_LOADER);
  185:       return 0;
  186:     }
  187: 
  188:   /* Call the loader finalisation function.  */
  189:   if (vtable && vtable->dlloader_exit)
  190:     {
  191:       if ((*vtable->dlloader_exit) (vtable->dlloader_data) != 0)
  192: 	{
  193: 	  /* If there is an exit function, and it returns non-zero
  194: 	     then it must set an error, and we will not remove it
  195: 	     from the list.  */
  196: 	  return 0;
  197: 	}
  198:     }
  199: 
  200:   /* If we got this far, remove the loader from our global list.  */
  201:   return (lt_dlvtable *)
  202:       slist_unbox ((SList *) slist_remove (&loaders, loader_callback, name));
  203: }
  204: 
  205: 
  206: const lt_dlvtable *
  207: lt_dlloader_find (char *name)
  208: {
  209:   return lt_dlloader_get (slist_find (loaders, loader_callback, name));
  210: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>