File: libtool.info, Node: User defined module data, Next: Module loaders for libltdl, Prev: Thread Safety in libltdl, Up: Using libltdl 11.4 Data associated with loaded modules ======================================== Some of the internal information about each loaded module that is maintained by libltdl is available to the user, in the form of this structure: -- Type: struct lt_dlinfo { char *filename; char *name; int ref_count; int is_resident; int is_symglobal; int is_symlocal;} ‘lt_dlinfo’ is used to store information about a module. The ‘filename’ attribute is a null-terminated character string of the real module file name. If the module is a libtool module then ‘name’ is its module name (e.g. ‘"libfoo"’ for ‘"dir/libfoo.la"’), otherwise it is set to ‘NULL’. The ‘ref_count’ attribute is a reference counter that describes how often the same module is currently loaded. The remaining fields can be compared to any hints that were passed to ‘lt_dlopenadvise’ to determine whether the underlying loader was able to follow them. The following function will return a pointer to libltdl's internal copy of this structure for the given HANDLE: -- Function: const lt_dlinfo * lt_dlgetinfo (lt_dlhandle HANDLE) Return a pointer to a struct that contains some information about the module HANDLE. The contents of the struct must not be modified. Return ‘NULL’ on failure. Furthermore, to save you from having to keep a list of the handles of all the modules you have loaded, these functions allow you to iterate over libltdl's list of loaded modules: -- Type: lt_dlinterface_id The opaque type used to hold the module interface details for each registered libltdl client. -- Type: int lt_dlhandle_interface (lt_dlhandle HANDLE, const char *ID_STRING) Functions of this type are called to check that a handle conforms to a library's expected module interface when iterating over the global handle list. You should be careful to write a callback function of this type that can correctly identify modules that belong to this client, both to prevent other clients from accidentally finding your loaded modules with the iterator functions below, and vice versa. The best way to do this is to check that module HANDLE conforms to the interface specification of your loader using ‘lt_dlsym’. The callback may be given *every* module loaded by all the libltdl module clients in the current address space, including any modules loaded by other libraries such as libltdl itself, and should return non-zero if that module does not fulfill the interface requirements of your loader. int my_interface_cb (lt_dlhandle handle, const char *id_string) { char *(*module_id) (void) = NULL; /* A valid my_module must provide all of these symbols. */ if (!((module_id = (char*(*)(void)) lt_dlsym ("module_version")) && lt_dlsym ("my_module_entrypoint"))) return 1; if (strcmp (id_string, module_id()) != 0) return 1; return 0; } -- Function: lt_dlinterface_id lt_dlinterface_register (const char *ID_STRING, lt_dlhandle_interface *IFACE) Use this function to register your interface validator with libltdl, and in return obtain a unique key to store and retrieve per-module data. You supply an ID_STRING and IFACE so that the resulting ‘lt_dlinterface_id’ can be used to filter the module handles returned by the iteration functions below. If IFACE is ‘NULL’, all modules will be matched. -- Function: void lt_dlinterface_free (lt_dlinterface_id IFACE) Release the data associated with IFACE. -- Function: int lt_dlhandle_map (lt_dlinterface_id IFACE, int (*FUNC) (lt_dlhandle HANDLE, void * DATA), void * DATA) For each module that matches IFACE, call the function FUNC. When writing the FUNC callback function, the argument HANDLE is the handle of a loaded module, and DATA is the last argument passed to ‘lt_dlhandle_map’. As soon as FUNC returns a non-zero value for one of the handles, ‘lt_dlhandle_map’ will stop calling FUNC and immediately return that non-zero value. Otherwise 0 is eventually returned when FUNC has been successfully called for all matching modules. -- Function: lt_dlhandle lt_dlhandle_iterate (lt_dlinterface_id IFACE, lt_dlhandle PLACE) Iterate over the module handles loaded by IFACE, returning the first matching handle in the list if PLACE is ‘NULL’, and the next one on subsequent calls. If PLACE is the last element in the list of eligible modules, this function returns ‘NULL’. lt_dlhandle handle = 0; lt_dlinterface_id iface = my_interface_id; while ((handle = lt_dlhandle_iterate (iface, handle))) { ... } -- Function: lt_dlhandle lt_dlhandle_fetch (lt_dlinterface_id IFACE, const char *MODULE_NAME) Search through the module handles loaded by IFACE for a module named MODULE_NAME, returning its handle if found or else ‘NULL’ if no such named module has been loaded by IFACE. However, you might still need to maintain your own list of loaded module handles (in parallel with the list maintained inside libltdl) if there were any other data that your application wanted to associate with each open module. Instead, you can use the following API calls to do that for you. You must first obtain a unique interface id from libltdl as described above, and subsequently always use it to retrieve the data you stored earlier. This allows different libraries to each store their own data against loaded modules, without interfering with one another. -- Function: void * lt_dlcaller_set_data (lt_dlinterface_id KEY, lt_dlhandle HANDLE, void * DATA) Set DATA as the set of data uniquely associated with KEY and HANDLE for later retrieval. This function returns the DATA previously associated with KEY and HANDLE if any. A result of 0, may indicate that a diagnostic for the last error (if any) is available from ‘lt_dlerror()’. For example, to correctly remove some associated data: void *stale = lt_dlcaller_set_data (key, handle, 0); if (stale != NULL) { free (stale); } else { char *error_msg = lt_dlerror (); if (error_msg != NULL) { my_error_handler (error_msg); return STATUS_FAILED; } } -- Function: void * lt_dlcaller_get_data (lt_dlinterface_id KEY, lt_dlhandle HANDLE) Return the address of the data associated with KEY and HANDLE, or else ‘NULL’ if there is none. Old versions of libltdl also provided a simpler, but similar, API based around ‘lt_dlcaller_id’. Unfortunately, it had no provision for detecting whether a module belonged to a particular interface as libltdl didn't support multiple loaders in the same address space at that time. Those APIs are no longer supported as there would be no way to stop clients of the old APIs from seeing (and accidentally altering) modules loaded by other libraries.