Next: , Previous: 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, in order 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.