20.1.4 Unloading a Module
When unloading a module, several things must be done:
-
Any built-in commands implemented by this module must be unregistered so
that Sic doesn't try to call them after the implementation has been
removed.
-
Any syntax extensions implemented by this module must be similarly
unregistered, including
syntax_init and syntax_finish
functions.
-
If there is a finalisation entry point in the module,
`module_finish' (see section 20.1.3 Loading a Module), it must be called.
My first cut implementation of a module subsystem kept a list of the
entry points associated with each module so that they could be looked up
and removed when the module was subsequently unloaded. It also kept
track of multiply loaded modules so that a module wasn't unloaded
prematurely. libltdl already does all of this though, and it is
wasteful to duplicate all of that work. This system uses
lt_dlforeach and lt_dlgetinfo to access libltdls records
of loaded modules, and save on duplication. These two functions are
described fully insection `Libltdl interface' in The Libtool Manual.
This function asks libltdl to call the function
unload_ltmodule for each of the modules it has loaded, along with
some details of the module it wants to unload. The tricky part of the
callback function below is recalculating the ntry point addresses for
the module to be unloaded and then removing all matching addresses from
the appropriate internal structures. Otherwise, the balance of this
callback is involved in informing the calling lt_dlforeach loop
of whether a matching module has been found and handled:
The userdata_address_compare helper function at the end is used
to compare the address of recalculated entry points against the already
registered functions and handlers to find which items need to be
unregistered.
There is also a matching header file to export the module interface, so
that the code for loadable modules can make use of it:
This header also includes some of the other Sic headers, so that in most
cases, the source code for a module need only `#include
<sic/module.h>'.
To make the module loading interface useful, I have added built-ins for
`load' and `unload'. Naturally, these must be compiled into
the bare sic executable, so that it is able to load additional
modules:
These new built-in commands are simply wrappers around the module loading
code in `module.c'.
As with `dlopen', you can use libltdl to `lt_dlopen' the
main executable, and then lookup its symbols. I have simplified
the initialisation of Sic by replacing the sic_init function in
`src/sic.c' by `loading' the executable itself as a module. This
works because I was careful to use the same format in
`sic_builtin.c' and `sic_syntax.c' as would be required for a
genuine loadable module, like so:
|