(linenum→info "unix/slp.c:2238")

glibc/2.7/iconv/gconv_dl.c

    1: /* Handle loading/unloading of shared object for transformation.
    2:    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005
    3:    Free Software Foundation, Inc.
    4:    This file is part of the GNU C Library.
    5:    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
    6: 
    7:    The GNU C Library is free software; you can redistribute it and/or
    8:    modify it under the terms of the GNU Lesser General Public
    9:    License as published by the Free Software Foundation; either
   10:    version 2.1 of the License, or (at your option) any later version.
   11: 
   12:    The GNU C Library is distributed in the hope that it will be useful,
   13:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   14:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15:    Lesser General Public License for more details.
   16: 
   17:    You should have received a copy of the GNU Lesser General Public
   18:    License along with the GNU C Library; if not, write to the Free
   19:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   20:    02111-1307 USA.  */
   21: 
   22: #include <assert.h>
   23: #include <dlfcn.h>
   24: #include <inttypes.h>
   25: #include <search.h>
   26: #include <stdlib.h>
   27: #include <string.h>
   28: #include <bits/libc-lock.h>
   29: #include <sys/param.h>
   30: 
   31: #include <gconv_int.h>
   32: #include <sysdep.h>
   33: 
   34: 
   35: #ifdef DEBUG
   36: /* For debugging purposes.  */
   37: static void print_all (void);
   38: #endif
   39: 
   40: 
   41: /* This is a tuning parameter.  If a transformation module is not used
   42:    anymore it gets not immediately unloaded.  Instead we wait a certain
   43:    number of load attempts for further modules.  If none of the
   44:    subsequent load attempts name the same object it finally gets unloaded.
   45:    Otherwise it is still available which hopefully is the frequent case.
   46:    The following number is the number of unloading attempts we wait
   47:    before unloading.  */
   48: #define TRIES_BEFORE_UNLOAD     2
   49: 
   50: /* Array of loaded objects.  This is shared by all threads so we have
   51:    to use semaphores to access it.  */
   52: static void *loaded;
   53: 
   54: /* Comparison function for searching `loaded_object' tree.  */
   55: static int
   56: known_compare (const void *p1, const void *p2)
   57: {
   58:   const struct __gconv_loaded_object *s1 =
   59:     (const struct __gconv_loaded_object *) p1;
   60:   const struct __gconv_loaded_object *s2 =
   61:     (const struct __gconv_loaded_object *) p2;
   62: 
   63:   return strcmp (s1->name, s2->name);
   64: }
   65: 
   66: /* Open the gconv database if necessary.  A non-negative return value
   67:    means success.  */
   68: struct __gconv_loaded_object *
   69: internal_function
   70: __gconv_find_shlib (const char *name)
   71: {
   72:   struct __gconv_loaded_object *found;
   73:   void *keyp;
   74: 
   75:   /* Search the tree of shared objects previously requested.  Data in
   76:      the tree are `loaded_object' structures, whose first member is a
   77:      `const char *', the lookup key.  The search returns a pointer to
   78:      the tree node structure; the first member of the is a pointer to
   79:      our structure (i.e. what will be a `loaded_object'); since the
   80:      first member of that is the lookup key string, &FCT_NAME is close
   81:      enough to a pointer to our structure to use as a lookup key that
   82:      will be passed to `known_compare' (above).  */
   83: 
   84:   keyp = __tfind (&name, &loaded, known_compare);
   85:   if (keyp == NULL)
   86:     {
   87:       /* This name was not known before.  */
   88:       size_t namelen = strlen (name) + 1;
   89: 
   90:       found = malloc (sizeof (struct __gconv_loaded_object) + namelen);
   91:       if (found != NULL)
   92:         {
   93:           /* Point the tree node at this new structure.  */
   94:           found->name = (char *) memcpy (found + 1, name, namelen);
   95:           found->counter = -TRIES_BEFORE_UNLOAD - 1;
   96:           found->handle = NULL;
   97: 
   98:           if (__builtin_expect (__tsearch (found, &loaded, known_compare)
   99:                                 == NULL, 0))
  100:             {
  101:               /* Something went wrong while inserting the entry.  */
  102:               free (found);
  103:               found = NULL;
  104:             }
  105:         }
  106:     }
  107:   else
  108:     found = *(struct __gconv_loaded_object **) keyp;
  109: 
  110:   /* Try to load the shared object if the usage count is 0.  This
  111:      implies that if the shared object is not loadable, the handle is
  112:      NULL and the usage count > 0.  */
  113:   if (found != NULL)
  114:     {
  115:       if (found->counter < -TRIES_BEFORE_UNLOAD)
  116:         {
  117:           assert (found->handle == NULL);
  118:           found->handle = __libc_dlopen (found->name);
  119:           if (found->handle != NULL)
  120:             {
  121:               found->fct = __libc_dlsym (found->handle, "gconv");
  122:               if (found->fct == NULL)
  123:                 {
  124:                   /* Argh, no conversion function.  There is something
  125:                      wrong here.  */
  126:                   __gconv_release_shlib (found);
  127:                   found = NULL;
  128:                 }
  129:               else
  130:                 {
  131:                   found->init_fct = __libc_dlsym (found->handle, "gconv_init");
  132:                   found->end_fct = __libc_dlsym (found->handle, "gconv_end");
  133: 
  134: #ifdef PTR_MANGLE
  135:                   PTR_MANGLE (found->fct);
  136:                   if (found->init_fct != NULL)
  137:                     PTR_MANGLE (found->init_fct);
  138:                   if (found->end_fct !=  NULL)
  139:                     PTR_MANGLE (found->end_fct);
  140: #endif
  141: 
  142:                   /* We have succeeded in loading the shared object.  */
  143:                   found->counter = 1;
  144:                 }
  145:             }
  146:           else
  147:             /* Error while loading the shared object.  */
  148:             found = NULL;
  149:         }
  150:       else if (found->handle != NULL)
  151:         found->counter = MAX (found->counter + 1, 1);
  152:     }
  153: 
  154:   return found;
  155: }
  156: 
  157: 
  158: /* This is very ugly but the tsearch functions provide no way to pass
  159:    information to the walker function.  So we use a global variable.
  160:    It is MT safe since we use a lock.  */
  161: static struct __gconv_loaded_object *release_handle;
  162: 
  163: static void
  164: do_release_shlib (void *nodep, VISIT value, int level)
  165: {
  166:   struct __gconv_loaded_object *obj = *(struct __gconv_loaded_object **) nodep;
  167: 
  168:   if (value != preorder && value != leaf)
  169:     return;
  170: 
  171:   if (obj == release_handle)
  172:     {
  173:       /* This is the object we want to unload.  Now decrement the
  174:          reference counter.  */
  175:       assert (obj->counter > 0);
  176:       --obj->counter;
  177:     }
  178:   else if (obj->counter <= 0 && obj->counter >= -TRIES_BEFORE_UNLOAD
  179:            && --obj->counter < -TRIES_BEFORE_UNLOAD && obj->handle != NULL)
  180:     {
  181:       /* Unload the shared object.  */
  182:       __libc_dlclose (obj->handle);
  183:       obj->handle = NULL;
  184:     }
  185: }
  186: 
  187: 
  188: /* Notify system that a shared object is not longer needed.  */
  189: void
  190: internal_function
  191: __gconv_release_shlib (struct __gconv_loaded_object *handle)
  192: {
  193:   /* Urgh, this is ugly but we have no other possibility.  */
  194:   release_handle = handle;
  195: 
  196:   /* Process all entries.  Please note that we also visit entries
  197:      with release counts <= 0.  This way we can finally unload them
  198:      if necessary.  */
  199:   __twalk (loaded, (__action_fn_t) do_release_shlib);
  200: }
  201: 
  202: 
  203: /* We run this if we debug the memory allocation.  */
  204: static void __libc_freeres_fn_section
  205: do_release_all (void *nodep)
  206: {
  207:   struct __gconv_loaded_object *obj = (struct __gconv_loaded_object *) nodep;
  208: 
  209:   /* Unload the shared object.  */
  210:   if (obj->handle != NULL)
  211:     __libc_dlclose (obj->handle);
  212: 
  213:   free (obj);
  214: }
  215: 
  216: libc_freeres_fn (free_mem)
  217: {
  218:   __tdestroy (loaded, do_release_all);
  219:   loaded = NULL;
  220: }
  221: 
  222: 
  223: #ifdef DEBUG
  224: static void
  225: do_print (const void *nodep, VISIT value, int level)
  226: {
  227:   struct __gconv_loaded_object *obj = *(struct __gconv_loaded_object **) nodep;
  228: 
  229:   printf ("%10s: \"%s\", %d\n",
  230:           value == leaf ? "leaf" :
  231:           value == preorder ? "preorder" :
  232:           value == postorder ? "postorder" : "endorder",
  233:           obj->name, obj->counter);
  234: }
  235: 
  236: static void
  237: print_all (void)
  238: {
  239:   __twalk (loaded, do_print);
  240: }
  241: #endif
Syntax (Markdown)