XFree86 X server ``New 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.

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, it *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 LoadSubModule()).

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 LoadModule(), 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.

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 X server ``New Design'' (DRAFT) : The Loader
Previous: The XFree86 X Video Extension (Xv) Device Dependent Layer
Next: Helper Functions