/[m4]/m4/m4/module.c
ViewVC logotype

Diff of /m4/m4/module.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.4 by akim, Tue Aug 7 10:41:11 2001 UTC revision 1.5 by gary, Thu Aug 16 22:21:30 2001 UTC
# Line 17  Line 17 
17     02111-1307  USA     02111-1307  USA
18  */  */
19    
 #define MODULES_UNINITIALISED -4444  
   
20  #include "m4.h"  #include "m4.h"
21  #include "pathconf.h"  #include "pathconf.h"
22  #include "ltdl.h"  #include "ltdl.h"
# Line 28  Line 26 
26  #undef DEBUG_MODULES  #undef DEBUG_MODULES
27    
28  /*  /*
29   * This file implements dynamic modules in GNU m4.  A module is a   * This file implements dynamic modules in GNU M4.  A module is a
30   * compiled shared object, that can be linked into GNU m4 at run   * compiled shared object, that can be loaded into GNU M4 at run
31   * time. Information about creating modules is in ../modules/README.   * time. Information about creating modules is in ../modules/README.
32   *   *
33   * The current implementation uses libltdl, which is in turn can load   * This implementation uses libltdl, which is in turn can open modules
34   * modules using either dlopen(3) (exists on GNU/Linux, OSF, Solaris,   * using either dlopen(3) (exists on GNU/Linux, OSF, Solaris, SunOS and
35   * SunOS), shl_load(3) (exists on HPUX), LoadLibrary(3) (exists on   * others), shl_load(3) (exists on HPUX), LoadLibrary(3) (exists on
36   * Windows, cygwin, OS/2), load_add_on(3) (exists on BeOS), and can   * Windows, cygwin, OS/2), load_add_on(3) (exists on BeOS), and can
37   * also fall back to dld_link(3) from libdld or lt_dlpreload(3) from   * also fall back to dld_link(3) from GNU libdld or lt_dlpreload from
38   * libtool if shared libraries are not available on the host machine.   * libtool if shared libraries are not available on the host machine.
39   *   *
40   * A m4 module need only define one external symbol, called   * An M4 module will usually define an external symbol called
41   * `m4_builtin_table'.  This symbol should point to a table of `m4_builtin'.   * `m4_builtin_table'.  This symbol points to a table of `m4_builtin'.
42   * This table is pushed on a list of builtin tables and each definition   * The table is pushed on an internal stack of builtin tables, each
43   * therein is added to the symbol table.   * definition therein is added to the symbol table.
  *  
  * The code implementing loadable modules is modest.  It is divided  
  * between the files builtin.c (user interface and support for multiple  
  * builtin tables) and this file (OS dependant routines).  
44   *   *
45   * To load a module, use `load(modulename)'.  The function   * To load a module, call m4_module_load(), which uses the libltdl
46   * `builtin_load' calls m4_module_load() in this file, which uses   * API to find the module in the module search path.  The search
47   * libltdl to find the module in the module search path.  This   * path is initialised from the environment variable M4MODPATH, followed
48   * path is initialised from the environment variable M4MODPATH, or if   * by the configuration time default where the modules shipped with M4
49   * not set, initalised to a configuration time default.  This   * itself are installed.  Libltdl reads the libtool .la file to
50   * function reads the libtool .la file to get the real library name   * get the real library name (which can be system dependent), returning
51   * (which can be system dependent) and returns NULL on failure and a   * NULL on failure or else a libtool module handle for the newly mapped
52   * non-NULL void* on success.  If successful lt_dlopen returns the   * vm segment containing the module code.  If the module is not already
53   * value of this void*, which is a handle for the vm segment mapped.   * loaded, m4_module_load() retrieves the value of the symbol
54   * Module_load() checks to see if the module is already loaded, and if   * `m4_builtin_table', which is installed using m4_builtin_table_install().
  * not, retrieves the symbol `m4_builtin_table' and returns it's value to  
  * m4_loadmodule().  This pointer should be an m4_builtin*, which is  
  * installed using install_builtin_table().  
55   *   *
56   * In addition to builtin functions, you can also define static macro   * In addition to builtin functions, you can also define static macro
57   * expansions in the `m4_macro_table' symbol.  If you define this symbol   * expansions in the `m4_macro_table' symbol.  If you define this symbol
58   * in your modules, it should be an array of `m4_macro's, mapping macro   * in your modules, it should be an array of `m4_macro's, mapping macro
59   * names to the expansion text.   * names to the expansion text.  Any macros defined in `m4_macro_table'
60   *   * are installed into the M4 symbol table with m4_macro_table_install().
  * When a module is loaded, the function "void m4_init_module(struct  
  * obstack *obs)" is called, if defined.  Any non NULL return value of  
  * this function will be the expansion of "load".  Before program  
  * exit, all modules are unloaded and the function "void  
  * m4_finish_module(void)" is called, if defined.  It is  
  * safe to load the same module several times.  
61   *   *
62   * To unload a module, use `unload(modulename)'.  The function   * Each time a module is loaded, the module function
63   * `m4_unload' calls m4_module_unload() in this file, which uses   * "void m4_init_module (struct obstack *obs)" is called, if defined.
64   * remove_builtin_table() to remove the builtins defined by the   * Any value stored in IBS by this function becomes the expansion of the
65   * unloaded module from the symbol table.  If the module has been loaded   * macro which called it.  Before M4 exits, all modules are unloaded and
66   * several times with calls to `load(modulename)', then the module   * the function "void m4_finish_module (struct obstack *obs)" is called,
67   * will not be unloaded until the same number of calls to unload   * if defined.  It is safe to load the same module several times:  the
68   * have been made (nor will the builtin table be purged, nor the finish   * init and finish functions will also be called multiple times in this
69   * function called).  If the module is successfully unloaded, and it   * case.
  * defined a function called `m4_finish_module', that function will be  
  * called last of all.  
70   *   *
71   * Modules loaded from the command line (with the `-m' switch) can be   * To unload a module, use m4_module_unload(). which uses
72   * removed with unload too.   * m4_builtin_table_uninstall() and m4_macro_table_uninstall() to remove
73   *   * the builtins defined by the unloaded module from the symbol table.  If
74   * When m4 exits, it will unload every remaining loaded module, calling   * the module has been loaded several times with calls to
75   * any `m4_finish_module' functions they defined before closing.   * m4_module_load, then the module will not be unloaded until the same
76     * number of calls to m4_module_unload() have been made (nor will the
77     * symbol table be purged).
78   **/   **/
79    
80  M4_GLOBAL_DATA List *m4_modules;  #define M4_BUILTIN_SYMBOL       "m4_builtin_table"
81    #define M4_MACRO_SYMBOL         "m4_macro_table"
82    #define M4_INIT_SYMBOL          "m4_init_module"
83    #define M4_FINISH_SYMBOL        "m4_finish_module"
84    
85    static const char*  m4_module_dlerror   M4_PARAMS((void));
86    
87    static lt_dlcaller_id m4_caller_id = 0;
88    
89  const char *  const char *
90  m4_module_name (module)  m4_module_name (handle)
91       const m4_module *module;       const lt_dlhandle handle;
92  {  {
93    return module ? module->modname : NULL;    const lt_dlinfo *info;
 }  
94    
95  const m4_builtin *    assert (handle);
96  m4_module_builtins (module)  
97       const m4_module *module;    info = lt_dlgetinfo (handle);
98  {  
99    return module ? module->bp : NULL;    return info ? info->name : 0;
100  }  }
101    
102  const m4_macro *  m4_builtin *
103  m4_module_macros (module)  m4_module_builtins (handle)
104       const m4_module *module;       const lt_dlhandle handle;
105  {  {
106    return module ? module->mp : NULL;    m4_module_data *data;
107    
108      assert (handle);
109    
110      data = (m4_module_data *) lt_dlcaller_get_data (m4_caller_id, handle);
111    
112      return data ? data->bp : 0;
113  }  }
114    
115  VOID *  m4_macro *
116  m4_module_find_by_modname (elt, match)  m4_module_macros (handle)
117       List *elt;       const lt_dlhandle handle;
      VOID *match;  
118  {  {
119    const m4_module *module = (const m4_module *) elt;    m4_module_data *data;
120    
121    if (strcmp (module->modname, (char *) match) == 0)    assert (handle);
     return (VOID *) module;  
122    
123    return NULL;    data = (m4_module_data *) lt_dlcaller_get_data (m4_caller_id, handle);
124    
125      return data ? data->mp : 0;
126  }  }
127    
128  VOID *  lt_dlhandle
129  m4_module_find_by_builtin (elt, match)  m4_module_find_by_builtin (match)
130       List *elt;       const m4_builtin *match;
      VOID *match;  
131  {  {
132    const m4_module *module = (const m4_module *) elt;    lt_dlhandle     handle = 0;
133    
134    if (module && module->bp)    while ((handle = lt_dlhandle_next (handle)))
135      {      {
136        const m4_builtin *bp;        m4_module_data *data
137            = (m4_module_data *) lt_dlcaller_get_data (m4_caller_id, handle);
138    
139        for (bp = &module->bp[0]; bp->name; ++bp)        if (data && data->bp)
140          {          {
141            if (bp == (const m4_builtin *) match)            const m4_builtin *bp;
142              return (VOID *) module;  
143              for (bp = &data->bp[0]; bp->name; ++bp)
144                if (bp == match)
145                  goto found;
146          }          }
147      }      }
148    
149    return NULL;   found:
150      return handle;
151  }  }
152    
153  /*  
154   * Initialisation.  Currently the module search path in path.c is  
155   * initialised from M4MODPATH.  Only absolute path names are accepted to  const char *
156   * prevent the path search of the dlopen library from finding wrong  m4_module_dlerror ()
157   * files.  {
158   */    const char *dlerror = lt_dlerror ();
159    
160      if (!dlerror)
161        dlerror = _("unknown error");
162    
163      return dlerror;
164    }
165    
166    /* Initialisation.  Currently the module search path in path.c is
167       initialised from M4MODPATH.  Only absolute path names are accepted to
168       prevent the path search of the dlopen library from finding wrong
169       files. */
170  void  void
171  m4_module_init ()  m4_module_init ()
172  {  {
173    static int errors = MODULES_UNINITIALISED;    int errors = 0;
174      
175    /* Do this only once! */    /* Do this only once!  If we already have a caller_id, then the
176    if (errors != MODULES_UNINITIALISED)       module system has already been initialised.  */
177      return;    if (m4_caller_id)
178        {
179          M4ERROR ((warning_status, 0,
180                    _("Warning: multiple module loader initialisations")));
181          return;
182        }
183    
184    /* initialise libltdl's memory management. */    /* initialise libltdl's memory management. */
185    lt_dlmalloc = xmalloc;    lt_dlmalloc = xmalloc;
186    lt_dlfree = xfree;    lt_dlfree   = xfree;
187    
188    errors = lt_dlinit();    errors      = lt_dlinit ();
189    
190    /* If the user set M4MODPATH, then use that as the start of libltdls    /* Register with libltdl for a key to store client data against
191     * module search path, else fall back on the default.       ltdl module handles.  */
192     */    if (!errors)
   if (errors == 0)  
193      {      {
194        char *path = getenv("M4MODPATH");        m4_caller_id = lt_dlcaller_register ();
195    
196  #ifdef DEBUG_MODULES        if (!m4_caller_id)
197        M4_DEBUG_MESSAGE("Module system initialised.");          {
198  #endif /* DEBUG_MODULES */            const char *error_msg = _("libltdl client registration failed");
199    
200        if (path != NULL)            lt_dlseterror (lt_dladderror (error_msg));
         errors = lt_dladdsearchdir(path);  
     }  
201    
202    if (errors == 0)            /* No need to check error statuses from the calls above -- If
203      errors = lt_dladdsearchdir(MODULE_PATH);               either fails for some reason, a diagnostic will be set for
204                 lt_dlerror() anyway.  */
205              ++errors;
206            }
207        }
208      
209      if (!errors)
210        errors = lt_dlsetsearchpath (MODULE_PATH);
211    
212    if (errors != 0)    /* If the user set M4MODPATH, then use that as the start of the module
213         search path.  */
214      if (!errors)
215      {      {
216        /* Couldn't initialise the module system; diagnose and exit. */        char *path = getenv ("M4MODPATH");
217        const char *dlerror = lt_dlerror();  
218        M4ERROR ((EXIT_FAILURE, 0,        if (path)
219                  _("ERROR: failed to initialise modules: %s"), dlerror));          errors = lt_dlinsertsearchdir (lt_dlgetsearchpath (), path);
220      }      }
221    
222      /* Couldn't initialise the module system; diagnose and exit.  */
223      if (errors)
224        M4ERROR ((EXIT_FAILURE, 0,
225                  _("ERROR: failed to initialise module loader: %s"),
226                  m4_module_dlerror ()));
227    
228    #ifdef DEBUG_MODULES
229      M4_DEBUG_MESSAGE ("Module loader initialised.");
230    #endif /* DEBUG_MODULES */
231  }  }
232    
233  /*  
234   * Load a module.  MODNAME can be a absolute file name or, if relative,  /* Load a module.  MODNAME can be a absolute file name or, if relative,
235   * it is searched for in the module path.  The module is unloaded in     it is searched for in the module path.  The module is unloaded in
236   * case of error.     case of error.  */
237   */  const lt_dlhandle
238    m4_module_open (name, obs)
239  static VOID *       const char *name;
 module_handle_find (elt, match)  
      List *elt;  
      VOID *match;  
 {  
   m4_module *module = (m4_module *) elt;  
   if (module->handle == match)  
     return (VOID *) module;  
   
   return NULL;  
 }  
   
 const m4_module *  
 m4_module_load (modname, obs)  
      const char *modname;  
240       struct obstack *obs;       struct obstack *obs;
241  {  {
242    lt_dlhandle       handle      = NULL;    lt_dlhandle           handle          = 0;
243    m4_module_init_t *init_func   = NULL;    m4_module_init_func  *init_func       = 0;
244    m4_module        *module      = NULL;    m4_builtin           *bp              = 0;
245    m4_builtin       *bp          = NULL;    m4_macro             *mp              = 0;
   m4_macro         *mp          = NULL;  
246    
247    /* Dynamically load the named module. */    /* Dynamically open the named module. */
248    handle = lt_dlopenext (modname);    handle = lt_dlopenext (name);
249    
250    if (handle)    if (handle)
251      {      {
252        module = (m4_module *) list_find (m4_modules, handle,  #ifdef DEBUG_MODULES
253                                          module_handle_find);        const lt_dlinfo *info = lt_dlgetinfo (handle);
254        if (module)        M4_DEBUG_MESSAGE2("module %s: opening at %s", name, info->filename);
255    #endif
256    
257          /* Find the builtin table in the opened module. */
258          bp = (m4_builtin *) lt_dlsym (handle, M4_BUILTIN_SYMBOL);
259    
260          /* Find the macro table in the opened module. */
261          mp = (m4_macro *) lt_dlsym (handle, M4_MACRO_SYMBOL);
262    
263          /* Find and run any initialising function in the opened module,
264             each time the module is opened.  */
265          init_func = (m4_module_init_func *) lt_dlsym (handle, M4_INIT_SYMBOL);
266          if (init_func)
267          {          {
268            lt_dlclose (handle); /* close the duplicate copy */            (*init_func) (handle, obs);
   
           /* increment the load counter */  
           module->ref_count++;  
269    
270  #ifdef DEBUG_MODULES  #ifdef DEBUG_MODULES
271            M4_DEBUG_MESSAGE2("module %s: now has %d references.",            M4_DEBUG_MESSAGE1("module %s: init hook called", name);
                          modname, module->ref_count);  
272  #endif /* DEBUG_MODULES */  #endif /* DEBUG_MODULES */
           return module;  
273          }          }
274      }      }
   
   
   if (handle)  
     {  
       /* Find the builtin table in the loaded module. */  
       bp = (m4_builtin *) lt_dlsym (handle, "m4_builtin_table");  
   
       /* Find the macro table in the loaded module. */  
       mp = (m4_macro *) lt_dlsym (handle, "m4_macro_table");  
   
       /* Find and run the initialising function in the loaded module  
        * (if any).  
        */  
       init_func = (m4_module_init_t*) lt_dlsym (handle, "m4_init_module");  
       if (init_func != NULL)  
         (*init_func) (obs);  
     }  
275    else    else
276      {      {
277        /* Couldn't load the module; diagnose and exit. */        /* Couldn't open the module; diagnose and exit. */
278        const char *dlerror = lt_dlerror();        M4ERROR ((EXIT_FAILURE, 0,
279        if (dlerror == NULL)                  _("ERROR: cannot open module `%s': %s"),
280          M4ERROR ((EXIT_FAILURE, 0,                  name, m4_module_dlerror ()));
                   _("ERROR: cannot load module: `%s'"), modname));  
       else  
         M4ERROR ((EXIT_FAILURE, 0,  
                   _("ERROR: cannot load module: `%s': %s"),  
                   modname, dlerror));  
281      }      }
282    
283    if (!bp && !mp && !init_func)    if (!bp && !mp && !init_func)
284      {      {
285        M4ERROR ((EXIT_FAILURE, 0,        /* Since we don't use it here, only check for the finish hook
286                  _("ERROR: module `%s' has no entry points"), modname));           if we were about to diagnose a module with no entry points.  */
287          if (!lt_dlsym (handle, M4_FINISH_SYMBOL))
288            M4ERROR ((EXIT_FAILURE, 0,
289                      _("ERROR: module `%s' has no entry points"),
290                      name));
291      }      }
292    
293    /* If the module was correctly loaded and has the necessary    /* If the module was correctly opened and has the necessary
294     * symbols, then update our internal tables to remember the       symbols, then store some client data for the new module
295     * new module.       on the first open only.  */
    */  
296    if (handle)    if (handle)
297      {      {
298        module = XMALLOC (m4_module, 1);        const lt_dlinfo  *info    = lt_dlgetinfo (handle);
299          
300  #ifdef DEBUG_MODULES        if (info && (info->ref_count == 1))
301        M4_DEBUG_MESSAGE1("module %s: loaded ok", modname);          {
302  #endif /* DEBUG_MODULES */            m4_module_data *data  = XMALLOC (m4_module_data, 1);
303              m4_module_data *stale = 0;
304    
305        module->modname   = xstrdup (modname);            data->bp      = bp;
306        module->handle    = handle;            data->mp      = mp;
       module->bp        = bp;  
       module->mp        = mp;  
       module->ref_count = 1;  
307    
308        m4_modules        = list_cons ((List *) module, m4_modules);            stale = lt_dlcaller_set_data (m4_caller_id, handle, data);
     }  
309    
310    if (module)            if (stale)
311      {              {
312        boolean m4_resident_module                xfree (stale);
313          = (boolean) lt_dlsym (handle, "m4_resident_module");            
314                  M4ERROR ((warning_status, 0,
315                            _("Warning: overiding stale caller data in module `%s'"),
316                            name));
317                }
318    
319        if (m4_resident_module)  #ifdef DEBUG_MODULES
320          {            M4_DEBUG_MESSAGE1("module %s: opened", name);
321            lt_dlmakeresident (handle);  #endif /* DEBUG_MODULES */
322          }          }
323      }      }
324    
325    return module;    return handle;
326  }  }
327    
328  void  void
329  m4_module_install (modname)  m4_module_close (handle, obs)
330       const char *modname;       lt_dlhandle handle;
331         struct obstack *obs;
332  {  {
333    const m4_module *module = m4_module_load (modname, NULL);    m4_module_finish_func *finish_func    = 0;
334      const char            *name           = 0;
335      int                    errors         = 0;
336      
337      assert (handle);
338      name = m4_module_name (handle);
339    
340    if (module)    /* Run any finishing function for the opened module. */
341      {    finish_func = (m4_module_finish_func *) lt_dlsym (handle, M4_FINISH_SYMBOL);
       const m4_builtin *bp      = m4_module_builtins (module);  
       const m4_macro *mp        = m4_module_macros (module);  
342    
343        /* Install the macro functions.  */    if (finish_func)
344        if (bp)      {
345          m4_builtin_table_install (module, bp);        (*finish_func) (handle, obs);
346    
347        /* Install the user macros. */  #ifdef DEBUG_MODULES
348        if (mp)        M4_DEBUG_MESSAGE1("module %s: finish hook called", name);
349          m4_macro_table_install (module, mp);  #endif /* DEBUG_MODULES */
350      }      }
351  }        
352      if (!lt_dlisresident (handle))
353        {
354          {
355            const lt_dlinfo  *info  = lt_dlgetinfo (handle);
356    
357            /* When we are about to unload the module for the final
358               time, be sure to release any client data memory.  */
359            if (info && (info->ref_count == 1))
360              {
361                m4_module_data *stale
362                  = lt_dlcaller_set_data (m4_caller_id, handle, 0);
363                xfree (stale);
364              }
365          }
366    
367  /*        errors = lt_dlclose (handle);
368   * Unload a module.        if (!errors)
  */  
 void  
 m4_module_unload (modname, obs)  
      const char *modname;  
      struct obstack *obs;  
 {  
   m4_module_finish_t *finish_func;  
   int           errors  = 0;  
   lt_dlhandle   handle  = NULL;  
   m4_module    *module  = NULL;  
   List          *cur    = NULL;  
   List          *prev   = NULL;  
   
   /* Scan the list for the first module with a matching modname field. */  
   for (cur = m4_modules; cur != NULL; cur = LIST_NEXT (cur))  
     {  
       module = (m4_module *) cur;  
       if (modname != NULL && strcmp (modname, module->modname) == 0)  
369          {          {
370            handle = module->handle;  #ifdef DEBUG_MODULES
371            break;            M4_DEBUG_MESSAGE1("module %s: closed", name);
372    #endif /* DEBUG_MODULES */
373          }          }
       prev = cur;  
374      }      }
375    
376    if (handle == NULL)    if (errors)
377      {      {
378        M4ERROR ((warning_status, 0,        M4ERROR ((EXIT_FAILURE, 0,
379                  _("ERROR: cannot close module: %s is not loaded."), modname));                  _("ERROR: cannot close module `%s': %s"),
380        return;                  name, m4_module_dlerror ()));
381      }      }
382    }
383    
384    /* Only do the actual unload when the number of calls to unload this  void
385       module is equal to the number of times it was loaded. */  m4_module_close_all (obs)
386    --module->ref_count;       struct obstack *obs;
387    if (module->ref_count > 0)  {
388      {    lt_dlhandle   handle  = lt_dlhandle_next (0);
 #ifdef DEBUG_MODULES  
       M4_DEBUG_MESSAGE2("module %s: now has %d references.",  
                      modname, module->ref_count);  
 #endif /* DEBUG_MODULES */  
       return;  
     }  
389    
390    if (module->ref_count == 0)    while (handle)
391      {      {
392        /* Remove the table references only when ref_count is *exactly* equal        /* Be careful not to reference each handle after it has been
393           to 0.  If m4_module_unload is called again on a resideent module           closed, even to find the address of the next handle.  */
394           after the references have already been removed, we needn't try to        lt_dlhandle pending = handle;
395           remove them again!  */        handle = lt_dlhandle_next (handle);
396        m4_remove_table_reference_symbols (module->bp, module->mp);        m4_module_close (pending, obs);
   
 #ifdef DEBUG_MODULES  
       M4_DEBUG_MESSAGE1("module %s: builtins undefined", modname);  
 #endif /* DEBUG_MODULES */  
397      }      }
398    
399    if (lt_dlisresident (handle))    if (lt_dlexit() != 0)
400      {      {
401        /* Fix up reference count for resident modules, for the next        M4ERROR ((EXIT_FAILURE, 0,
402           call to m4_module_unload(). */                  _("ERROR: cannot close modules: %s"),
403        module->ref_count = 0;                  m4_module_dlerror ()));
404      }      }
405    else  }
     {  
       /* Run the finishing function for the loaded module. */  
       finish_func  
         = (m4_module_finish_t *) lt_dlsym (handle, "m4_finish_module");  
406    
407        if (finish_func != NULL)  lt_dlhandle
408          (*finish_func)();  m4_module_load (name, obs)
409         const char *name;
410         struct obstack *obs;
411    {
412      const lt_dlhandle handle = m4_module_open (name, obs);
413    
414        errors = lt_dlclose (handle);    if (handle)
415        if (errors != 0)      {
416          {        const lt_dlinfo  *info    = lt_dlgetinfo (handle);
           const char *dlerror = lt_dlerror();  
417    
418            if (dlerror == NULL)        if (!info)
419              M4ERROR ((EXIT_FAILURE, 0,          {
420                        _("ERROR: cannot close module: `%s'"), modname));            M4ERROR ((warning_status, 0,
421            else                      _("Warning: cannot load module `%s': %s"),
422              M4ERROR ((EXIT_FAILURE, 0,                      name, m4_module_dlerror ()));
                       _("ERROR: cannot close module: `%s': %s"),  
                       modname, dlerror));  
423          }          }
424        else        else if (info->ref_count == 1)
425          {          {
426              const m4_builtin *bp  = m4_module_builtins (handle);
427              const m4_macro   *mp  = m4_module_macros (handle);
428    
429              /* Install the macro functions.  */
430              if (bp)
431                {
432                  m4_builtin_table_install (handle, bp);
433  #ifdef DEBUG_MODULES  #ifdef DEBUG_MODULES
434            M4_DEBUG_MESSAGE1("module %s unloaded", module->modname);                M4_DEBUG_MESSAGE1("module %s: builtins loaded", name);
435  #endif /* DEBUG_MODULES */  #endif /* DEBUG_MODULES */
436                }
437    
438            if (prev)            /* Install the user macros. */
439              prev->next = (List *) module->next;            if (mp)
440            else              {
441              m4_modules = (List *) module->next;                m4_macro_table_install (handle, mp);
442    #ifdef DEBUG_MODULES
443            xfree (module->modname);                M4_DEBUG_MESSAGE1("module %s: macros loaded", name);
444            xfree (module);  #endif /* DEBUG_MODULES */
445                }
446          }          }
447      }      }
448    
449      return handle;
450  }  }
451    
452    /* Unload a module.  */
453  void  void
454  m4_module_unload_all ()  m4_module_unload (name, obs)
455         const char *name;
456         struct obstack *obs;
457  {  {
458    int errors = 0;    lt_dlhandle   handle  = 0;
459    m4_module *module;    int           errors  = 0;
460    m4_module_finish_t *finish_func;  
461      /* Scan the list for the first module with a matching name.  */
462      while ((handle = lt_dlhandle_next (handle)))
463        {
464          if (name && (strcmp (name, m4_module_name (handle)) == 0))
465            break;
466        }
467    
468    /* Find and run the finishing function for each loaded module. */    if (!handle)
   while (m4_modules != NULL)  
469      {      {
470        module = (m4_module *) m4_modules;        const char *error_msg = _("module not loaded");
471    
472        finish_func = (m4_module_finish_t*)        lt_dlseterror (lt_dladderror (error_msg));
473          lt_dlsym(module->handle, "m4_finish_module");        ++errors;
474        }
475      else
476        {
477          const lt_dlinfo *info = lt_dlgetinfo (handle);
478    
479        if (finish_func != NULL)        /* Only do the actual close when the number of calls to close this
480             module is equal to the number of times it was opened. */
481          if (info->ref_count > 1)
482          {          {
           (*finish_func)();  
   
483  #ifdef DEBUG_MODULES  #ifdef DEBUG_MODULES
484            M4_DEBUG_MESSAGE1("module %s finish hook called", module->modname);            M4_DEBUG_MESSAGE2("module %s: now has %d references.",
485                                name, info->ref_count -1);
486  #endif /* DEBUG_MODULES */  #endif /* DEBUG_MODULES */
487          }          }
488    
489        errors = lt_dlclose (module->handle);        if (info->ref_count == 1)
490        if (errors != 0)          {
491          break;            /* Remove the table references only when ref_count is *exactly*
492                 equal to 1.  If m4_module_close is called again on a
493                 resident module after the references have already been
494                 removed, we needn't try to remove them again!  */
495              m4_remove_table_reference_symbols (m4_module_builtins (handle),
496                                                 m4_module_macros (handle));
497    
498  #ifdef DEBUG_MODULES  #ifdef DEBUG_MODULES
499        M4_DEBUG_MESSAGE1("module %s unloaded", module->modname);            M4_DEBUG_MESSAGE1("module %s: symbols unloaded", name);
500  #endif /* DEBUG_MODULES */  #endif /* DEBUG_MODULES */
   
       m4_modules = LIST_NEXT (m4_modules);  
       xfree(module->modname);  
       xfree(module);  
     }  
   
   if (errors != 0)  
     errors = lt_dlexit();  
   
   if (errors != 0)  
     {  
       const char *dlerror = lt_dlerror();  
       if (m4_modules == NULL)  
         {  
           if (dlerror == NULL)  
             M4ERROR ((EXIT_FAILURE, 0,  
                       _("ERROR: cannot close modules")));  
           else  
             M4ERROR ((EXIT_FAILURE, 0,  
                       _("ERROR: cannot close modules: %s"),  
                       dlerror));  
         }  
       else  
         {  
           if (dlerror == NULL)  
             M4ERROR ((EXIT_FAILURE, 0,  
                       _("ERROR: cannot close module: `%s'"),  
                       module->modname));  
           else  
             M4ERROR ((EXIT_FAILURE, 0,  
                       _("ERROR: cannot close module: `%s': %s"),  
                       module->modname, dlerror));  
501          }          }
502      }      }
503    
504      if (!errors)
505        m4_module_close (handle, obs);
506    
507      if (errors)
508        {
509          M4ERROR ((EXIT_FAILURE, 0,
510                    _("ERROR: cannot unload module `%s': %s"),
511                    name, m4_module_dlerror ()));
512        }
513  }  }

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.5

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26