From aeb92bcb25e253b55650961f341640f93ec3b54e Mon Sep 17 00:00:00 2001 From: "Gary V. Vaughan" Date: Fri, 20 Sep 2013 12:00:02 +0700 Subject: [PATCH] modules: remove support for module unload and refcount. Module management is horrifically more complex than it needs to be for the simple purpose of providing a means to implement new builtins using C. Fussing about reference counting or needing to maintain and test a facility to unload modules is an easy 600 lines to cut as a start at simplification. * src/main.c (main): Don't call m4__module_exit to unload all modules just prior to exiting the application. * m4/m4private.h (FINISH_SYMBOL, m4_module:refcount) (m4__module_exit, m4_module_refcount): Remove. (m4__module_next): Rename from this... * m4/m4module.h (m4_module_next): ...to this. Adjust all callers. (M4FINISH_HANDLER, m4_module_finish_func, m4_module_makeresident) (m4_module_refcount, m4_module_unload, m4_module_exit): Remove. * m4/m4module.c (m4__module_next): Rename from this... (m4_module_next): ...to this. (module_remove, m4_module_makeresident, m4_module_unload) (m4_module_exit, m4_module_refcount): Remove. * modules/load.c: Remove. (m4modules): Move from here... * modules/gnu.c (m4modules): ...to here. Update all callers. (M4FINISH_HANDLER(gnu)): Remove. * modules/m4.c (M4INIT_HANDLER(m4)): Remove. * modules/modtest.c (M4FINISH_HANDLER(modtest)): Remove. * modules/shadow.c (M4INIT_HANDLER(shadow)): Rewrite to work without refcount. * Makefile.am (pkglib_LTLIBRARIES): Remove modules/load.la. (modules_load_la_LDFLAGS, modules_load_la_LIBADD): Remove. * tests/modules.at: Remove references to load module, and tests of unload builtin. * tests/options.at: Remove obsolute finish hook and module unload trace output. * doc/m4.texi (Unload, Refcount): Remove. (M4modules): Change module reference from load to gnu. Signed-off-by: Gary V. Vaughan --- Makefile.am | 4 - doc/m4.texi | 82 ++---------------- m4/builtin.c | 8 +- m4/m4module.h | 17 +--- m4/m4private.h | 10 --- m4/module.c | 229 +++----------------------------------------------- modules/gnu.c | 42 +++++----- modules/load.c | 126 ---------------------------- modules/m4.c | 16 ---- modules/modtest.c | 13 --- modules/shadow.c | 10 ++- src/freeze.c | 4 +- src/main.c | 1 - tests/modules.at | 247 ++++-------------------------------------------------- tests/options.at | 6 -- 15 files changed, 67 insertions(+), 748 deletions(-) delete mode 100644 modules/load.c diff --git a/Makefile.am b/Makefile.am index 7920b9df..e9807a0f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -160,7 +160,6 @@ pkgmodinclude_HEADERS = modules/m4.h pkglib_LTLIBRARIES = \ modules/gnu.la \ - modules/load.la \ modules/m4.la \ modules/traditional.la @@ -169,9 +168,6 @@ modules_gnu_la_LDFLAGS = $(module_ldflags) modules_gnu_la_LIBADD = $(module_libadd) EXTRA_DIST += $(EXTRA_modules_gnu_la_SOURCES) -modules_load_la_LDFLAGS = $(module_ldflags) -modules_load_la_LIBADD = $(module_libadd) - EXTRA_modules_m4_la_SOURCES = modules/evalparse.c modules_m4_la_LDFLAGS = $(module_ldflags) modules_m4_la_LIBADD = $(module_libadd) diff --git a/doc/m4.texi b/doc/m4.texi index 7def990a..77c3a5fe 100644 --- a/doc/m4.texi +++ b/doc/m4.texi @@ -235,8 +235,6 @@ Diverting and undiverting output Extending M4 with dynamic runtime modules * M4modules:: Listing loaded modules -* Unload:: Removing loaded modules -* Refcount:: Tracking module references * Standard Modules:: Standard bundled modules Macros for text handling @@ -6669,8 +6667,8 @@ extensions by configuring the distribution with @kbd{./configure --with-modules=m4}. For a binary built with that option to understand code that uses GNU extensions, you must then run @kbd{m4 gnu}. It is also possible to build a @emph{fatter} binary with additional -modules preloaded: adding, say, the @code{load} module usingr - @kbd{./configure --with-modules="m4 gnu load"}. +modules preloaded: adding, say, the @code{load} module using +@kbd{./configure --with-modules="m4 gnu load"}. GNU M4 now has a facility for defining additional builtins without recompiling the sources. In actual fact, all of the builtins provided @@ -6686,15 +6684,13 @@ two modes of startup. @menu * M4modules:: Listing loaded modules -* Unload:: Removing loaded modules -* Refcount:: Tracking module references * Standard Modules:: Standard bundled modules @end menu @node M4modules @section Listing loaded modules -@deffn {Builtin (load)} m4modules +@deffn {Builtin (gnu)} m4modules Expands to a quoted ordered list of currently loaded modules, with the most recently loaded module at the front of the list. Loading a module multiple times will not affect the order of this list, the @@ -6704,78 +6700,10 @@ position depends on when the module was @emph{first} loaded. For example, if GNU @code{m4} is started with the @option{load} module, @code{m4modules} will yield the following: -@comment options: load - @example -$ @kbd{m4 load -} -m4modules -@result{}load,gnu,m4 -@end example - -@node Unload -@section Removing loaded modules - -@deffn {Builtin (load)} unload (@var{module-name}) -Any loaded modules that can be listed by the @code{m4modules} macro can be -removed by naming them as the @var{module-name} parameter of the -@code{unload} macro. Unloading a module consists of removing all of the -macros it provides from the internal table of visible macros, and -running the module's finalization method (if any). - -The macro @code{unload} is recognized only with parameters. -@end deffn - -@comment options: mpeval load - -@example -$ @kbd{m4 mpeval load -} -m4modules -@result{}load,mpeval,gnu,m4 -unload(`mpeval') -@result{} -m4modules -@result{}load,gnu,m4 -@end example - -@node Refcount -@section Tracking module references - -@deffn {Builtin (load)} refcount (@var{module-name}) -This macro expands to an integer representing the number of times -@var{module-name} has been loaded but not yet unloaded. No warning is -issued, even if @var{module-name} does not represent a valid module. - -The macro @code{refcount} is recognized only with parameters. -@end deffn - -This example demonstrates tracking the reference count of the gnu -module. - -@comment options: load - -@example -$ @kbd{m4 load -} -m4modules -@result{}load,gnu,m4 -refcount(`gnu') -@result{}1 -m4modules -@result{}load,gnu,m4 -include(`gnu') -@result{} -refcount(`gnu') -@result{}2 -unload(`gnu') -@result{} -m4modules -@result{}load,gnu,m4 -refcount(`gnu') -@result{}1 -unload(`gnu') -@result{} +$ @kbd{m4} m4modules -@result{}load,m4 -refcount(`gnu') -@result{}0 -refcount(`NoSuchModule') -@result{}0 +@result{}gnu,m4 @end example @node Standard Modules diff --git a/m4/builtin.c b/m4/builtin.c index 51f636e4..c5107534 100644 --- a/m4/builtin.c +++ b/m4/builtin.c @@ -41,7 +41,7 @@ compare_builtin_name_CB (const void *name, const void *b) m4_symbol_value * M4_GNUC_PURE m4_builtin_find_by_name (m4_module *module, const char *name) { - m4_module *cur = module ? module : m4__module_next (NULL); + m4_module *cur = module ? module : m4_module_next (NULL); m4__builtin *bp; do @@ -55,7 +55,7 @@ m4_builtin_find_by_name (m4_module *module, const char *name) return token; } } - while (!module && (cur = m4__module_next (cur))); + while (!module && (cur = m4_module_next (cur))); return NULL; } @@ -67,7 +67,7 @@ m4_builtin_find_by_name (m4_module *module, const char *name) m4_symbol_value * M4_GNUC_PURE m4_builtin_find_by_func (m4_module *module, m4_builtin_func *func) { - m4_module *cur = module ? module : m4__module_next (NULL); + m4_module *cur = module ? module : m4_module_next (NULL); size_t i; do @@ -81,7 +81,7 @@ m4_builtin_find_by_func (m4_module *module, m4_builtin_func *func) return token; } } - while (!module && (cur = m4__module_next (cur))); + while (!module && (cur = m4_module_next (cur))); return 0; } diff --git a/m4/m4module.h b/m4/m4module.h index 8c249f04..a6bd5139 100644 --- a/m4/m4module.h +++ b/m4/m4module.h @@ -122,17 +122,6 @@ struct m4_string_pair void name ## _LTX_m4_init_module \ (m4 *context, m4_module *module, m4_obstack *obs) -/* Declare a prototype, then begin the implementation of the function - "_LTX_m4_init_module", which will automatically be registered - as the cleanup function for module NAME. Note that NAME is - intentionally used literally, rather than subjected to macro - expansion. */ -#define M4FINISH_HANDLER(name) \ - void name ## _LTX_m4_finish_module \ - (m4 *, m4_module *, m4_obstack *); \ - void name ## _LTX_m4_finish_module \ - (m4 *context, m4_module *module, m4_obstack *obs) - /* Declare a variable S of type "_func" to be a pointer to the function named S imported from the module M, or NULL if the import fails. Note that M and S are intentionally used literally rather @@ -243,17 +232,13 @@ m4_context_opt_bit_table /* --- MODULE MANAGEMENT --- */ typedef void m4_module_init_func (m4 *, m4_module *, m4_obstack *); -typedef void m4_module_finish_func (m4 *, m4_module *, m4_obstack *); extern m4_module * m4_module_load (m4 *, const char *, m4_obstack *); -extern const char * m4_module_makeresident (m4_module *); -extern int m4_module_refcount (const m4_module *); -extern void m4_module_unload (m4 *, const char *, m4_obstack *); extern void * m4_module_import (m4 *, const char *, const char *, m4_obstack *); extern const char * m4_get_module_name (const m4_module *); -extern void m4__module_exit (m4 *); +extern m4_module * m4_module_next (m4_module *); diff --git a/m4/m4private.h b/m4/m4private.h index bffc57b5..29f2bfe9 100644 --- a/m4/m4private.h +++ b/m4/m4private.h @@ -176,13 +176,11 @@ extern void m4__builtin_print (m4_obstack *, const m4__builtin *, bool, #define BUILTIN_SYMBOL "m4_builtin_table" #define MACRO_SYMBOL "m4_macro_table" #define INIT_SYMBOL "m4_init_module" -#define FINISH_SYMBOL "m4_finish_module" /* Representation of a loaded m4 module. */ struct m4_module { lt_dlhandle handle; /* All ltdl module information. */ - int refcount; /* Count of loads not matched by unload. */ m4__builtin *builtins; /* Sorted array of builtins. */ size_t builtins_len; /* Number of builtins. */ }; @@ -190,16 +188,8 @@ struct m4_module extern void m4__module_init (m4 *context); extern m4_module * m4__module_open (m4 *context, const char *name, m4_obstack *obs); -extern void m4__module_exit (m4 *context); -extern m4_module * m4__module_next (m4_module *); extern m4_module * m4__module_find (const char *name); -/* Fast macro versions of symbol table accessor functions, that also - have an identically named function exported in m4module.h. */ -#ifdef NDEBUG -# define m4_module_refcount(M) ((M)->refcount) -#endif - /* --- SYMBOL TABLE MANAGEMENT --- */ diff --git a/m4/module.c b/m4/module.c index ec2913ad..ebedcffe 100644 --- a/m4/module.c +++ b/m4/module.c @@ -63,25 +63,12 @@ * Each time a module is loaded, the module function prototyped as * "M4INIT_HANDLER ()" is called, if defined. Any value * stored in OBS by this function becomes the expansion of the macro - * which called it. Before M4 exits, all modules are unloaded and the - * function prototyped as "M4FINISH_HANDLER ()" is called, - * if defined. It is safe to load the same module several times: the - * init and finish functions will also be called multiple times in this - * case. - * - * To unload a module, use m4_module_unload(). which uses - * m4__symtab_remove_module_references() to remove the builtins defined by - * the unloaded module from the symbol table. If the module has been - * loaded several times with calls to m4_module_load, then the module will - * not be unloaded until the same number of calls to m4_module_unload() - * have been made (nor will the symbol table be purged). + * which called it. **/ #define MODULE_SELF_NAME "!myself!" static const char* module_dlerror (void); -static int module_remove (m4 *context, m4_module *module, - m4_obstack *obs); static void install_builtin_table (m4*, m4_module *); static void install_macro_table (m4*, m4_module *); @@ -196,55 +183,20 @@ m4_module_load (m4 *context, const char *name, m4_obstack *obs) { m4_module *module = m4__module_open (context, name, obs); - if (module && module->refcount == 1) - { - install_builtin_table (context, module); - install_macro_table (context, module); - } - - return module; -} - -/* Make the module MODULE resident. Return NULL on success, or a - pre-translated error string on failure. */ -const char * -m4_module_makeresident (m4_module *module) -{ - assert (module); - return lt_dlmakeresident (module->handle) ? module_dlerror () : NULL; -} - -/* Unload a module. */ -void -m4_module_unload (m4 *context, const char *name, m4_obstack *obs) -{ - m4_module * module = NULL; - int errors = 0; - - assert (context); - - if (name) - module = m4__module_find (name); - - if (!module) + if (module) { - const char *error_msg = _("module not loaded"); + const lt_dlinfo *info = lt_dlgetinfo (module->handle); - lt_dlseterror (lt_dladderror (error_msg)); - ++errors; + if (info->ref_count == 1) + { + install_builtin_table (context, module); + install_macro_table (context, module); + } } - else - errors = module_remove (context, module, obs); - if (errors) - { - m4_error (context, EXIT_FAILURE, 0, NULL, - _("cannot unload module `%s': %s"), - name ? name : MODULE_SELF_NAME, module_dlerror ()); - } + return module; } - static int m4__module_interface (lt_dlhandle handle, const char *id_string) @@ -258,7 +210,6 @@ m4__module_interface (lt_dlhandle handle, const char *id_string) /* A valid m4 module must provide at least one of these symbols. */ return !(lt_dlsym (handle, INIT_SYMBOL) - || lt_dlsym (handle, FINISH_SYMBOL) || lt_dlsym (handle, BUILTIN_SYMBOL) || lt_dlsym (handle, MACRO_SYMBOL)); } @@ -267,7 +218,7 @@ m4__module_interface (lt_dlhandle handle, const char *id_string) /* Return successive loaded modules that pass the interface test registered with the interface id. */ m4_module * -m4__module_next (m4_module *module) +m4_module_next (m4_module *module) { lt_dlhandle handle = module ? module->handle : NULL; assert (iface_id); @@ -482,7 +433,6 @@ m4__module_open (m4 *context, const char *name, m4_obstack *obs) /* Find and run any initializing function in the opened module, each time the module is opened. */ - module->refcount++; init_func = (m4_module_init_func *) lt_dlsym (handle, INIT_SYMBOL); if (init_func) { @@ -491,8 +441,7 @@ m4__module_open (m4 *context, const char *name, m4_obstack *obs) m4_debug_message (context, M4_DEBUG_TRACE_MODULE, _("module %s: init hook called"), name); } - else if (!lt_dlsym (handle, FINISH_SYMBOL) - && !lt_dlsym (handle, BUILTIN_SYMBOL) + else if (!lt_dlsym (handle, BUILTIN_SYMBOL) && !lt_dlsym (handle, MACRO_SYMBOL)) { m4_error (context, EXIT_FAILURE, 0, NULL, @@ -512,39 +461,6 @@ m4__module_open (m4 *context, const char *name, m4_obstack *obs) return module; } -void -m4__module_exit (m4 *context) -{ - m4_module * module = m4__module_next (NULL); - int errors = 0; - - while (module && !errors) - { - m4_module *pending = module; - - /* If we are about to unload the final reference, move on to the - next module before we unload the current one. */ - if (pending->refcount <= 1) - module = m4__module_next (module); - - errors = module_remove (context, pending, NULL); - } - - assert (iface_id); /* need to have called m4__module_init */ - lt_dlinterface_free (iface_id); - iface_id = NULL; - - if (!errors) - errors = lt_dlexit (); - - if (errors) - { - m4_error (context, EXIT_FAILURE, 0, NULL, - _("cannot unload all modules: %s"), module_dlerror ()); - } -} - - /* FIXME - libtool doesn't expose lt_dlerror strings for translation. */ static const char * @@ -557,126 +473,3 @@ module_dlerror (void) return dlerror; } - -/* Close one reference to the module MODULE, and output to OBS any - information from the finish hook of the module. If no references - to MODULE remain, also remove all symbols and other memory - associated with the module. */ -static int -module_remove (m4 *context, m4_module *module, m4_obstack *obs) -{ - const lt_dlinfo * info; - int errors = 0; - const char * name; - lt_dlhandle handle; - bool last_reference = false; - bool resident = false; - m4_module_finish_func * finish_func; - - assert (module && module->handle); - - /* Be careful when closing myself. */ - handle = module->handle; - name = m4_get_module_name (module); - name = xstrdup (name ? name : MODULE_SELF_NAME); - - info = lt_dlgetinfo (handle); - resident = info->is_resident; - - /* Only do the actual close when the number of calls to close this - module is equal to the number of times it was opened. */ -#ifdef DEBUG_MODULES - if (info->ref_count > 1) - { - xfprintf (stderr, "module %s: now has %d libtool references.", - name, info->ref_count - 1); - } -#endif /* DEBUG_MODULES */ - - if (module->refcount-- == 1) - { - /* Remove the table references only when ref_count is *exactly* - equal to 1. If module_close is called again on a - resident module after the references have already been - removed, we needn't try to remove them again! */ - m4__symtab_remove_module_references (M4SYMTAB, module); - - m4_debug_message (context, M4_DEBUG_TRACE_MODULE, - _("module %s: symbols unloaded"), name); - last_reference = true; - } - - finish_func = (m4_module_finish_func *) lt_dlsym (handle, FINISH_SYMBOL); - if (finish_func) - { - finish_func (context, module, obs); - - m4_debug_message (context, M4_DEBUG_TRACE_MODULE, - _("module %s: finish hook called"), name); - } - - if (last_reference && resident) - { - /* Special case when closing last reference to resident module - - we need to remove the association of the m4_module wrapper - with the dlhandle, because we are about to free the wrapper, - but the module will still show up in lt_dlhandle_iterate. - Still call lt_dlclose to reduce the ref count, but ignore the - failure about not closing a resident module. */ - void *old = lt_dlcaller_set_data (iface_id, handle, NULL); - if (!old) - m4_error (context, EXIT_FAILURE, 0, NULL, - _("unable to close module `%s': %s"), name, - module_dlerror()); - assert (old == module); - lt_dlclose (handle); - m4_debug_message (context, M4_DEBUG_TRACE_MODULE, - _("module %s: resident module not closed"), name); - } - else - { - errors = lt_dlclose (handle); - /* Ignore the error expected if the module was resident. */ - if (resident) - errors = 0; - if (!errors) - { - m4_debug_message (context, M4_DEBUG_TRACE_MODULE, - _("module %s: closed"), name); - } - } - - if (errors) - m4_error (context, EXIT_FAILURE, 0, NULL, - _("cannot close module `%s': %s"), name, module_dlerror ()); - if (last_reference) - { - size_t i; - for (i = 0; i < module->builtins_len; i++) - DELETE (module->builtins[i].builtin.name); - free (module->builtins); - free (module); - } - - DELETE (name); - - return errors; -} - - -/* Below here are the accessor functions behind fast macros. Declare - them last, so the rest of the file can use the macros. */ - -/* Return the current refcount, or times that module MODULE has been - opened. */ -#undef m4_module_refcount -int -m4_module_refcount (const m4_module *module) -{ - const lt_dlinfo *info; - assert (module); - info = lt_dlgetinfo (module->handle); - assert (info); - assert (module->refcount <= info->ref_count); - return module->refcount; -} diff --git a/modules/gnu.c b/modules/gnu.c index c69862e8..ae3024f7 100644 --- a/modules/gnu.c +++ b/modules/gnu.c @@ -58,6 +58,7 @@ BUILTIN (patsubst, false, true, true, 2, 4 ) \ BUILTIN (regexp, false, true, true, 2, 4 ) \ BUILTIN (renamesyms, false, true, false, 2, 3 ) \ + BUILTIN (m4modules, false, false, false, 0, 0 ) \ BUILTIN (m4symbols, true, false, false, 0, -1 ) \ BUILTIN (syncoutput, false, true, false, 1, 1 ) \ @@ -352,25 +353,6 @@ regexp_substitute (m4 *context, m4_obstack *obs, const m4_call_info *caller, } -/* Reclaim memory used by this module. */ -M4FINISH_HANDLER(gnu) -{ - int i; - for (i = 0; i < REGEX_CACHE_SIZE; i++) - if (regex_cache[i].str) - { - free (regex_cache[i].str); - regfree (regex_cache[i].pat); - free (regex_cache[i].pat); - free (regex_cache[i].regs.start); - free (regex_cache[i].regs.end); - } - /* If this module was preloaded, then we need to explicitly reset - the memory in case it gets reloaded. */ - memset (®ex_cache, 0, sizeof regex_cache); -} - - /** * __file__ @@ -1016,6 +998,28 @@ M4BUILTIN_HANDLER (renamesyms) } +/** + * m4modules() + **/ +M4BUILTIN_HANDLER (m4modules) +{ + /* The expansion of this builtin is a comma separated list of + loaded modules. */ + m4_module *module = m4_module_next (NULL); + + if (module) + do + { + m4_shipout_string (context, obs, m4_get_module_name (module), SIZE_MAX, + true); + + if ((module = m4_module_next (module))) + obstack_1grow (obs, ','); + } + while (module); +} + + /* Implementation of "m4symbols". It builds up a table of pointers to symbols, sorts it and ships out the symbol names. */ diff --git a/modules/load.c b/modules/load.c deleted file mode 100644 index 0b0eb1be..00000000 --- a/modules/load.c +++ /dev/null @@ -1,126 +0,0 @@ -/* GNU m4 -- A simple macro processor - Copyright (C) 2000, 2005-2008, 2010, 2013 Free Software Foundation, - Inc. - - This file is part of GNU M4. - - GNU M4 is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - GNU M4 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include - -/* This module needs private symbols, and may not compile correctly if - m4private.h isn't included. */ -#include "m4private.h" - - -/* Rename exported symbols for dlpreload()ing. */ -#define m4_builtin_table load_LTX_m4_builtin_table -#define m4_macro_table load_LTX_m4_macro_table - - -/* Maintain each of the builtins implemented in this modules along - with their details in a single table for easy maintenance. - - function macros blind side minargs maxargs */ -#define builtin_functions \ - BUILTIN (m4modules, false, false, false, 0, 0 ) \ - BUILTIN (refcount, false, true, false, 1, 1 ) \ - BUILTIN (unload, false, true, false, 1, 1 ) \ - - -/* Generate prototypes for each builtin handler function. */ -#define BUILTIN(handler, macros, blind, side, min, max) M4BUILTIN (handler) - builtin_functions -#undef BUILTIN - - -/* Generate a table for mapping m4 symbol names to handler functions. */ -const m4_builtin m4_builtin_table[] = -{ -#define BUILTIN(handler, macros, blind, side, min, max) \ - M4BUILTIN_ENTRY (handler, #handler, macros, blind, side, min, max) - - builtin_functions -#undef BUILTIN - - { NULL, NULL, 0, 0, 0 }, -}; - - -/* A table for mapping m4 symbol names to simple expansion text. */ -const m4_macro m4_macro_table[] = -{ - /* name text min max */ - { "__load__", "", 0, 0 }, - { NULL, NULL, 0, 0 }, -}; - - -/* This module cannot be safely unloaded from memory, incase the unload - is triggered by the unload builtin, and the module is removed while - unload is in progress. */ -M4INIT_HANDLER (load) -{ - const char *err = m4_module_makeresident (module); - if (err) - m4_error (context, 0, 0, NULL, _("cannot make module `%s' resident: %s"), - m4_get_module_name (module), err); -} - - - -/* Loading an external module at runtime. - The following functions provide the implementation for each - of the m4 builtins declared in `m4_builtin_table[]' above. */ - -/** - * m4modules() - **/ -M4BUILTIN_HANDLER (m4modules) -{ - /* The expansion of this builtin is a comma separated list of - loaded modules. */ - m4_module *module = m4__module_next (NULL); - - if (module) - do - { - m4_shipout_string (context, obs, m4_get_module_name (module), SIZE_MAX, - true); - - if ((module = m4__module_next (module))) - obstack_1grow (obs, ','); - } - while (module); -} - -/** - * refcount(module) - **/ -M4BUILTIN_HANDLER (refcount) -{ - m4_module *module = m4__module_find (M4ARG (1)); - m4_shipout_int (obs, module ? m4_module_refcount (module) : 0); -} - -/** - * unload(MODULE-NAME) - **/ -M4BUILTIN_HANDLER (unload) -{ - /* Remove all builtins and macros installed by the named module, - and then unload the module from memory entirely. */ - m4_module_unload (context, M4ARG(1), obs); -} diff --git a/modules/m4.c b/modules/m4.c index 64abdae0..f9449fe0 100644 --- a/modules/m4.c +++ b/modules/m4.c @@ -128,19 +128,6 @@ const m4_builtin m4_builtin_table[] = -/* This module cannot be safely unloaded from memory, incase the unload - is triggered by m4exit, and the module is removed while m4exit is in - progress. */ -M4INIT_HANDLER (m4) -{ - const char *err = m4_module_makeresident (module); - if (err) - m4_error (context, 0, 0, NULL, _("cannot make module `%s' resident: %s"), - m4_get_module_name (module), err); -} - - - /* The rest of this file is code for builtins and expansion of user defined macros. All the functions for builtins have a prototype as: @@ -840,9 +827,6 @@ M4BUILTIN_HANDLER (m4exit) if (exit_code != EXIT_SUCCESS) m4_set_exit_failure (exit_code); - /* Ensure any module exit callbacks are executed. */ - m4__module_exit (context); - /* Change debug stream back to stderr, to force flushing debug stream and detect any errors. */ m4_debug_set_output (context, me, NULL); diff --git a/modules/modtest.c b/modules/modtest.c index 5febf086..385049b4 100644 --- a/modules/modtest.c +++ b/modules/modtest.c @@ -80,19 +80,6 @@ M4INIT_HANDLER (modtest) /** - * modtest() - **/ -M4FINISH_HANDLER (modtest) -{ - const char *s = "Test module unloaded.\n"; - - /* Don't depend on OBS so that the traces are the same when used - directly, or via a frozen file. */ - fputs (s, stderr); -} - - -/** * test() **/ M4BUILTIN_HANDLER (test) diff --git a/modules/shadow.c b/modules/shadow.c index 16260f12..529425c4 100644 --- a/modules/shadow.c +++ b/modules/shadow.c @@ -64,12 +64,16 @@ const m4_macro m4_macro_table[] = M4INIT_HANDLER (shadow) { + static bool loaded = false; + const char *s = "Shadow module loaded."; - int refcount = m4_module_refcount (module); /* Only display the message on first load. */ - if (obs && refcount == 1) - obstack_grow (obs, s, strlen (s)); + if (obs && !loaded) + { + loaded = true; + obstack_grow (obs, s, strlen (s)); + } } diff --git a/src/freeze.c b/src/freeze.c index 9f36e8cc..5ac913d8 100644 --- a/src/freeze.c +++ b/src/freeze.c @@ -156,7 +156,7 @@ produce_module_dump (FILE *file, m4_module *module) const char *name = m4_get_module_name (module); size_t len = strlen (name); - module = m4__module_next (module); + module = m4_module_next (module); if (module) produce_module_dump (file, module); @@ -322,7 +322,7 @@ produce_frozen_state (m4 *context, const char *name) produce_debugmode_state (file, m4_get_debug_level_opt (context)); /* Dump all loaded modules. */ - produce_module_dump (file, m4__module_next (NULL)); + produce_module_dump (file, m4_module_next (NULL)); /* Dump all symbols. */ produce_symbol_dump (context, file, M4SYMTAB); diff --git a/src/main.c b/src/main.c index 1e3e706f..53305451 100644 --- a/src/main.c +++ b/src/main.c @@ -744,7 +744,6 @@ main (int argc, char *const *argv, char *const *envp) Strictly, we don't need to do this, but it makes leak detection a whole lot easier! */ - m4__module_exit (context); m4_output_exit (); m4_input_exit (); diff --git a/tests/modules.at b/tests/modules.at index 623f531d..dddba9ee 100644 --- a/tests/modules.at +++ b/tests/modules.at @@ -51,14 +51,14 @@ test3 # First generate the `expout' ouput by running over the sources before # freezing. -AT_CHECK_M4([-I "$abs_builddir" load frozen.m4 unfrozen.m4], +AT_CHECK_M4([-I "$abs_builddir" frozen.m4 unfrozen.m4], [0], [stdout], [stderr]) mv stdout expout mv stderr experr # Now freeze the first source file. -AT_CHECK_M4([-I "$abs_builddir" load -F frozen.m4f frozen.m4], +AT_CHECK_M4([-I "$abs_builddir" -F frozen.m4f frozen.m4], [0], [], [ignore]) # Now rerun the original sequence, but using the frozen file. @@ -68,33 +68,6 @@ AT_CHECK_M4([-I "$abs_builddir" -R frozen.m4f unfrozen.m4], AT_CLEANUP([frozen.m4f]) -## ------------------ ## -## module test macros ## -## ------------------ ## - -AT_SETUP([module test macros]) -AT_CHECK_DYNAMIC_MODULE -AT_CHECK_GMP - -AT_DATA([in], [[include(`mpeval') --__load__-__mpeval__- -unload(`mpeval') --__load__-__mpeval__- -unload(`load') --__load__-__mpeval__- -]]) - -AT_CHECK_M4([load in], [0], [[ ---- - ---__mpeval__- - --__load__-__mpeval__- -]]) - -AT_CLEANUP - - ## ---------------------------- ## ## Exercising the test module. ## ## ---------------------------- ## @@ -108,10 +81,9 @@ m4_define([AT_CHECK_M4_MODTEST], AT_CHECK_DYNAMIC_MODULE AT_DATA([input.m4], -[[include(`modtest') -test +[[test Dumpdef: dumpdef(`test'). -unload(`modtest') +include(`modtest') test Dumpdef: dumpdef(`test'). ]]) @@ -122,18 +94,16 @@ dnl carry over to the next AT_SETUP. m4_ifval([$2], [$2 export m4_substr([$2], [0], m4_index([$2], [=]))]) -AT_CHECK_M4([load $3 input.m4], [0], -[[ -Test module called. +AT_CHECK_M4([$3 input.m4], [0], +[[test Dumpdef: . -test +Test module called. Dumpdef: . ]], -[[Test module loaded. +[[m4:input.m4:2: warning: dumpdef: undefined macro 'test' +Test module loaded. test: -Test module unloaded. -m4:input.m4:6: warning: dumpdef: undefined macro 'test' ]]) AT_CLEANUP @@ -196,26 +166,6 @@ dumpdef(`test') dumpdef(`shadow') test shadow - -# Unloading Modtest will unshadow the test definition in Shadow -unload(`modtest') -dumpdef(`test') -dumpdef(`shadow') -test -shadow - -# Unloading Shadow once has no effect (we loaded it twice) -unload(`shadow') -dumpdef(`test') -dumpdef(`shadow') -test -shadow - -# Unloading Shadow again will revert to copying `test' and the local -# `shadow' macro. -unload(`shadow') -test -shadow ]]) AT_DATA([[expout]], @@ -252,26 +202,6 @@ Shadow::shadow called. Test module called. Shadow::shadow called. - -# Unloading Modtest will unshadow the test definition in Shadow - - - -Shadow::test called. -Shadow::shadow called. - -# Unloading Shadow once has no effect (we loaded it twice) - - - -Shadow::test called. -Shadow::shadow called. - -# Unloading Shadow again will revert to copying `test' and the local -# `shadow' macro. - -local::test -local::shadow ]]) AT_DATA([[experr]], @@ -282,88 +212,15 @@ test: shadow: test: shadow: -Test module unloaded. -test: -shadow: -test: -shadow: ]]) -AT_CHECK_M4([-I "$abs_builddir" load input.m4], [0], +AT_CHECK_M4([-I "$abs_builddir" input.m4], [0], [expout], [experr]) AT_CLEANUP -## ------ ## -## unload ## -## ------ ## - -AT_SETUP([modules: unload]) -AT_CHECK_DYNAMIC_MODULE - -AT_DATA([[input.m4]], -[[test -__test__ -include(`modtest') -test -__test__ -include(`shadow') -test -__test__ -unload(`modtest') -test -__test__ -include(`modtest') -test -__test__ -unload(`modtest') -test -__test__ -unload(`shadow') -test -__test__ -]]) - -AT_DATA([[expout]], -[[test -__test__ - -Test module called. -modtest -Shadow module loaded. -Shadow::test called. -shadow - -Shadow::test called. -shadow - -Test module called. -modtest - -Shadow::test called. -shadow - -test -__test__ -]]) - -AT_DATA([[experr]], -[[Test module loaded. -Test module unloaded. -Test module loaded. -Test module unloaded. -]]) - - -AT_CHECK_M4([-I "$abs_builddir" load input.m4], - [0], [expout], [experr]) - -AT_CLEANUP - - - ## ----------------------- ## ## module symbol importing ## ## ----------------------- ## @@ -382,7 +239,6 @@ AT_DATA([[input.m4]], [[import include(`import') import -unload(`modtest') import symbol_fail module_fail @@ -392,7 +248,6 @@ AT_DATA([[expout]], [[import import::import called. - import::import called. import::symbol_fail called. ]]) @@ -401,17 +256,15 @@ AT_DATA([[experr]], [[Test module loaded. TRUE -Test module unloaded. -Test module loaded. TRUE -m4:input.m4:6: cannot load symbol `no_such' from module `modtest' -m4:input.m4:7: cannot open module `no_such' +m4:input.m4:5: cannot load symbol `no_such' from module `modtest' +m4:input.m4:6: cannot open module `no_such' ]]) ls "$abs_builddir" -AT_CHECK_M4([-I "$abs_builddir" load input.m4], +AT_CHECK_M4([-I "$abs_builddir" input.m4], [1], [expout], [experr]) AT_CLEANUP @@ -454,7 +307,6 @@ m4:input.m4:2: warning: __test__: extra arguments ignored: 1 > 0 m4:input.m4:3: warning: __test__: extra arguments ignored: 2 > 0 m4:input.m4:4: warning: onearg: too few arguments: 0 < 1 m4:input.m4:6: warning: onearg: extra arguments ignored: 2 > 1 -Test module unloaded. ]]) AT_CLEANUP @@ -474,8 +326,6 @@ AT_DATA([[input.m4]], [[test include(`shadow') test -unload(`shadow') -test include(`shadow') test ]]) @@ -485,8 +335,6 @@ AT_DATA([[expout]], Shadow module loaded. Shadow::test called. -test -Shadow module loaded. Shadow::test called. ]]) @@ -496,74 +344,7 @@ m4trace: -1- test -> `Shadow::`test' called.' ]]) -AT_CHECK_M4([-I "$abs_builddir" load -t test input.m4], +AT_CHECK_M4([-I "$abs_builddir" -t test input.m4], [0], [expout], [experr]) AT_CLEANUP - - -## ----------------- ## -## unload gnu module ## -## ----------------- ## - -AT_SETUP([unload gnu module]) -AT_CHECK_DYNAMIC_MODULE - -dnl Ensure that the gnu module does not leak memory. I don't know how -dnl to portably artificially limit the heap to cause an out-of-memory -dnl condition in the case of a leak, but examining the run of this test -dnl in a debugger can show whether it is leaking. -AT_DATA([input.m4], [[divert(-1) -define(`forloop', - `pushdef(`$1', `$2')_forloop(`$1', `$2', `$3', `$4')popdef(`$1')') -define(`_forloop', - `$4`'ifelse($1, `$3', `', - `define(`$1', incr($1))_forloop(`$1', `$2', `$3', `$4')')') -forloop(`i', `1', `5000', `unload(`gnu')include(`gnu')regexp(`123', `\(4\)?2')') -]]) - -AT_CHECK_M4([load input.m4], [0]) - -AT_CLEANUP - - -## ------------------ ## -## unload load module ## -## ------------------ ## - -AT_SETUP([unload load module]) -AT_CHECK_DYNAMIC_MODULE - -dnl Ensure that the load module can be unloaded and reloaded (obviously, -dnl it can't reload itself; the reload occurs on the command line). Since -dnl the module must be resident (after all, the `unload' builtin had better -dnl not unmap the memory for the code it is currently executing), make sure -dnl that resident modules are handled gracefully. -AT_DATA([in1.m4], [[__load__ 1 -unload(`load') 2 -__load__ 3 -]]) - -AT_DATA([in2.m4], [[__load__ 4 -include(`load') 5 -__load__ 6 -unload(`load') 7 -__load__ 8 -unload(`load') 9 -__load__ 10 -]]) - -AT_CHECK_M4([load in1.m4 load in2.m4], [0], -[[ 1 - 2 -__load__ 3 - 4 - 5 - 6 - 7 - 8 - 9 -__load__ 10 -]]) - -AT_CLEANUP diff --git a/tests/options.at b/tests/options.at index 921c6fe5..5848fa80 100644 --- a/tests/options.at +++ b/tests/options.at @@ -423,7 +423,6 @@ dnl Test all flags. AT_CHECK_M4([-dV in], [0], [[3 0 ]], [[m4debug: module m4: opening file -m4debug: module m4: init hook called m4debug: module m4: opened m4debug: module m4: builtins loaded m4debug: module gnu: opening file @@ -451,11 +450,6 @@ m4debug: input from m4wrap recursion level 1 m4trace:nested:1: -1- id 6: divnum ... = {m4} m4trace:nested:1: -1- id 6: divnum -> `0' m4debug: input from m4wrap exhausted -m4debug: module gnu: symbols unloaded -m4debug: module gnu: finish hook called -m4debug: module gnu: closed -m4debug: module m4: symbols unloaded -m4debug: module m4: resident module not closed ]]) dnl Test addition and subtraction of flags. -- 2.11.4.GIT