[Mesa-dev] [PATCH v2] dri megadriver_stub: provide compatibility with older DRI loader
Kenneth Graunke
kenneth at whitecape.org
Sun Dec 8 13:56:35 PST 2013
On 12/06/2013 07:11 PM, Jordan Justen wrote:
> To help the transition period when DRI loaders are being updated
> to support the newer __driDriverExtensions_foo mechanism,
> we populate __DRIextension with the extensions returned
> by __driDriverExtensions_foo during a library contructor
constructor (typo)
> function.
>
> We find the driver foo's name by using the dladdr function
> which gives the path of the dynamic library's name that
> was being loaded.
>
> v2:
> * dladdr on public symbol __driDriverExtensions rather
> than static megadriver_stub_init.
> * Incorporate fixes and suggestions from Keith
>
> Signed-off-by: Jordan Justen <jordan.l.justen at intel.com>
> Cc: "10.0" <mesa-stable at lists.freedesktop.org>
> ---
> src/mesa/drivers/dri/common/megadriver_stub.c | 125 ++++++++++++++++++++++++++
> 1 file changed, 125 insertions(+)
>
> diff --git a/src/mesa/drivers/dri/common/megadriver_stub.c b/src/mesa/drivers/dri/common/megadriver_stub.c
> index 6bf5d73..cb1078d 100644
> --- a/src/mesa/drivers/dri/common/megadriver_stub.c
> +++ b/src/mesa/drivers/dri/common/megadriver_stub.c
> @@ -23,6 +23,131 @@
>
> #include <stdio.h>
> #include "dri_util.h"
> +#include <dlfcn.h>
> +#include "main/macros.h"
> +
> +/* The extensions that allow the megadriver stub to provide backward
> + * compatibility for the older DRI driver loader require GNU
> + * extensions from dlfcn.h.
> + */
> +#ifdef _GNU_SOURCE
> +
> +#define MEGADRIVER_STUB_MAX_EXTENSIONS 10
> +#define LIB_PATH_SUFFIX "_dri.so"
> +#define LIB_PATH_SUFFIX_LENGTH (sizeof(LIB_PATH_SUFFIX)-1)
> +
> +/* This is the table of extensions that the loader will dlsym() for.
> + *
> + * Initially it is empty for the megadriver stub, but the library
> + * contructor may initialize it based on the name of the library that
> + * is being loaded.
> + */
> +PUBLIC const __DRIextension *
> +__driDriverExtensions[MEGADRIVER_STUB_MAX_EXTENSIONS] = {
> + NULL
> +};
> +
> +/**
> + * This is a contructor function for the megadriver dynamic library.
constructor (typo)
> + *
> + * When the driver is dlopen'ed, this function will run. It will
> + * search for the name of the foo_dri.so file that was opened using
> + * the dladdr function.
> + *
> + * After finding foo's name, it will call __driDriverGetExtensions_foo
> + * and use the return to update __driDriverExtensions to enable
> + * compatibility with older DRI driver loaders.
> + */
> +__attribute__((constructor)) static void
> +megadriver_stub_init(void)
> +{
> + Dl_info info;
> + char *driver_name;
> + size_t name_len;
> + char *get_extensions_name;
> + const __DRIextension **(*get_extensions)(void);
> + const __DRIextension **extensions;
> + int i;
> +
> + /* Call dladdr on __driDriverExtensions. We are really
> + * interested in the returned info.dli_fname so we can
> + * figure out the path name of the library being loaded.
> + */
> + i = dladdr((void*) __driDriverExtensions, &info);
> + if (i == 0)
> + return;
> +
> + /* Search for the last '/' character in the path. */
> + driver_name = strrchr(info.dli_fname, '/');
> + if (driver_name != NULL) {
> + /* Skip '/' character */
> + driver_name++;
> + } else {
> + /* Try using the start of the path */
> + driver_name = (char*) info.dli_fname;
> + }
> +
> + /* Make sure the path ends with _dri.so */
> + name_len = strlen(driver_name);
> + i = name_len - LIB_PATH_SUFFIX_LENGTH;
> + if (i < 0 || strcmp(driver_name + i, LIB_PATH_SUFFIX) != 0)
> + return;
> +
> + /* Duplicate the string so we can modify it.
> + * So far we've been using info.dli_fname.
> + */
> + driver_name = strdup(driver_name);
> + if (!driver_name)
> + return;
> +
> + /* The path ends with _dri.so. Chop this part of the
> + * string off. Then we'll have the driver's final name.
> + */
> + driver_name[i] = '\0';
> +
> + i = asprintf(&get_extensions_name, "%s_%s",
> + __DRI_DRIVER_GET_EXTENSIONS, driver_name);
> + free(driver_name);
> + if (i == -1)
> + return;
> +
> + /* dlsym to get the driver's get extensions function. We
> + * don't have the dlopen handle, so we have to use
> + * RTLD_DEFAULT. It seems unlikely that the symbol will
> + * be found in another library, but this isn't optimal.
> + */
> + get_extensions = dlsym(RTLD_DEFAULT, get_extensions_name);
> + free(get_extensions_name);
> + if (!get_extensions)
> + return;
> +
> + /* Use the newer DRI loader entrypoint to find extensions.
> + * We will then expose these extensions via the older
> + * __driDriverExtensions symbol.
> + */
> + extensions = get_extensions();
> +
> + /* Copy the extensions into the __driDriverExtensions array
> + * we declared.
> + */
> + for (i = 0; i < ARRAY_SIZE(__driDriverExtensions); i++) {
> + __driDriverExtensions[i] = extensions[i];
> + if (extensions[i] == NULL)
> + break;
> + }
> +
> + /* If the driver had more extensions than we reserved, then
> + * bail out.
> + */
> + if (i == ARRAY_SIZE(__driDriverExtensions)) {
> + __driDriverExtensions[0] = NULL;
> + fprintf(stderr, "Megadriver stub did not reserve enough extension "
> + "slots.\n");
> + return;
> + }
> +}
> +
> +#endif // #ifdef _GNU_SOURCE
The usual convention is:
#endif /* _GNU_SOURCE */
>
> static const
> __DRIconfig **stub_error_init_screen(__DRIscreen *psp)
>
This is great work, Jordan.
Reviewed-by: Kenneth Graunke <kenneth at whitecape.org>
More information about the mesa-dev
mailing list