Mercurial > hg > xemacs-beta
view src/emodules.c @ 5127:a9c41067dd88 ben-lisp-object
more cleanups, terminology clarification, lots of doc work
-------------------- ChangeLog entries follow: --------------------
man/ChangeLog addition:
2010-03-05 Ben Wing <ben@xemacs.org>
* internals/internals.texi (Introduction to Allocation):
* internals/internals.texi (Integers and Characters):
* internals/internals.texi (Allocation from Frob Blocks):
* internals/internals.texi (lrecords):
* internals/internals.texi (Low-level allocation):
Rewrite section on allocation of Lisp objects to reflect the new
reality. Remove references to nonexistent XSETINT and XSETCHAR.
modules/ChangeLog addition:
2010-03-05 Ben Wing <ben@xemacs.org>
* postgresql/postgresql.c (allocate_pgconn):
* postgresql/postgresql.c (allocate_pgresult):
* postgresql/postgresql.h (struct Lisp_PGconn):
* postgresql/postgresql.h (struct Lisp_PGresult):
* ldap/eldap.c (allocate_ldap):
* ldap/eldap.h (struct Lisp_LDAP):
Same changes as in src/ dir. See large log there in ChangeLog,
but basically:
ALLOC_LISP_OBJECT -> ALLOC_NORMAL_LISP_OBJECT
LISP_OBJECT_HEADER -> NORMAL_LISP_OBJECT_HEADER
../hlo/src/ChangeLog addition:
2010-03-05 Ben Wing <ben@xemacs.org>
* alloc.c:
* alloc.c (old_alloc_sized_lcrecord):
* alloc.c (very_old_free_lcrecord):
* alloc.c (copy_lisp_object):
* alloc.c (zero_sized_lisp_object):
* alloc.c (zero_nonsized_lisp_object):
* alloc.c (lisp_object_storage_size):
* alloc.c (free_normal_lisp_object):
* alloc.c (FREE_FIXED_TYPE_WHEN_NOT_IN_GC):
* alloc.c (ALLOC_FROB_BLOCK_LISP_OBJECT):
* alloc.c (Fcons):
* alloc.c (noseeum_cons):
* alloc.c (make_float):
* alloc.c (make_bignum):
* alloc.c (make_bignum_bg):
* alloc.c (make_ratio):
* alloc.c (make_ratio_bg):
* alloc.c (make_ratio_rt):
* alloc.c (make_bigfloat):
* alloc.c (make_bigfloat_bf):
* alloc.c (size_vector):
* alloc.c (make_compiled_function):
* alloc.c (Fmake_symbol):
* alloc.c (allocate_extent):
* alloc.c (allocate_event):
* alloc.c (make_key_data):
* alloc.c (make_button_data):
* alloc.c (make_motion_data):
* alloc.c (make_process_data):
* alloc.c (make_timeout_data):
* alloc.c (make_magic_data):
* alloc.c (make_magic_eval_data):
* alloc.c (make_eval_data):
* alloc.c (make_misc_user_data):
* alloc.c (Fmake_marker):
* alloc.c (noseeum_make_marker):
* alloc.c (size_string_direct_data):
* alloc.c (make_uninit_string):
* alloc.c (make_string_nocopy):
* alloc.c (mark_lcrecord_list):
* alloc.c (alloc_managed_lcrecord):
* alloc.c (free_managed_lcrecord):
* alloc.c (sweep_lcrecords_1):
* alloc.c (malloced_storage_size):
* buffer.c (allocate_buffer):
* buffer.c (compute_buffer_usage):
* buffer.c (DEFVAR_BUFFER_LOCAL_1):
* buffer.c (nuke_all_buffer_slots):
* buffer.c (common_init_complex_vars_of_buffer):
* buffer.h (struct buffer_text):
* buffer.h (struct buffer):
* bytecode.c:
* bytecode.c (make_compiled_function_args):
* bytecode.c (size_compiled_function_args):
* bytecode.h (struct compiled_function_args):
* casetab.c (allocate_case_table):
* casetab.h (struct Lisp_Case_Table):
* charset.h (struct Lisp_Charset):
* chartab.c (fill_char_table):
* chartab.c (Fmake_char_table):
* chartab.c (make_char_table_entry):
* chartab.c (copy_char_table_entry):
* chartab.c (Fcopy_char_table):
* chartab.c (put_char_table):
* chartab.h (struct Lisp_Char_Table_Entry):
* chartab.h (struct Lisp_Char_Table):
* console-gtk-impl.h (struct gtk_device):
* console-gtk-impl.h (struct gtk_frame):
* console-impl.h (struct console):
* console-msw-impl.h (struct Lisp_Devmode):
* console-msw-impl.h (struct mswindows_device):
* console-msw-impl.h (struct msprinter_device):
* console-msw-impl.h (struct mswindows_frame):
* console-msw-impl.h (struct mswindows_dialog_id):
* console-stream-impl.h (struct stream_console):
* console-stream.c (stream_init_console):
* console-tty-impl.h (struct tty_console):
* console-tty-impl.h (struct tty_device):
* console-tty.c (allocate_tty_console_struct):
* console-x-impl.h (struct x_device):
* console-x-impl.h (struct x_frame):
* console.c (allocate_console):
* console.c (nuke_all_console_slots):
* console.c (DEFVAR_CONSOLE_LOCAL_1):
* console.c (common_init_complex_vars_of_console):
* data.c (make_weak_list):
* data.c (make_weak_box):
* data.c (make_ephemeron):
* database.c:
* database.c (struct Lisp_Database):
* database.c (allocate_database):
* database.c (finalize_database):
* device-gtk.c (allocate_gtk_device_struct):
* device-impl.h (struct device):
* device-msw.c:
* device-msw.c (mswindows_init_device):
* device-msw.c (msprinter_init_device):
* device-msw.c (finalize_devmode):
* device-msw.c (allocate_devmode):
* device-tty.c (allocate_tty_device_struct):
* device-x.c (allocate_x_device_struct):
* device.c:
* device.c (nuke_all_device_slots):
* device.c (allocate_device):
* dialog-msw.c (handle_question_dialog_box):
* elhash.c:
* elhash.c (struct Lisp_Hash_Table):
* elhash.c (finalize_hash_table):
* elhash.c (make_general_lisp_hash_table):
* elhash.c (Fcopy_hash_table):
* elhash.h (htentry):
* emacs.c (main_1):
* eval.c:
* eval.c (size_multiple_value):
* event-stream.c (finalize_command_builder):
* event-stream.c (allocate_command_builder):
* event-stream.c (free_command_builder):
* event-stream.c (event_stream_generate_wakeup):
* event-stream.c (event_stream_resignal_wakeup):
* event-stream.c (event_stream_disable_wakeup):
* event-stream.c (event_stream_wakeup_pending_p):
* events.h (struct Lisp_Timeout):
* events.h (struct command_builder):
* extents-impl.h:
* extents-impl.h (struct extent_auxiliary):
* extents-impl.h (struct extent_info):
* extents-impl.h (set_extent_no_chase_aux_field):
* extents-impl.h (set_extent_no_chase_normal_field):
* extents.c:
* extents.c (gap_array_marker):
* extents.c (gap_array):
* extents.c (extent_list_marker):
* extents.c (extent_list):
* extents.c (stack_of_extents):
* extents.c (gap_array_make_marker):
* extents.c (extent_list_make_marker):
* extents.c (allocate_extent_list):
* extents.c (SLOT):
* extents.c (mark_extent_auxiliary):
* extents.c (allocate_extent_auxiliary):
* extents.c (attach_extent_auxiliary):
* extents.c (size_gap_array):
* extents.c (finalize_extent_info):
* extents.c (allocate_extent_info):
* extents.c (uninit_buffer_extents):
* extents.c (allocate_soe):
* extents.c (copy_extent):
* extents.c (vars_of_extents):
* extents.h:
* faces.c (allocate_face):
* faces.h (struct Lisp_Face):
* faces.h (struct face_cachel):
* file-coding.c:
* file-coding.c (finalize_coding_system):
* file-coding.c (sizeof_coding_system):
* file-coding.c (Fcopy_coding_system):
* file-coding.h (struct Lisp_Coding_System):
* file-coding.h (MARKED_SLOT):
* fns.c (size_bit_vector):
* font-mgr.c:
* font-mgr.c (finalize_fc_pattern):
* font-mgr.c (print_fc_pattern):
* font-mgr.c (Ffc_pattern_p):
* font-mgr.c (Ffc_pattern_create):
* font-mgr.c (Ffc_name_parse):
* font-mgr.c (Ffc_name_unparse):
* font-mgr.c (Ffc_pattern_duplicate):
* font-mgr.c (Ffc_pattern_add):
* font-mgr.c (Ffc_pattern_del):
* font-mgr.c (Ffc_pattern_get):
* font-mgr.c (fc_config_create_using):
* font-mgr.c (fc_strlist_to_lisp_using):
* font-mgr.c (fontset_to_list):
* font-mgr.c (Ffc_config_p):
* font-mgr.c (Ffc_config_up_to_date):
* font-mgr.c (Ffc_config_build_fonts):
* font-mgr.c (Ffc_config_get_cache):
* font-mgr.c (Ffc_config_get_fonts):
* font-mgr.c (Ffc_config_set_current):
* font-mgr.c (Ffc_config_get_blanks):
* font-mgr.c (Ffc_config_get_rescan_interval):
* font-mgr.c (Ffc_config_set_rescan_interval):
* font-mgr.c (Ffc_config_app_font_add_file):
* font-mgr.c (Ffc_config_app_font_add_dir):
* font-mgr.c (Ffc_config_app_font_clear):
* font-mgr.c (size):
* font-mgr.c (Ffc_config_substitute):
* font-mgr.c (Ffc_font_render_prepare):
* font-mgr.c (Ffc_font_match):
* font-mgr.c (Ffc_font_sort):
* font-mgr.c (finalize_fc_config):
* font-mgr.c (print_fc_config):
* font-mgr.h:
* font-mgr.h (struct fc_pattern):
* font-mgr.h (XFC_PATTERN):
* font-mgr.h (struct fc_config):
* font-mgr.h (XFC_CONFIG):
* frame-gtk.c (allocate_gtk_frame_struct):
* frame-impl.h (struct frame):
* frame-msw.c (mswindows_init_frame_1):
* frame-x.c (allocate_x_frame_struct):
* frame.c (nuke_all_frame_slots):
* frame.c (allocate_frame_core):
* gc.c:
* gc.c (GC_CHECK_NOT_FREE):
* glyphs.c (finalize_image_instance):
* glyphs.c (allocate_image_instance):
* glyphs.c (Fcolorize_image_instance):
* glyphs.c (allocate_glyph):
* glyphs.c (unmap_subwindow_instance_cache_mapper):
* glyphs.c (register_ignored_expose):
* glyphs.h (struct Lisp_Image_Instance):
* glyphs.h (struct Lisp_Glyph):
* glyphs.h (struct glyph_cachel):
* glyphs.h (struct expose_ignore):
* gui.c (allocate_gui_item):
* gui.h (struct Lisp_Gui_Item):
* keymap.c (struct Lisp_Keymap):
* keymap.c (make_keymap):
* lisp.h:
* lisp.h (struct Lisp_String_Direct_Data):
* lisp.h (struct Lisp_String_Indirect_Data):
* lisp.h (struct Lisp_Vector):
* lisp.h (struct Lisp_Bit_Vector):
* lisp.h (DECLARE_INLINE_LISP_BIT_VECTOR):
* lisp.h (struct weak_box):
* lisp.h (struct ephemeron):
* lisp.h (struct weak_list):
* lrecord.h:
* lrecord.h (struct lrecord_implementation):
* lrecord.h (MC_ALLOC_CALL_FINALIZER):
* lrecord.h (struct lcrecord_list):
* lstream.c (finalize_lstream):
* lstream.c (sizeof_lstream):
* lstream.c (Lstream_new):
* lstream.c (Lstream_delete):
* lstream.h (struct lstream):
* marker.c:
* marker.c (finalize_marker):
* marker.c (compute_buffer_marker_usage):
* mule-charset.c:
* mule-charset.c (make_charset):
* mule-charset.c (compute_charset_usage):
* objects-impl.h (struct Lisp_Color_Instance):
* objects-impl.h (struct Lisp_Font_Instance):
* objects-tty-impl.h (struct tty_color_instance_data):
* objects-tty-impl.h (struct tty_font_instance_data):
* objects-tty.c (tty_initialize_color_instance):
* objects-tty.c (tty_initialize_font_instance):
* objects.c (finalize_color_instance):
* objects.c (Fmake_color_instance):
* objects.c (finalize_font_instance):
* objects.c (Fmake_font_instance):
* objects.c (reinit_vars_of_objects):
* opaque.c:
* opaque.c (sizeof_opaque):
* opaque.c (make_opaque_ptr):
* opaque.c (free_opaque_ptr):
* opaque.h:
* opaque.h (Lisp_Opaque):
* opaque.h (Lisp_Opaque_Ptr):
* print.c (printing_unreadable_lcrecord):
* print.c (external_object_printer):
* print.c (debug_p4):
* process.c (finalize_process):
* process.c (make_process_internal):
* procimpl.h (struct Lisp_Process):
* rangetab.c (Fmake_range_table):
* rangetab.c (Fcopy_range_table):
* rangetab.h (struct Lisp_Range_Table):
* scrollbar.c:
* scrollbar.c (create_scrollbar_instance):
* scrollbar.c (compute_scrollbar_instance_usage):
* scrollbar.h (struct scrollbar_instance):
* specifier.c (finalize_specifier):
* specifier.c (sizeof_specifier):
* specifier.c (set_specifier_caching):
* specifier.h (struct Lisp_Specifier):
* specifier.h (struct specifier_caching):
* symeval.h:
* symeval.h (SYMBOL_VALUE_MAGIC_P):
* symeval.h (DEFVAR_SYMVAL_FWD):
* symsinit.h:
* syntax.c (init_buffer_syntax_cache):
* syntax.h (struct syntax_cache):
* toolbar.c:
* toolbar.c (allocate_toolbar_button):
* toolbar.c (update_toolbar_button):
* toolbar.h (struct toolbar_button):
* tooltalk.c (struct Lisp_Tooltalk_Message):
* tooltalk.c (make_tooltalk_message):
* tooltalk.c (struct Lisp_Tooltalk_Pattern):
* tooltalk.c (make_tooltalk_pattern):
* ui-gtk.c:
* ui-gtk.c (allocate_ffi_data):
* ui-gtk.c (emacs_gtk_object_finalizer):
* ui-gtk.c (allocate_emacs_gtk_object_data):
* ui-gtk.c (allocate_emacs_gtk_boxed_data):
* ui-gtk.h:
* window-impl.h (struct window):
* window-impl.h (struct window_mirror):
* window.c (finalize_window):
* window.c (allocate_window):
* window.c (new_window_mirror):
* window.c (mark_window_as_deleted):
* window.c (make_dummy_parent):
* window.c (compute_window_mirror_usage):
* window.c (compute_window_usage):
Overall point of this change and previous ones in this repository:
(1) Introduce new, clearer terminology: everything other than int
or char is a "record" object, which comes in two types: "normal
objects" and "frob-block objects". Fix up all places that
referred to frob-block objects as "simple", "basic", etc.
(2) Provide an advertised interface for doing operations on Lisp
objects, including creating new types, that is clean and
consistent in its naming, uses the above-referenced terms and
avoids referencing "lrecords", "old lcrecords", etc., which should
hide under the surface.
(3) Make the size_in_bytes and finalizer methods take a
Lisp_Object rather than a void * for consistency with other methods.
(4) Separate finalizer method into finalizer and disksaver, so
that normal finalize methods don't have to worry about disksaving.
Other specifics:
(1) Renaming:
LISP_OBJECT_HEADER -> NORMAL_LISP_OBJECT_HEADER
ALLOC_LISP_OBJECT -> ALLOC_NORMAL_LISP_OBJECT
implementation->basic_p -> implementation->frob_block_p
ALLOCATE_FIXED_TYPE_AND_SET_IMPL -> ALLOC_FROB_BLOCK_LISP_OBJECT
*FCCONFIG*, wrap_fcconfig -> *FC_CONFIG*, wrap_fc_config
*FCPATTERN*, wrap_fcpattern -> *FC_PATTERN*, wrap_fc_pattern
(the last two changes make the naming of these macros consistent
with the naming of all other macros, since the objects are named
fc-config and fc-pattern with a hyphen)
(2) Lots of documentation fixes in lrecord.h.
(3) Eliminate macros for copying, freeing, zeroing objects, getting
their storage size. Instead, new functions:
zero_sized_lisp_object()
zero_nonsized_lisp_object()
lisp_object_storage_size()
free_normal_lisp_object()
(copy_lisp_object() already exists)
LISP_OBJECT_FROB_BLOCK_P() (actually a macro)
Eliminated:
free_lrecord()
zero_lrecord()
copy_lrecord()
copy_sized_lrecord()
old_copy_lcrecord()
old_copy_sized_lcrecord()
old_zero_lcrecord()
old_zero_sized_lcrecord()
LISP_OBJECT_STORAGE_SIZE()
COPY_SIZED_LISP_OBJECT()
COPY_SIZED_LCRECORD()
COPY_LISP_OBJECT()
ZERO_LISP_OBJECT()
FREE_LISP_OBJECT()
(4) Catch the remaining places where lrecord stuff was used directly
and use the advertised interface, e.g. alloc_sized_lrecord() ->
ALLOC_SIZED_LISP_OBJECT().
(5) Make certain statically-declared pseudo-objects
(buffer_local_flags, console_local_flags) have their lheader
initialized correctly, so things like copy_lisp_object() can work
on them. Make extent_auxiliary_defaults a proper heap object
Vextent_auxiliary_defaults, and make extent auxiliaries dumpable
so that this object can be dumped. allocate_extent_auxiliary()
now just creates the object, and attach_extent_auxiliary()
creates an extent auxiliary and attaches to an extent, like the
old allocate_extent_auxiliary().
(6) Create EXTENT_AUXILIARY_SLOTS macro, similar to the foo-slots.h
files but in a macro instead of a file. The purpose is to avoid
duplication when iterating over all the slots in an extent auxiliary.
Use it.
(7) In lstream.c, don't zero out object after allocation because
allocation routines take care of this.
(8) In marker.c, fix a mistake in computing marker overhead.
(9) In print.c, clean up printing_unreadable_lcrecord(),
external_object_printer() to avoid lots of ifdef NEW_GC's.
(10) Separate toolbar-button allocation into a separate
allocate_toolbar_button() function for use in the example code
in lrecord.h.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Fri, 05 Mar 2010 04:08:17 -0600 |
parents | 3c3c1d139863 |
children | 6c6d78781d59 |
line wrap: on
line source
/* emodules.c - Support routines for dynamic module loading (C) Copyright 1998, 1999 J. Kean Johnston. All rights reserved. (C) Copyright 2010 Ben Wing. This file is part of XEmacs. XEmacs 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 2, or (at your option) any later version. XEmacs 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 XEmacs; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This file has been Mule-ized, Ben Wing, 1-26-10. */ #include "emodules.h" #include "sysdll.h" #ifdef HAVE_LTDL #include <ltdl.h> #endif /* Load path */ static Lisp_Object Vmodule_load_path; /* Module lFile extensions */ static Lisp_Object Vmodule_extensions; #ifdef HAVE_SHLIB /* CE-Emacs version number */ Lisp_Object Vmodule_version; /* Do we do our work quietly? */ int load_modules_quietly; /* Set this while unloading a module. This should NOT be made set by users, as it allows the unbinding of symbol-value-forward variables. */ int unloading_module; Lisp_Object Qdll_error; Lisp_Object Qmodule, Qunload_module, module_tag; typedef struct _emodules_list { int used; /* Is this slot used? */ Ibyte *soname; /* Name of the shared object loaded (full path) */ Ibyte *modname; /* The name of the module */ Ibyte *modver; /* The module version string */ Ibyte *modtitle; /* How the module announces itself */ void (*unload) (void);/* Module cleanup function to run before unloading */ dll_handle dlhandle; /* Dynamic lib handle */ } emodules_list; static int emodules_depth; static dll_handle dlhandle; static emodules_list *modules; static int modnum; static int find_make_module (Lisp_Object mod, const Ibyte *name, const Ibyte *ver, int make_or_find); static Lisp_Object module_load_unwind (Lisp_Object); static void attempt_module_delete (int mod); DEFUN ("load-module", Fload_module, 1, 3, "FLoad dynamic module: ", /* Load in a C Emacs Extension module named FILE. The optional NAME and VERSION are used to identify specific modules. DO NOT USE THIS FUNCTION in your programs. Use `require' instead. This function is similar in intent to `load' except that it loads in pre-compiled C or C++ code, using dynamic shared objects. If NAME is specified, then the module is only loaded if its internal name matches the NAME specified. If VERSION is specified, then the module is only loaded if it matches that VERSION. This function will check to make sure that the same module is not loaded twice. Modules are searched for in the same way as Lisp files, except that the valid file extensions are `.so', `.dll', `.ell', or `.dylib'. All symbols in the shared module must be completely resolved in order for this function to be successful. Any modules which the specified FILE depends on will be automatically loaded. You can determine which modules have been loaded as dynamic shared objects by examining the return value of the function `list-modules'. It is possible, although unwise, to unload modules using `unload-feature'. The preferred mechanism for unloading or reloading modules is to quit XEmacs, and then reload those new or changed modules that are required. Messages informing you of the progress of the load are displayed unless the variable `load-modules-quietly' is non-NIL. */ (file, name, version)) { const Ibyte *mod, *mname, *mver; int speccount = specpdl_depth(); CHECK_STRING (file); mod = XSTRING_DATA (file); if (NILP (name)) mname = (const Ibyte *) ""; else mname = XSTRING_DATA (name); if (NILP (version)) mver = (const Ibyte *) ""; else mver = XSTRING_DATA (version); dlhandle = 0; record_unwind_protect (module_load_unwind, make_int(modnum)); emodules_load (mod, mname, mver); unbind_to (speccount); return Qt; } DEFUN ("unload-module", Funload_module, 1, 3, 0, /* Unload a module previously loaded with load-module. DO NOT USE THIS FUNCTION in your programs. Use `unload-feature' instead. As with load-module, this function requires at least the module FILE, and optionally the module NAME and VERSION to unload. It may not be possible for the module to be unloaded from memory, as there may be Lisp objects referring to variables inside the module code. However, once you have requested a module to be unloaded, it will be unloaded from memory as soon as the last reference to symbols within the module is destroyed. */ (file, name, version)) { int x; const Ibyte *mname, *mver; Lisp_Object foundname = Qnil; struct gcpro gcpro1; CHECK_STRING(file); GCPRO1 (foundname); if (locate_file (Vmodule_load_path, file, Vmodule_extensions, &foundname, 0) < 0) return Qt; UNGCPRO; if (NILP (name)) mname = (const Ibyte *) ""; else mname = XSTRING_DATA (name); if (NILP (version)) mver = (const Ibyte *) ""; else mver = XSTRING_DATA (version); x = find_make_module (foundname, mname, mver, 1); if (x != -1) { if (modules[x].unload != NULL) modules[x].unload (); attempt_module_delete (x); } return Qt; } DEFUN ("list-modules", Flist_modules, 0, 0, "", /* Produce a list of loaded dynamic modules. This function will return a list of all the loaded dynamic modules. Each element in the list is a list in the form (SONAME NAME VER DESC), where SONAME is the name of the shared object that was loaded, NAME is the internal module name, VER is the version of the module, and DESC is how the module describes itself. This function returns a list, so you will need to assign the return value to a variable and then examine the variable with `describe-variable'. For example: (setq mylist (list-modules)) (describe-variable 'mylist) NOTE: It is possible for the same module to be loaded more than once, at different versions. However, you should never see the same module, with the same name and version, loaded more than once. If you do, this is a bug, and you are encouraged to report it. */ ()) { Lisp_Object mlist = Qnil; int i; for (i = 0; i < modnum; i++) { if (modules[i].used == 1) mlist = Fcons (list4 (build_istring (modules[i].soname), build_istring (modules[i].modname), build_istring (modules[i].modver), build_istring (modules[i].modtitle)), mlist); } return mlist; } static int find_make_module (Lisp_Object mod, const Ibyte *name, const Ibyte *ver, int mof) { int i, fs = -1; Ibyte *modstr = XSTRING_DATA (mod); for (i = 0; i < modnum; i++) { if (fs == -1 && modules[i].used == 0) fs = i; if (qxestrcmp (modules[i].soname, modstr) == 0) { if (name && name[0] && qxestrcmp (modules[i].modname, name)) continue; if (ver && ver[0] && qxestrcmp (modules[i].modver, ver)) continue; return i; /* Found a match */ } } if (mof) return fs; if (fs != -1) return fs; /* First free slot */ /* * We only get here if we haven't found a free slot and the module was * not previously loaded. */ if (modules == NULL) modules = xnew (emodules_list); modnum++; XREALLOC_ARRAY (modules, emodules_list, modnum); fs = modnum - 1; memset (&modules[fs], 0, sizeof (emodules_list)); return fs; } static void attempt_module_delete (int mod) { if (dll_close (modules[mod].dlhandle) == 0) { xfree (modules[mod].soname); xfree (modules[mod].modname); xfree (modules[mod].modver); xfree (modules[mod].modtitle); modules[mod].dlhandle = 0; modules[mod].used = 0; } else if (modules[mod].used > 1) modules[mod].used = 1; /* We couldn't delete it - it stays */ } static Lisp_Object module_load_unwind (Lisp_Object upto) { int x,l=0; /* * First close off the current handle if it is open. */ if (dlhandle != 0) dll_close (dlhandle); dlhandle = 0; if (CONSP (upto)) { if (INTP (XCAR (upto))) l = XINT (XCAR (upto)); free_cons (upto); } else l = XINT (upto); /* * Here we need to go through and dlclose() (IN REVERSE ORDER!) any * modules that were loaded as part of this load chain. We only mark * the slots as closed if the dlclose() succeeds. */ for (x = modnum-1; x >= l; x--) { if (modules[x].used > 1) attempt_module_delete (x); } emodules_depth = 0; return Qnil; } /* * Do the actual grunt-work of loading in a module. We first try and * dlopen() the module. If that fails, we have an error and we bail * out immediately. If the dlopen() succeeds, we need to check for the * existence of certain special symbols. * * All modules will have complete access to the variables and functions * defined within XEmacs itself. It is up to the module to declare any * variables or functions it uses, however. Modules will also have access * to other functions and variables in other loaded modules, unless they * are defined as STATIC. * * We need to be very careful with how we load modules. If we encounter an * error along the way, we need to back out completely to the point at * which the user started. Since we can be called recursively, we need to * take care with marking modules as loaded. When we first start loading * modules, we set the counter to zero. As we enter the function each time, * we increment the counter, and before we leave we decrement it. When * we get back down to 0, we know we are at the end of the chain and we * can mark all the modules in the list as loaded. * * When we signal an error, we need to be sure to unwind all modules loaded * thus far (but only for this module chain). It is assumed that if any * modules in a chain fail, then they all do. This is logical, considering * that the only time we recurse is when we have dependent modules. So in * the error handler we take great care to close off the module chain before * we call "error" and let the Fmodule_load unwind_protect() function handle * the cleaning up. */ void emodules_load (const Ibyte *module, const Ibyte *modname, const Ibyte *modver) { Lisp_Object old_load_list; Lisp_Object filename; Lisp_Object foundname, lisp_modname; int x, mpx; const Extbyte **f; const long *ellcc_rev; Ibyte *mver, *mname, *mtitle, *symname; void (*modload)(void) = 0; void (*modsyms)(void) = 0; void (*modvars)(void) = 0; void (*moddocs)(void) = 0; void (*modunld)(void) = 0; emodules_list *mp; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; filename = Qnil; foundname = Qnil; emodules_depth++; dlhandle = 0; if (module == NULL || module[0] == '\0') invalid_argument ("Empty module name", Qunbound); GCPRO4 (filename, foundname, old_load_list, lisp_modname); filename = build_istring (module); if (locate_file (Vmodule_load_path, filename, Vmodule_extensions, &foundname, 0) < 0) signal_error (Qdll_error, "Cannot open dynamic module", filename); lisp_modname = call1 (Qfile_name_sans_extension, Ffile_name_nondirectory (foundname)); dlhandle = dll_open (foundname); if (dlhandle == NULL) { signal_error (Qdll_error, "Opening dynamic module", dll_error ()); } ellcc_rev = (const long *) dll_variable (dlhandle, (const Ibyte *) "emodule_compiler"); if (ellcc_rev == NULL || *ellcc_rev <= 0L) signal_error (Qdll_error, "Invalid dynamic module: Missing symbol `emodule_compiler'", Qunbound); if (*ellcc_rev > EMODULES_REVISION) signal_ferror (Qdll_error, "Invalid dynamic module: Unsupported version `%ld(%ld)'", *ellcc_rev, EMODULES_REVISION); f = (const Extbyte **) dll_variable (dlhandle, (const Ibyte *) "emodule_name"); if (f == NULL || *f == NULL) signal_error (Qdll_error, "Invalid dynamic module: Missing symbol `emodule_name'", Qunbound); mname = EXTERNAL_TO_ITEXT (f, Qemodule_string_encoding); /* #### Not obvious we have to force an alloca copy here, but the old code did so */ IBYTE_STRING_TO_ALLOCA (mname, mname); if (mname[0] == '\0') signal_error (Qdll_error, "Invalid dynamic module: Empty value for `emodule_name'", Qunbound); f = (const Extbyte **) dll_variable (dlhandle, (const Ibyte *) "emodule_version"); if (f == NULL || *f == NULL) signal_error (Qdll_error, "Missing symbol `emodule_version': Invalid dynamic module", Qunbound); mver = EXTERNAL_TO_ITEXT (f, Qemodule_string_encoding); /* #### Not obvious we have to force an alloca copy here, but the old code did so */ IBYTE_STRING_TO_ALLOCA (mver, mver); f = (const Extbyte **) dll_variable (dlhandle, (const Ibyte *) "emodule_title"); if (f == NULL || *f == NULL) signal_error (Qdll_error, "Invalid dynamic module: Missing symbol `emodule_title'", Qunbound); mtitle = EXTERNAL_TO_ITEXT (f, Qemodule_string_encoding); /* #### Not obvious we have to force an alloca copy here, but the old code did so */ IBYTE_STRING_TO_ALLOCA (mtitle, mtitle); symname = alloca_ibytes (qxestrlen (mname) + 15); qxestrcpy_ascii (symname, "modules_of_"); qxestrcat (symname, mname); modload = (void (*)(void)) dll_function (dlhandle, symname); /* * modload is optional. If the module doesn't require other modules it can * be left out. */ qxestrcpy_ascii (symname, "syms_of_"); qxestrcat (symname, mname); modsyms = (void (*)(void)) dll_function (dlhandle, symname); if (modsyms == NULL) { missing_symbol: signal_error (Qdll_error, "Invalid dynamic module: Missing symbol", build_istring (symname)); } qxestrcpy_ascii (symname, "vars_of_"); qxestrcat (symname, mname); modvars = (void (*)(void)) dll_function (dlhandle, symname); if (modvars == NULL) goto missing_symbol; qxestrcpy_ascii (symname, "docs_of_"); qxestrcat (symname, mname); moddocs = (void (*)(void)) dll_function (dlhandle, symname); if (moddocs == NULL) goto missing_symbol; /* Now look for the optional unload function. */ qxestrcpy_ascii (symname, "unload_"); qxestrcat (symname, mname); modunld = (void (*)(void)) dll_function (dlhandle, symname); if (modname && modname[0] && qxestrcmp (modname, mname)) signal_error (Qdll_error, "Module name mismatch", Qunbound); if (modver && modver[0] && qxestrcmp (modver, mver)) signal_error (Qdll_error, "Module version mismatch", Qunbound); /* * Attempt to make a new slot for this module. If this really is the * first time we are loading this module, the used member will be 0. * If that is non-zero, we know that we have a previously loaded module * of the same name and version, and we don't need to go any further. */ mpx = find_make_module (foundname, mname, mver, 0); mp = &modules[mpx]; if (mp->used > 0) { emodules_depth--; dll_close (dlhandle); dlhandle = 0; /* Zero this out before module_load_unwind runs */ return; } if (!load_modules_quietly) message ("Loading %s v%s (%s)", mname, mver, mtitle); /* * We have passed the basic initialization, and can now add this * module to the list of modules. */ mp->used = emodules_depth + 1; mp->soname = qxestrdup (XSTRING_DATA (foundname)); mp->modname = qxestrdup (mname); mp->modver = qxestrdup (mver); mp->modtitle = qxestrdup (mtitle); mp->dlhandle = dlhandle; mp->unload = modunld; dlhandle = 0; old_load_list = Vcurrent_load_list; Vcurrent_load_list = Qnil; LOADHIST_ATTACH (lisp_modname); LOADHIST_ATTACH (module_tag); /* * Now we need to call the module init function and perform the various * startup tasks. */ if (modload != 0) (*modload) (); /* * Now we can get the module to initialize its symbols, and then its * variables, and lastly the documentation strings. */ (*modsyms) (); (*modvars) (); (*moddocs) (); if (!load_modules_quietly) message ("Loaded module %s v%s (%s)", mname, mver, mtitle); Vload_history = Fcons (Fnreverse (Vcurrent_load_list), Vload_history); Vcurrent_load_list = old_load_list; UNGCPRO; emodules_depth--; if (emodules_depth == 0) { /* * We have reached the end of the load chain. We now go through the * list of loaded modules and mark all the valid modules as just * that. */ for (x = 0; x < modnum; x++) if (modules[x].used > 1) modules[x].used = 1; } } void emodules_doc_subr (const Ascbyte *symname, const Ascbyte *doc) { Bytecount len; Lisp_Object sym; Lisp_Subr *subr; ASSERT_ASCTEXT_ASCII (symname); len = strlen (symname); sym = oblookup (Vobarray, (const Ibyte *) symname, len); /* We do this assert to avoid the possibility of externally formatted text ending up in the doc string, where it could cause crashes. It you need to have a non-ASCII doc string, create another version emodules_doc_subr_istring() that accepts an Ibyte * and doesn't assert, or create an emodules_doc_subr_extstring() that takes an externally_formatted string and a coding system name. */ ASSERT_ASCTEXT_ASCII (doc); /* Skip autoload cookies */ if (SYMBOLP (sym) && SUBRP (XSYMBOL (sym)->function)) { subr = XSUBR (XSYMBOL (sym)->function); subr->doc = xstrdup (doc); } /* * #### FIXME: I wish there was some way to avoid the xstrdup(). Is it * possible to just set a pointer to the string, or somehow create a * symbol whose value we can point to the constant string? Can someone * look into this? */ } void emodules_doc_sym (const Ascbyte *symname, const Ascbyte *doc) { Bytecount len; Lisp_Object sym; Lisp_Object docstr; struct gcpro gcpro1; ASSERT_ASCTEXT_ASCII (symname); len = strlen (symname); sym = oblookup (Vobarray, (const Ibyte *) symname, len); /* See comments above in emodules_doc_subr() about why we assert like this. */ ASSERT_ASCTEXT_ASCII (doc); if (SYMBOLP (sym)) { docstr = build_ascstring (doc); GCPRO1 (docstr); Fput (sym, Qvariable_documentation, docstr); UNGCPRO; } } void syms_of_module (void) { DEFERROR_STANDARD (Qdll_error, Qerror); DEFSYMBOL (Qmodule); DEFSYMBOL (Qunload_module); DEFSUBR (Fload_module); DEFSUBR (Flist_modules); DEFSUBR (Funload_module); module_tag = Fcons (Qmodule, Qnil); staticpro (&module_tag); Fput (Qunload_module, Qdisabled, Qt); } void reinit_vars_of_module (void) { emodules_depth = 0; modules = NULL; modnum = 0; } #endif /* HAVE_SHLIB */ void vars_of_module (void) { #ifdef HAVE_SHLIB Fprovide (intern ("modules")); #ifdef HAVE_LTDL lt_dlinit (); lt_dlmalloc = (lt_ptr (*) (size_t)) xmalloc; lt_dlrealloc = (lt_ptr (*) (lt_ptr, size_t)) xrealloc; lt_dlfree = (void (*) (lt_ptr)) xfree_1; #endif DEFVAR_LISP ("module-version", &Vmodule_version /* Emacs dynamic loading mechanism version, as a string. This string is in the form XX.YY.ppp, where XX is the major version number, YY is the minor version number, and ppp is the patch level. This variable can be used to distinguish between different versions of the dynamic loading technology used in Emacs, if required. It is not a given that this value will be the same as the Emacs version number. */ ); Vmodule_version = build_cistring (EMODULES_VERSION); DEFVAR_BOOL ("load-modules-quietly", &load_modules_quietly /* *Set to t if module loading is to be silent. Normally, when loading dynamic modules, Emacs will inform you of its progress, and will display the module name and version if the module is loaded correctly. Setting this variable to `t' will suppress these messages. This would normally only be done if `load-module' was being called by a Lisp function. */); load_modules_quietly = 0; DEFVAR_BOOL ("unloading-module", &unloading_module /* Used internally by `unload-feature'. Do not set this variable. Danger, danger, Will Robinson! */); unloading_module = 0; #endif /* HAVE_SHLIB */ DEFVAR_LISP ("module-load-path", &Vmodule_load_path /* *List of directories to search for dynamic modules to load. Each element is a string (directory name) or nil (try default directory). Note that elements of this list *may not* begin with "~", so you must call `expand-file-name' on them before adding them to this list. Initialized based on EMACSMODULEPATH environment variable, if any, otherwise to default specified the file `paths.h' when XEmacs was built. If there were no paths specified in `paths.h', then XEmacs chooses a default value for this variable by looking around in the file-system near the directory in which the XEmacs executable resides. Due to the nature of dynamic modules, the path names should almost always refer to architecture-dependent directories. It is unwise to attempt to store dynamic modules in a heterogenous environment. Some environments are similar enough to each other that XEmacs will be unable to determine the correctness of a dynamic module, which can have unpredictable results when a dynamic module is loaded. */); Vmodule_load_path = Qnil; DEFVAR_LISP ("module-extensions", &Vmodule_extensions /* *List of filename extensions to use when searching for dynamic modules. */); Vmodule_extensions = list5 (build_ascstring (".ell"), build_ascstring (".so"), build_ascstring (".dll"), build_ascstring (".dylib"), build_ascstring ("")); }