XFree86 server 4.x Design (DRAFT)
: The Loader
Previous: The XFree86 X Video Extension (Xv) Device Dependent Layer
Next: Helper Functions
17. The Loader
This section describes the interfaces to the module loader. The loader
interfaces can be divided into two groups: those that are only available to
the XFree86 common layer, and those that are also available to modules.
17.1. Loader Overview
The loader is capable of loading modules in a range of object formats,
and knowledge of these formats is built in to the loader. Knowledge of
new object formats can be added to the loader in a straightforward
manner. This makes it possible to provide OS-independent modules (for
a given CPU architecture type). In addition to this, the loader can
load modules via the OS-provided dlopen(3) service where
available. Such modules are not platform independent, and the semantics
of dlopen() on most systems results in significant
limitations in the use of modules of this type. Support for
dlopen() modules in the loader is primarily for
experimental and development purposes.
Symbols exported by the loader (on behalf of the core X server) to
modules are determined at compile time. Only those symbols explicitly
exported are available to modules. All external symbols of loaded
modules are exported to other modules, and to the core X server. The
loader can be requested to check for unresolved symbols at any time,
and the action to be taken for unresolved symbols can be controlled by
the caller of the loader. Typically the caller identifies which symbols
can safely remain unresolved and which cannot.
NOTE: Now that ISO-C allows pointers to functions and pointers to data to
have different internal representations, some of the following interfaces
will need to be revisited.
17.2. Semi-private Loader Interface
The following is the semi-private loader interface that is available to the
XFree86 common layer.
void LoaderInit(void)
The LoaderInit() function initialises the loader,
and it must be called once before calling any other loader functions.
This function initialises the tables of exported symbols, and anything
else that might need to be initialised.
void LoaderSetPath(const char *path)
The LoaderSetPath() function initialises a default
module search path. This must be called if calls to other functions
are to be made without explicitly specifying a module search path.
The search path path must be a string of one or more
comma separated absolute paths. Modules are expected to be located
below these paths, possibly in subdirectories of these paths.
pointer LoadModule(const char *module, const char *path,
const char **subdirlist, const char **patternlist,
pointer options, const XF86ModReqInfo * modreq,
int *errmaj, int *errmin)
The LoadModule() function loads the module called
module. The return value is a module handle, and
may be used in future calls to the loader that require a reference
to a loaded module. The module name module is
normally the module's canonical name, which doesn't contain any
directory path information, or any object/library file prefixes of
suffixes. Currently a full pathname and/or filename is also accepted.
This might change. The other parameters are:
path
An optional comma-separated list of module search paths.
When NULL, the default search path is used.
subdirlist
An optional NULL terminated list of
subdirectories to search. When NULL,
the default built-in list is used (refer to
stdSubdirs in loadmod.c).
The default list is also substituted for entries in
subdirlist with the value
DEFAULT_LIST. This makes is possible
to augment the default list instead of replacing it.
Subdir elements must be relative, and must not contain
"..". If any violate this requirement,
the load fails.
patternlist
An optional NULL terminated list of
POSIX regular expressions used to connect module
filenames with canonical module names. Each regex
should contain exactly one subexpression that corresponds
to the canonical module name. When NULL,
the default built-in list is used (refer to
stdPatterns in
loadmod.c). The default list is also
substituted for entries in patternlist
with the value DEFAULT_LIST. This
makes it possible to augment the default list instead
of replacing it.
options
An optional parameter that is passed to the newly
loaded module's SetupProc function
(if it has one). This argument is normally a
NULL terminated list of
Options, and must be interpreted that
way by modules loaded directly by the XFree86 common
layer. However, it may be used for application-specific
parameter passing in other situations.
When loading ``external'' modules (modules that don't
have the standard entry point, for example a
special shared library) the options parameter can be
set to EXTERN_MODULE to tell the
loader not to reject the module when it doesn't find
the standard entry point.
modreq
An optional XF86ModReqInfo* containing
version/ABI/vendor information to requirements to
check the newly loaded module against. The main
purpose of this is to allow the loader to verify that
a module of the correct type/version before running
its SetupProc function.
The XF86ModReqInfo struct is defined
as follows:
typedef struct {
CARD8 majorversion; /* MAJOR_UNSPEC */
CARD8 minorversion; /* MINOR_UNSPEC */
CARD16 patchlevel; /* PATCH_UNSPEC */
const char * abiclass; /* ABI_CLASS_NONE */
CARD32 abiversion; /* ABI_VERS_UNSPEC */
const char * moduleclass; /* MOD_CLASS_NONE */
} XF86ModReqInfo;
The information here is compared against the equivalent
information in the module's
XF86ModuleVersionInfo record (which
is described below). The values in comments above
indicate ``don't care'' settings for each of the fields.
The comparisons made are as follows:
majorversion
Must match the module's majorversion
exactly.
minorversion
The module's minor version must be
no less than this value. This
comparison is only made if
majorversion is
specified and matches.
patchlevel
The module's patchlevel must be no
less than this value. This comparison
is only made if
minorversion is
specified and matches.
abiclass
String must match the module's abiclass
string.
abiversion
Must be consistent with the module's
abiversion (major equal, minor no
older).
moduleclass
String must match the module's
moduleclass string.
errmaj
An optional pointer to a variable holding the major
part or the error code. When provided,
*errmaj is filled in when
LoadModule() fails.
errmin
Like errmaj, but for the minor part
of the error code.
void UnloadModule(pointer mod)
This function unloads the module referred to by the handle mod.
All child modules are also unloaded recursively. This function must
not be used to directly unload modules that are child modules (i.e.,
those that have been loaded with the LoadSubModule()
described below).
17.3. Module Requirements
Modules must provide information about themselves to the loader, and
may optionally provide entry points for "setup" and "teardown" functions
(those two functions are referred to here as SetupProc
and TearDownProc).
The module information is contained in the
XF86ModuleVersionInfo struct, which is defined as follows:
typedef struct {
const char * modname; /* name of module, e.g. "foo" */
const char * vendor; /* vendor specific string */
CARD32 _modinfo1_; /* constant MODINFOSTRING1/2 to find */
CARD32 _modinfo2_; /* infoarea with a binary editor/sign tool */
CARD32 xf86version; /* contains XF86_VERSION_CURRENT */
CARD8 majorversion; /* module-specific major version */
CARD8 minorversion; /* module-specific minor version */
CARD16 patchlevel; /* module-specific patch level */
const char * abiclass; /* ABI class that the module uses */
CARD32 abiversion; /* ABI version */
const char * moduleclass; /* module class */
CARD32 checksum[4]; /* contains a digital signature of the */
/* version info structure */
} XF86ModuleVersionInfo;
The fields are used as follows:
modname
The module's name. This field is currently only for
informational purposes, but the loader may be modified
in future to require it to match the module's canonical
name.
vendor
The module vendor. This field is for informational purposes
only.
_modinfo1_
This field holds the first part of a signature that can
be used to locate this structure in the binary. It should
always be initialised to MODINFOSTRING1.
_modinfo2_
This field holds the second part of a signature that can
be used to locate this structure in the binary. It should
always be initialised to MODINFOSTRING2.
xf86version
The XFree86 version against which the module was compiled.
This is mostly for informational/diagnostic purposes. It
should be initialised to XF86_VERSION_CURRENT, which is
defined in xf86Version.h.
majorversion
The module-specific major version. For modules where this
version is used for more than simply informational
purposes, the major version should only change (be
incremented) when ABI incompatibilities are introduced,
or ABI components are removed.
minorversion
The module-specific minor version. For modules where this
version is used for more than simply informational
purposes, the minor version should only change (be
incremented) when ABI additions are made in a backward
compatible way. It should be reset to zero when the major
version is increased.
patchlevel
The module-specific patch level. The patch level should
increase with new revisions of the module where there
are no ABI changes, and it should be reset to zero when
the minor version is increased.
abiclass
The ABI class that the module requires. The class is
specified as a string for easy extensibility. It should
indicate which (if any) of the X server's built-in ABI
classes that the module relies on, or a third-party ABI
if appropriate. Built-in ABI classes currently defined are:
ABI_CLASS_NONE
no class
ABI_CLASS_ANSIC
only requires the ANSI C interfaces
ABI_CLASS_VIDEODRV
requires the video driver ABI
ABI_CLASS_XINPUT
requires the XInput driver ABI
ABI_CLASS_EXTENSION
requires the extension module ABI
ABI_CLASS_FONT
requires the font module ABI
abiversion
The version of abiclass that the module requires. The
version consists of major and minor components. The
major version must match and the minor version must be
no newer than that provided by the server or parent
module. Version identifiers for the built-in classes
currently defined are:
ABI_ANSIC_VERSION
ABI_VIDEODRV_VERSION
ABI_XINPUT_VERSION
ABI_EXTENSION_VERSION
ABI_FONT_VERSION
moduleclass
This is similar to the abiclass field, except that it
defines the type of module rather than the ABI it
requires. For example, although all video drivers require
the video driver ABI, not all modules that require the
video driver ABI are video drivers. This distinction
can be made with the moduleclass. Currently pre-defined
module classes are:
MOD_CLASS_NONE
MOD_CLASS_VIDEODRV
MOD_CLASS_XINPUT
MOD_CLASS_FONT
MOD_CLASS_EXTENSION
checksum
Not currently used.
The module version information, and the optional SetupProc
and TearDownProc entry points are found by the loader
by locating a data object in the module called "modnameModuleData",
where "modname" is the canonical name of the module. Modules must
contain such a data object, and it must be declared with global scope,
be compile-time initialised, and is of the following type:
typedef struct {
XF86ModuleVersionInfo * vers;
ModuleSetupProc setup;
ModuleTearDownProc teardown;
} XF86ModuleData;
The vers parameter must be initialised to a pointer to a correctly
initialised XF86ModuleVersionInfo struct. The other
two parameter are optional, and should be initialised to
NULL when not required. The other parameters are defined
as
typedef pointer (*ModuleSetupProc)(pointer, pointer, int *, int *)
typedef void (*ModuleTearDownProc)(pointer)
pointer SetupProc(pointer module, pointer options,
int *errmaj, int *errmin)
When defined, this function is called by the loader after successfully
loading a module. module is a handle for the newly loaded module,
and maybe used by the SetupProc if it calls other
loader functions that require a reference to it. The remaining
arguments are those that were passed to the
LoadModule() (or LoadSubModule()),
and are described above. When the SetupProc is
successful it must return a non-NULL value. The
loader checks this, and if it is NULL it unloads
the module and reports the failure to the caller of
LoadModule(). If the SetupProc
does things that need to be undone when the module is unloaded,
it should define a TearDownProc, and return a
pointer that the TearDownProc can use to undo what
has been done.
When a module is loaded multiple times, the SetupProc
is called once for each time it is loaded.
void TearDownProc(pointer tearDownData)
When defined, this function is called when the loader unloads a
module. The tearDownData parameter is the return
value of the SetupProc() that was called when the
module was loaded. The purpose of this function is to clean up
before the module is unloaded (for example, by freeing allocated
resources).
17.4. Public Loader Interface
The following is the Loader interface that is available to any part of
the server, and may also be used from within modules.
pointer LoadSubModule(pointer parent, const char *module,
const char **subdirlist, const char **patternlist,
pointer options, const XF86ModReqInfo * modreq,
int *errmaj, int *errmin)
This function is like the LoadModule() function
described above, except that the module loaded is registered as a
child of the calling module. The parent parameter
is the calling module's handle. Modules loaded with this function
are automatically unloaded when the parent module is unloaded. The
other difference is that the path parameter may not be specified.
The module search path used for modules loaded with this function
is the default search path as initialised with
LoaderSetPath().
void UnloadSubModule(pointer module)
This function unloads the module with handle module.
If that module itself has children, they are also unloaded. It is
like UnloadModule(), except that it is safe to use
for unloading child modules.
pointer LoaderSymbol(const char *symbol)
This function returns the address of the symbol with name
symbol. This may be used to locate a module entry
point with a known name.
char **LoaderlistDirs(const char **subdirlist,
const char **patternlist)
This function returns a NULL terminated list of
canonical modules names for modules found in the default module
search path. The subdirlist and
patternlist parameters are as described above, and
can be used to control the locations and names that are searched.
If no modules are found, the return value is NULL.
The returned list should be freed by calling
LoaderFreeDirList() when it is no longer needed.
void LoaderFreeDirList(char **list)
This function frees a module list created by
LoaderlistDirs().
void LoaderReqSymLists(const char **list0, ...)
This function allows the registration of required symbols with the
loader. It is normally used by a caller of
LoadSubModule(). If any symbols registered in this
way are found to be unresolved when
LoaderCheckUnresolved() is called then
LoaderCheckUnresolved() will report a failure.
The function takes one or more NULL terminated
lists of symbols. The end of the argument list is indicated by a
NULL argument.
void LoaderReqSymbols(const char *sym0, ...)
This function is like LoaderReqSymLists() except
that its arguments are symbols rather than lists of symbols. This
function is more convenient when single functions are to be registered,
especially when the single function might depend on runtime factors.
The end of the argument list is indicated by a NULL
argument.
void LoaderRefSymLists(const char **list0, ...)
This function allows the registration of possibly unresolved symbols
with the loader. When LoaderCheckUnresolved() is
run it won't generate warnings for symbols registered in this way
unless they were also registered as required symbols.
The function takes one or more NULL terminated
lists of symbols. The end of the argument list is indicated by a
NULL argument.
void LoaderRefSymbols(const char *sym0, ...)
This function is like LoaderRefSymLists() except
that its arguments are symbols rather than lists of symbols. This
function is more convenient when single functions are to be registered,
especially when the single function might depend on runtime factors.
The end of the argument list is indicated by a NULL
argument.
int LoaderCheckUnresolved(int delayflag)
This function checks for unresolved symbols. It generates warnings
for unresolved symbols that have not been registered with
LoaderRefSymLists(), and maps them to a dummy
function. This behaviour may change in future. If unresolved
symbols are found that have been registered with
LoaderReqSymLists() or
LoaderReqSymbols() then this function returns a
non-zero value. If none of these symbols are unresolved the return
value is zero, indicating success.
The delayflag parameter should normally be set to
LD_RESOLV_IFDONE.
LoaderErrorMsg(const char *name, const char *modname,
int errmaj, int errmin)
This function prints an error message that includes the text ``Failed
to load module'', the module name modname, a message
specific to the errmaj value, and the value if
errmin. If name is
non-NULL, it is printed as an identifying prefix
to the message (followed by a `:').
17.5. Special Registration Functions
The loader contains some functions for registering some classes of modules.
These may be moved out of the loader at some point.
void LoadExtension(ExtensionModule *ext)
This registers the entry points for the extension identified by
ext. The ExtensionModule struct is
defined as:
typedef struct {
InitExtension initFunc;
char * name;
Bool *disablePtr;
InitExtension setupFunc;
} ExtensionModule;
void LoadFont(FontModule *font)
This registers the entry points for the font rasteriser module
identified by font. The FontModule
struct is defined as:
typedef struct {
InitFont initFunc;
char * name;
pointer module;
} FontModule;
XFree86 server 4.x Design (DRAFT)
: The Loader
Previous: The XFree86 X Video Extension (Xv) Device Dependent Layer
Next: Helper Functions
|