From 2a24a013bf3f554bb03c0f5af155d23dbb27b599 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Fri, 17 Sep 2010 07:32:17 -0400 Subject: [PATCH 1/8] loader: Merge dlloader directly into the loader This lets us drop some double-tracking of loaded modules too. If your OS is too lame to have libdl, fix that first. Reviewed-by: Alan Coopersmith Reviewed-by: Julien Cristau Signed-off-by: Adam Jackson --- hw/xfree86/loader/Makefile.am | 2 - hw/xfree86/loader/dlloader.c | 178 ---------------------------------- hw/xfree86/loader/dlloader.h | 33 ------- hw/xfree86/loader/loader.c | 76 ++++++++++++++- hw/xfree86/loader/loader.h | 3 - 5 files changed, 72 insertions(+), 220 deletions(-) delete mode 100644 hw/xfree86/loader/dlloader.c delete mode 100644 hw/xfree86/loader/dlloader.h diff --git a/hw/xfree86/loader/Makefile.am b/hw/xfree86/loader/Makefile.am index d3c17d173..2bac89ac9 100644 --- a/hw/xfree86/loader/Makefile.am +++ b/hw/xfree86/loader/Makefile.am @@ -8,7 +8,6 @@ INCLUDES = $(XORG_INCS) -I$(srcdir)/../parser -I$(top_srcdir)/miext/cw \ AM_CFLAGS = $(DIX_CFLAGS) $(XORG_CFLAGS) EXTRA_DIST = \ - dlloader.h \ loader.h \ loaderProcs.h \ sdksyms.sh @@ -18,7 +17,6 @@ libloader_la_SOURCES = \ loaderProcs.h \ loadext.c \ loadmod.c \ - dlloader.c \ os.c \ sdksyms.c libloader_la_LIBADD = $(DLOPEN_LIBS) diff --git a/hw/xfree86/loader/dlloader.c b/hw/xfree86/loader/dlloader.c deleted file mode 100644 index 18dcb76c6..000000000 --- a/hw/xfree86/loader/dlloader.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 1997 The XFree86 Project, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software - * and its documentation for any purpose is hereby granted without - * fee, provided that the above copyright notice appear in all copies - * and that both that copyright notice and this permission notice - * appear in supporting documentation, and that the name of the - * XFree86 Project, Inc. not be used in advertising or publicity - * pertaining to distribution of the software without specific, - * written prior permission. The Xfree86 Project, Inc. makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied - * warranty. - * - * THE XFREE86 PROJECT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE XFREE86 PROJECT, INC. BE LIABLE - * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* - * Once upon a time, X had multiple loader backends, three of which were - * essentially libdl reimplementations. This was nonsense so we chucked - * it, but we still retain the factorization between loader API and - * platform implementation. This file is the libdl implementation, and - * currently the only backend. If you find yourself porting to a platform - * without working libdl - hpux, win32, some forsaken a.out host, etc. - - * make a new backend rather than hacking up this file. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include "os.h" - -#include "loader.h" -#include "dlloader.h" - -#if defined(DL_LAZY) -#define DLOPEN_LAZY DL_LAZY -#elif defined(RTLD_LAZY) -#define DLOPEN_LAZY RTLD_LAZY -#elif defined(__FreeBSD__) -#define DLOPEN_LAZY 1 -#else -#define DLOPEN_LAZY 0 -#endif - -#if defined(LD_GLOBAL) -#define DLOPEN_GLOBAL LD_GLOBAL -#elif defined(RTLD_GLOBAL) -#define DLOPEN_GLOBAL RTLD_GLOBAL -#else -#define DLOPEN_GLOBAL 0 -#endif - -#if defined(CSRG_BASED) && !defined(__ELF__) -#define DLSYM_PREFIX "_" -#else -#define DLSYM_PREFIX "" -#endif - -/* Hooray, yet another open coded linked list! FIXME */ -typedef struct DLModuleList { - void *module; - struct DLModuleList *next; -} DLModuleList; - -static DLModuleList *dlModuleList = NULL; - -static void * -DLFindSymbolLocal(pointer module, const char *name) -{ - void *p; - char *n; - - static const char symPrefix[] = DLSYM_PREFIX; - - if (sizeof(symPrefix) > 1) { - n = malloc(strlen(symPrefix) + strlen(name) + 1); - sprintf(n, "%s%s", symPrefix, name); - name = n; - } - - p = dlsym(module, name); - - if (sizeof(symPrefix) > 1) - free(n); - - return p; -} - -static void *global_scope = NULL; - -void * -DLFindSymbol(const char *name) -{ - DLModuleList *l; - void *p; - - p = dlsym(RTLD_DEFAULT, name); - if (p != NULL) - return p; - - for (l = dlModuleList; l != NULL; l = l->next) { - p = DLFindSymbolLocal(l->module, name); - if (p) - return p; - } - - if (!global_scope) - global_scope = dlopen(NULL, DLOPEN_LAZY | DLOPEN_GLOBAL); - - if (global_scope) - return DLFindSymbolLocal(global_scope, name); - - return NULL; -} - -void * -DLLoadModule(loaderPtr modrec, int flags) -{ - void * dlfile; - DLModuleList *l; - int dlopen_flags; - - if (flags & LD_FLAG_GLOBAL) - dlopen_flags = DLOPEN_LAZY | DLOPEN_GLOBAL; - else - dlopen_flags = DLOPEN_LAZY; - dlfile = dlopen(modrec->name, dlopen_flags); - if (dlfile == NULL) { - ErrorF("dlopen: %s\n", dlerror()); - return NULL; - } - - l = malloc(sizeof(DLModuleList)); - l->module = dlfile; - l->next = dlModuleList; - dlModuleList = l; - - return (void *)dlfile; -} - -void -DLUnloadModule(void *modptr) -{ - DLModuleList *l, *p; - - /* remove it from dlModuleList. */ - if (dlModuleList->module == modptr) { - l = dlModuleList; - dlModuleList = l->next; - free(l); - } else { - p = dlModuleList; - for (l = dlModuleList->next; l != NULL; l = l->next) { - if (l->module == modptr) { - p->next = l->next; - free(l); - break; - } - p = l; - } - } - dlclose(modptr); -} diff --git a/hw/xfree86/loader/dlloader.h b/hw/xfree86/loader/dlloader.h deleted file mode 100644 index 8ae610f02..000000000 --- a/hw/xfree86/loader/dlloader.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 1997 Metro Link, Inc. - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Metro Link, Inc. not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Metro Link, Inc. makes no - * representations about the suitability of this software for any purpose. - * It is provided "as is" without express or implied warranty. - * - * METRO LINK, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL METRO LINK, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_XORG_CONFIG_H -#include -#endif - -#ifndef _DLLOADER_H -#define _DLLOADER_H - -extern void *DLLoadModule(loaderPtr, int flags); -extern void DLUnloadModule(void *); -extern void *DLFindSymbol(const char *name); - -#endif diff --git a/hw/xfree86/loader/loader.c b/hw/xfree86/loader/loader.c index e043bb233..d51ea928f 100644 --- a/hw/xfree86/loader/loader.c +++ b/hw/xfree86/loader/loader.c @@ -75,6 +75,33 @@ #include "xf86Priv.h" #include "compiler.h" +#ifdef HAVE_DLFCN_H + +#include +#include + +#if defined(DL_LAZY) +#define DLOPEN_LAZY DL_LAZY +#elif defined(RTLD_LAZY) +#define DLOPEN_LAZY RTLD_LAZY +#elif defined(__FreeBSD__) +#define DLOPEN_LAZY 1 +#else +#define DLOPEN_LAZY 0 +#endif + +#if defined(LD_GLOBAL) +#define DLOPEN_GLOBAL LD_GLOBAL +#elif defined(RTLD_GLOBAL) +#define DLOPEN_GLOBAL RTLD_GLOBAL +#else +#define DLOPEN_GLOBAL 0 +#endif + +#else +#error i have no dynamic linker and i must scream +#endif + extern void *xorg_symbols[]; #define MAX_HANDLE 256 @@ -154,6 +181,27 @@ LoaderInit(void) #endif } +static void * +do_dlopen(loaderPtr modrec, int flags) +{ + void *dlfile; + int dlopen_flags; + + if (flags & LD_FLAG_GLOBAL) + dlopen_flags = DLOPEN_LAZY | DLOPEN_GLOBAL; + else + dlopen_flags = DLOPEN_LAZY; + + dlfile = dlopen(modrec->name, dlopen_flags); + + if (dlfile == NULL) { + ErrorF("dlopen: %s\n", dlerror()); + return NULL; + } + + return dlfile; +} + /* Public Interface to the loader. */ int @@ -217,7 +265,7 @@ LoaderOpen(const char *module, const char *cname, int handle, tmp->handle = new_handle; tmp->module = moduleseq++; - if ((tmp->private = DLLoadModule(tmp, flags)) == NULL) { + if ((tmp->private = do_dlopen(tmp, flags)) == NULL) { xf86Msg(X_ERROR, "Failed to load %s\n", module); _LoaderListPop(new_handle); refCount[new_handle] = 0; @@ -245,9 +293,29 @@ LoaderHandleOpen(int handle) } void * -LoaderSymbol(const char *sym) +LoaderSymbol(const char *name) { - return (DLFindSymbol(sym)); + static void *global_scope = NULL; + loaderPtr l; + void *p; + + p = dlsym(RTLD_DEFAULT, name); + if (p != NULL) + return p; + + for (l = listHead; l != NULL; l = l->next) { + p = dlsym(l->private, name); + if (p) + return p; + } + + if (!global_scope) + global_scope = dlopen(NULL, DLOPEN_LAZY | DLOPEN_GLOBAL); + + if (global_scope) + return dlsym(global_scope, name); + + return NULL; } int @@ -270,7 +338,7 @@ LoaderUnload(int handle) while ((tmp = _LoaderListPop(handle)) != NULL) { xf86Msg(X_INFO, "Unloading %s\n", tmp->name); - DLUnloadModule(tmp->private); + dlclose(tmp->private); free(tmp->name); free(tmp->cname); free(tmp); diff --git a/hw/xfree86/loader/loader.h b/hw/xfree86/loader/loader.h index 6121e02c6..9695c6c59 100644 --- a/hw/xfree86/loader/loader.h +++ b/hw/xfree86/loader/loader.h @@ -91,7 +91,4 @@ extern unsigned long LoaderOptions; int LoaderOpen(const char *, const char *, int, int *, int *, int *, int); int LoaderHandleOpen(int); -/* Loader backends. */ -#include "dlloader.h" - #endif /* _LOADER_H */ From 3a26e7f459764d4aee71b2d7e25b113b729b94ac Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Fri, 17 Sep 2010 07:55:48 -0400 Subject: [PATCH 2/8] loader: Remove unused module serial number Reviewed-by: Alan Coopersmith Reviewed-by: Julien Cristau Signed-off-by: Adam Jackson --- hw/xfree86/loader/loader.c | 3 --- hw/xfree86/loader/loader.h | 1 - 2 files changed, 4 deletions(-) diff --git a/hw/xfree86/loader/loader.c b/hw/xfree86/loader/loader.c index d51ea928f..580d05914 100644 --- a/hw/xfree86/loader/loader.c +++ b/hw/xfree86/loader/loader.c @@ -107,8 +107,6 @@ extern void *xorg_symbols[]; #define MAX_HANDLE 256 static int refCount[MAX_HANDLE]; -static int moduleseq = 0; - /* Prototypes for static functions. */ static loaderPtr listHead = NULL; @@ -263,7 +261,6 @@ LoaderOpen(const char *module, const char *cname, int handle, tmp->name = strdup(module); tmp->cname = strdup(cname); tmp->handle = new_handle; - tmp->module = moduleseq++; if ((tmp->private = do_dlopen(tmp, flags)) == NULL) { xf86Msg(X_ERROR, "Failed to load %s\n", module); diff --git a/hw/xfree86/loader/loader.h b/hw/xfree86/loader/loader.h index 9695c6c59..42e1518e6 100644 --- a/hw/xfree86/loader/loader.h +++ b/hw/xfree86/loader/loader.h @@ -67,7 +67,6 @@ typedef struct _loader *loaderPtr; typedef struct _loader { int handle; /* Unique id used to remove symbols from * this module when it is unloaded */ - int module; /* Unique id to identify compilation units */ char *name; char *cname; void *private; /* format specific data */ From 09929da50503b559459f5b722c11647c47857fdb Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Fri, 17 Sep 2010 08:16:51 -0400 Subject: [PATCH 3/8] loader: Remove unused canonical name field Reviewed-by: Alan Coopersmith Reviewed-by: Julien Cristau Signed-off-by: Adam Jackson --- hw/xfree86/loader/loader.c | 6 ++---- hw/xfree86/loader/loader.h | 3 +-- hw/xfree86/loader/loadmod.c | 3 +-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/xfree86/loader/loader.c b/hw/xfree86/loader/loader.c index 580d05914..878cb398d 100644 --- a/hw/xfree86/loader/loader.c +++ b/hw/xfree86/loader/loader.c @@ -174,7 +174,7 @@ LoaderInit(void) path = uwcrtpath; /* fallback: try to get libcrt.a from the uccs */ else path = xcrtpath; /* get the libcrt.a we compiled with */ - LoaderOpen (path, "libcrt", 0, &errmaj, &errmin, &wasLoaded); + LoaderOpen (path, 0, &errmaj, &errmin, &wasLoaded); } #endif } @@ -203,7 +203,7 @@ do_dlopen(loaderPtr modrec, int flags) /* Public Interface to the loader. */ int -LoaderOpen(const char *module, const char *cname, int handle, +LoaderOpen(const char *module, int handle, int *errmaj, int *errmin, int *wasLoaded, int flags) { loaderPtr tmp; @@ -259,7 +259,6 @@ LoaderOpen(const char *module, const char *cname, int handle, tmp = _LoaderListPush(); tmp->name = strdup(module); - tmp->cname = strdup(cname); tmp->handle = new_handle; if ((tmp->private = do_dlopen(tmp, flags)) == NULL) { @@ -337,7 +336,6 @@ LoaderUnload(int handle) xf86Msg(X_INFO, "Unloading %s\n", tmp->name); dlclose(tmp->private); free(tmp->name); - free(tmp->cname); free(tmp); } diff --git a/hw/xfree86/loader/loader.h b/hw/xfree86/loader/loader.h index 42e1518e6..9dfc30758 100644 --- a/hw/xfree86/loader/loader.h +++ b/hw/xfree86/loader/loader.h @@ -68,7 +68,6 @@ typedef struct _loader { int handle; /* Unique id used to remove symbols from * this module when it is unloaded */ char *name; - char *cname; void *private; /* format specific data */ loaderPtr next; } loaderRec; @@ -87,7 +86,7 @@ extern const ModuleVersions LoaderVersionInfo; extern unsigned long LoaderOptions; /* Internal Functions */ -int LoaderOpen(const char *, const char *, int, int *, int *, int *, int); +int LoaderOpen(const char *, int, int *, int *, int *, int); int LoaderHandleOpen(int); #endif /* _LOADER_H */ diff --git a/hw/xfree86/loader/loadmod.c b/hw/xfree86/loader/loadmod.c index 615e8c691..a9d04b832 100644 --- a/hw/xfree86/loader/loadmod.c +++ b/hw/xfree86/loader/loadmod.c @@ -926,8 +926,7 @@ doLoadModule(const char *module, const char *path, const char **subdirlist, *errmin = 0; goto LoadModule_fail; } - ret->handle = LoaderOpen(found, name, 0, - errmaj, errmin, &wasLoaded, flags); + ret->handle = LoaderOpen(found, 0, errmaj, errmin, &wasLoaded, flags); if (ret->handle < 0) goto LoadModule_fail; From 2f003fe49697f8343c052dff2b3752eace814ea7 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Fri, 17 Sep 2010 09:02:13 -0400 Subject: [PATCH 4/8] loader: Remove the handle field from LoaderOpen This was always 0 from all the callers. Reviewed-by: Alan Coopersmith Reviewed-by: Julien Cristau Signed-off-by: Adam Jackson --- hw/xfree86/loader/loader.c | 32 +++++++++++++++----------------- hw/xfree86/loader/loader.h | 2 +- hw/xfree86/loader/loadmod.c | 2 +- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/hw/xfree86/loader/loader.c b/hw/xfree86/loader/loader.c index 878cb398d..baadbc416 100644 --- a/hw/xfree86/loader/loader.c +++ b/hw/xfree86/loader/loader.c @@ -174,7 +174,7 @@ LoaderInit(void) path = uwcrtpath; /* fallback: try to get libcrt.a from the uccs */ else path = xcrtpath; /* get the libcrt.a we compiled with */ - LoaderOpen (path, 0, &errmaj, &errmin, &wasLoaded); + LoaderOpen (path, &errmaj, &errmin, &wasLoaded, 0); } #endif } @@ -203,8 +203,8 @@ do_dlopen(loaderPtr modrec, int flags) /* Public Interface to the loader. */ int -LoaderOpen(const char *module, int handle, - int *errmaj, int *errmin, int *wasLoaded, int flags) +LoaderOpen(const char *module, int *errmaj, int *errmin, int *wasLoaded, + int flags) { loaderPtr tmp; int new_handle; @@ -214,22 +214,20 @@ LoaderOpen(const char *module, int handle, #endif /* Is the module already loaded? */ - if (handle >= 0) { - tmp = listHead; - while (tmp) { + tmp = listHead; + while (tmp) { #ifdef DEBUGLIST - ErrorF("strcmp(%x(%s),{%x} %x(%s))\n", module, module, - &(tmp->name), tmp->name, tmp->name); + ErrorF("strcmp(%x(%s),{%x} %x(%s))\n", module, module, + &(tmp->name), tmp->name, tmp->name); #endif - if (!strcmp(module, tmp->name)) { - refCount[tmp->handle]++; - if (wasLoaded) - *wasLoaded = 1; - xf86MsgVerb(X_INFO, 2, "Reloading %s\n", module); - return tmp->handle; - } - tmp = tmp->next; - } + if (!strcmp(module, tmp->name)) { + refCount[tmp->handle]++; + if (wasLoaded) + *wasLoaded = 1; + xf86MsgVerb(X_INFO, 2, "Reloading %s\n", module); + return tmp->handle; + } + tmp = tmp->next; } /* diff --git a/hw/xfree86/loader/loader.h b/hw/xfree86/loader/loader.h index 9dfc30758..4bb571e69 100644 --- a/hw/xfree86/loader/loader.h +++ b/hw/xfree86/loader/loader.h @@ -86,7 +86,7 @@ extern const ModuleVersions LoaderVersionInfo; extern unsigned long LoaderOptions; /* Internal Functions */ -int LoaderOpen(const char *, int, int *, int *, int *, int); +int LoaderOpen(const char *, int *, int *, int *, int); int LoaderHandleOpen(int); #endif /* _LOADER_H */ diff --git a/hw/xfree86/loader/loadmod.c b/hw/xfree86/loader/loadmod.c index a9d04b832..e41e0c8d9 100644 --- a/hw/xfree86/loader/loadmod.c +++ b/hw/xfree86/loader/loadmod.c @@ -926,7 +926,7 @@ doLoadModule(const char *module, const char *path, const char **subdirlist, *errmin = 0; goto LoadModule_fail; } - ret->handle = LoaderOpen(found, 0, errmaj, errmin, &wasLoaded, flags); + ret->handle = LoaderOpen(found, errmaj, errmin, &wasLoaded, flags); if (ret->handle < 0) goto LoadModule_fail; From 0438002cd238011f33dbf176c555de5e380ba77e Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Fri, 17 Sep 2010 09:13:04 -0400 Subject: [PATCH 5/8] loader: include cleanup Reviewed-by: Alan Coopersmith Reviewed-by: Julien Cristau Signed-off-by: Adam Jackson --- hw/xfree86/loader/loader.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/hw/xfree86/loader/loader.c b/hw/xfree86/loader/loader.c index baadbc416..22d8273d3 100644 --- a/hw/xfree86/loader/loader.c +++ b/hw/xfree86/loader/loader.c @@ -54,18 +54,10 @@ #include #include #include -#if defined(UseMMAP) || (defined(linux) && defined(__ia64__)) -#include -#endif #include #include #include #include -#if defined(linux) && \ - (defined(__alpha__) || defined(__powerpc__) || defined(__ia64__) \ - || defined(__amd64__)) -#include -#endif #include #include "os.h" From ab7f057ce9df4e905b12cebc1e587b9a7f200418 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Fri, 17 Sep 2010 11:19:17 -0400 Subject: [PATCH 6/8] loader: Remove a silly layer of reference counting libdl will refcount objects for us just fine, thanks. Reviewed-by: Alan Coopersmith Reviewed-by: Julien Cristau Signed-off-by: Adam Jackson --- hw/xfree86/loader/loader.c | 167 +++----------------------------- hw/xfree86/loader/loader.h | 18 +--- hw/xfree86/loader/loaderProcs.h | 5 +- hw/xfree86/loader/loadmod.c | 78 +++++++-------- 4 files changed, 51 insertions(+), 217 deletions(-) diff --git a/hw/xfree86/loader/loader.c b/hw/xfree86/loader/loader.c index 22d8273d3..89218312a 100644 --- a/hw/xfree86/loader/loader.c +++ b/hw/xfree86/loader/loader.c @@ -96,41 +96,6 @@ extern void *xorg_symbols[]; -#define MAX_HANDLE 256 -static int refCount[MAX_HANDLE]; - -/* Prototypes for static functions. */ -static loaderPtr listHead = NULL; - -static loaderPtr -_LoaderListPush(void) -{ - loaderPtr item = calloc(1, sizeof(struct _loader)); - - item->next = listHead; - listHead = item; - - return item; -} - -static loaderPtr -_LoaderListPop(int handle) -{ - loaderPtr item = listHead; - loaderPtr *bptr = &listHead; /* pointer to previous node */ - - while (item) { - if (item->handle == handle) { - *bptr = item->next; /* remove this from the list */ - return item; - } - bptr = &(item->next); - item = item->next; - } - - return 0; -} - void LoaderInit(void) { @@ -171,130 +136,41 @@ LoaderInit(void) #endif } -static void * -do_dlopen(loaderPtr modrec, int flags) -{ - void *dlfile; - int dlopen_flags; - - if (flags & LD_FLAG_GLOBAL) - dlopen_flags = DLOPEN_LAZY | DLOPEN_GLOBAL; - else - dlopen_flags = DLOPEN_LAZY; - - dlfile = dlopen(modrec->name, dlopen_flags); - - if (dlfile == NULL) { - ErrorF("dlopen: %s\n", dlerror()); - return NULL; - } - - return dlfile; -} - /* Public Interface to the loader. */ -int -LoaderOpen(const char *module, int *errmaj, int *errmin, int *wasLoaded, - int flags) +void * +LoaderOpen(const char *module, int *errmaj, int *errmin) { - loaderPtr tmp; - int new_handle; + void *ret; #if defined(DEBUG) ErrorF("LoaderOpen(%s)\n", module); #endif - /* Is the module already loaded? */ - tmp = listHead; - while (tmp) { -#ifdef DEBUGLIST - ErrorF("strcmp(%x(%s),{%x} %x(%s))\n", module, module, - &(tmp->name), tmp->name, tmp->name); -#endif - if (!strcmp(module, tmp->name)) { - refCount[tmp->handle]++; - if (wasLoaded) - *wasLoaded = 1; - xf86MsgVerb(X_INFO, 2, "Reloading %s\n", module); - return tmp->handle; - } - tmp = tmp->next; - } - - /* - * OK, it's a new one. Add it. - */ xf86Msg(X_INFO, "Loading %s\n", module); - if (wasLoaded) - *wasLoaded = 0; - /* - * Find a free handle. - */ - new_handle = 1; - while (new_handle < MAX_HANDLE && refCount[new_handle]) - new_handle++; - - if (new_handle == MAX_HANDLE) { - xf86Msg(X_ERROR, "Out of loader space\n"); /* XXX */ - if (errmaj) - *errmaj = LDR_NOSPACE; - if (errmin) - *errmin = LDR_NOSPACE; - return -1; - } - - refCount[new_handle] = 1; - - tmp = _LoaderListPush(); - tmp->name = strdup(module); - tmp->handle = new_handle; - - if ((tmp->private = do_dlopen(tmp, flags)) == NULL) { - xf86Msg(X_ERROR, "Failed to load %s\n", module); - _LoaderListPop(new_handle); - refCount[new_handle] = 0; + if (!(ret = dlopen(module, DLOPEN_LAZY | DLOPEN_GLOBAL))) { + xf86Msg(X_ERROR, "Failed to load %s: %s\n", module, dlerror()); if (errmaj) *errmaj = LDR_NOLOAD; if (errmin) *errmin = LDR_NOLOAD; - return -1; + return NULL; } - return new_handle; -} - -int -LoaderHandleOpen(int handle) -{ - if (handle < 0 || handle >= MAX_HANDLE) - return -1; - - if (!refCount[handle]) - return -1; - - refCount[handle]++; - return handle; + return ret; } void * LoaderSymbol(const char *name) { static void *global_scope = NULL; - loaderPtr l; void *p; p = dlsym(RTLD_DEFAULT, name); if (p != NULL) return p; - for (l = listHead; l != NULL; l = l->next) { - p = dlsym(l->private, name); - if (p) - return p; - } - if (!global_scope) global_scope = dlopen(NULL, DLOPEN_LAZY | DLOPEN_GLOBAL); @@ -304,32 +180,11 @@ LoaderSymbol(const char *name) return NULL; } -int -LoaderUnload(int handle) +void +LoaderUnload(const char *name, void *handle) { - loaderRec fakeHead; - loaderPtr tmp = &fakeHead; - - if (handle < 0 || handle >= MAX_HANDLE) - return -1; - - /* - * check the reference count, only free it if it goes to zero - */ - if (--refCount[handle]) - return 0; - /* - * find the loaderRecs associated with this handle. - */ - - while ((tmp = _LoaderListPop(handle)) != NULL) { - xf86Msg(X_INFO, "Unloading %s\n", tmp->name); - dlclose(tmp->private); - free(tmp->name); - free(tmp); - } - - return 0; + xf86Msg(X_INFO, "Unloading %s\n", name); + dlclose(handle); } unsigned long LoaderOptions = 0; diff --git a/hw/xfree86/loader/loader.h b/hw/xfree86/loader/loader.h index 4bb571e69..edea91133 100644 --- a/hw/xfree86/loader/loader.h +++ b/hw/xfree86/loader/loader.h @@ -57,21 +57,6 @@ #include #include -/* LoadModule proc flags; LD_FLAG_GLOBAL adds symbols to global - * namespace, default is to keep symbols local to module. */ -#define LD_FLAG_GLOBAL 1 - -typedef struct _loader *loaderPtr; - -/* Each module loaded has a loaderRec */ -typedef struct _loader { - int handle; /* Unique id used to remove symbols from - * this module when it is unloaded */ - char *name; - void *private; /* format specific data */ - loaderPtr next; -} loaderRec; - /* Compiled-in version information */ typedef struct { int xf86Version; @@ -86,7 +71,6 @@ extern const ModuleVersions LoaderVersionInfo; extern unsigned long LoaderOptions; /* Internal Functions */ -int LoaderOpen(const char *, int *, int *, int *, int); -int LoaderHandleOpen(int); +void * LoaderOpen(const char *, int *, int *); #endif /* _LOADER_H */ diff --git a/hw/xfree86/loader/loaderProcs.h b/hw/xfree86/loader/loaderProcs.h index a7925ecee..0b67c5f7a 100644 --- a/hw/xfree86/loader/loaderProcs.h +++ b/hw/xfree86/loader/loaderProcs.h @@ -60,7 +60,8 @@ typedef struct module_desc { struct module_desc *sib; struct module_desc *parent; char *name; - int handle; + char *path; + void *handle; ModuleSetupProc SetupProc; ModuleTearDownProc TearDownProc; void *TearDownData; /* returned from SetupProc */ @@ -81,7 +82,7 @@ void UnloadDriver(ModuleDescPtr); void LoaderSetPath(const char *path); void LoaderSortExtensions(void); -int LoaderUnload(int); +void LoaderUnload(const char *, void *); unsigned long LoaderGetModuleVersion(ModuleDescPtr mod); void LoaderResetOptions(void); diff --git a/hw/xfree86/loader/loadmod.c b/hw/xfree86/loader/loadmod.c index e41e0c8d9..6e6522774 100644 --- a/hw/xfree86/loader/loadmod.c +++ b/hw/xfree86/loader/loadmod.c @@ -83,8 +83,7 @@ static char *LoaderGetCanonicalName(const char *, PatternPtr); static void RemoveChild(ModuleDescPtr); static ModuleDescPtr doLoadModule(const char *, const char *, const char **, const char **, pointer, - const XF86ModReqInfo *, int *, int *, - int flags); + const XF86ModReqInfo *, int *, int *); const ModuleVersions LoaderVersionInfo = { XORG_VERSION_CURRENT, @@ -765,7 +764,7 @@ LoadSubModule(pointer _parent, const char *module, } submod = doLoadModule(module, NULL, subdirlist, patternlist, options, - modreq, errmaj, errmin, LD_FLAG_GLOBAL); + modreq, errmaj, errmin); if (submod && submod != (ModuleDescPtr) 1) { parent->child = AddSibling(parent->child, submod); submod->parent = parent; @@ -776,18 +775,10 @@ LoadSubModule(pointer _parent, const char *module, static ModuleDescPtr NewModuleDesc(const char *name) { - ModuleDescPtr mdp = malloc(sizeof(ModuleDesc)); + ModuleDescPtr mdp = calloc(1, sizeof(ModuleDesc)); - if (mdp) { - mdp->child = NULL; - mdp->sib = NULL; - mdp->parent = NULL; + if (mdp) mdp->name = xstrdup(name); - mdp->handle = -1; - mdp->SetupProc = NULL; - mdp->TearDownProc = NULL; - mdp->TearDownData = NULL; - } return mdp; } @@ -796,6 +787,7 @@ ModuleDescPtr DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent) { ModuleDescPtr ret; + int errmaj, errmin; if (!mod) return NULL; @@ -804,10 +796,11 @@ DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent) if (ret == NULL) return NULL; - if (LoaderHandleOpen(mod->handle) == -1) - return NULL; + if (!(ret->handle = LoaderOpen(mod->path, &errmaj, &errmin))) { + free(ret); + return NULL; + } - ret->handle = mod->handle; ret->SetupProc = mod->SetupProc; ret->TearDownProc = mod->TearDownProc; ret->TearDownData = NULL; @@ -815,6 +808,7 @@ DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent) ret->sib = DuplicateModule(mod->sib, parent); ret->parent = parent; ret->VersionInfo = mod->VersionInfo; + ret->path = strdup(mod->path); return ret; } @@ -830,7 +824,7 @@ static ModuleDescPtr doLoadModule(const char *module, const char *path, const char **subdirlist, const char **patternlist, pointer options, const XF86ModReqInfo * modreq, - int *errmaj, int *errmin, int flags) + int *errmaj, int *errmin) { XF86ModuleData *initdata = NULL; char **pathlist = NULL; @@ -839,7 +833,6 @@ doLoadModule(const char *module, const char *path, const char **subdirlist, char **path_elem = NULL; char *p = NULL; ModuleDescPtr ret = NULL; - int wasLoaded = 0; PatternPtr patterns = NULL; int noncanonical = 0; char *m = NULL; @@ -926,9 +919,10 @@ doLoadModule(const char *module, const char *path, const char **subdirlist, *errmin = 0; goto LoadModule_fail; } - ret->handle = LoaderOpen(found, errmaj, errmin, &wasLoaded, flags); + ret->handle = LoaderOpen(found, errmaj, errmin); if (ret->handle < 0) goto LoadModule_fail; + ret->path = strdup(found); /* drop any explicit suffix from the module name */ p = strchr(name, '.'); @@ -959,26 +953,24 @@ doLoadModule(const char *module, const char *path, const char **subdirlist, setup = initdata->setup; teardown = initdata->teardown; - if (!wasLoaded) { - if (vers) { - if (!CheckVersion(module, vers, modreq)) { - if (errmaj) - *errmaj = LDR_MISMATCH; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - } else { - xf86Msg(X_ERROR, - "LoadModule: Module %s does not supply" - " version information\n", module); - if (errmaj) - *errmaj = LDR_INVALID; - if (errmin) - *errmin = 0; - goto LoadModule_fail; - } - } + if (vers) { + if (!CheckVersion(module, vers, modreq)) { + if (errmaj) + *errmaj = LDR_MISMATCH; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } + } else { + xf86Msg(X_ERROR, + "LoadModule: Module %s does not supply" + " version information\n", module); + if (errmaj) + *errmaj = LDR_INVALID; + if (errmin) + *errmin = 0; + goto LoadModule_fail; + } if (setup) ret->SetupProc = setup; if (teardown) @@ -1066,7 +1058,7 @@ LoadModule(const char *module, const char *path, const char **subdirlist, const XF86ModReqInfo * modreq, int *errmaj, int *errmin) { return doLoadModule(module, path, subdirlist, patternlist, options, - modreq, errmaj, errmin, LD_FLAG_GLOBAL); + modreq, errmaj, errmin); } void @@ -1088,12 +1080,13 @@ UnloadModuleOrDriver(ModuleDescPtr mod) if ((mod->TearDownProc) && (mod->TearDownData)) mod->TearDownProc(mod->TearDownData); - LoaderUnload(mod->handle); + LoaderUnload(mod->name, mod->handle); if (mod->child) UnloadModuleOrDriver(mod->child); if (mod->sib) UnloadModuleOrDriver(mod->sib); + free(mod->path); free(mod->name); free(mod); } @@ -1110,13 +1103,14 @@ UnloadSubModule(pointer _mod) if ((mod->TearDownProc) && (mod->TearDownData)) mod->TearDownProc(mod->TearDownData); - LoaderUnload(mod->handle); + LoaderUnload(mod->name, mod->handle); RemoveChild(mod); if (mod->child) UnloadModuleOrDriver(mod->child); + free(mod->path); free(mod->name); free(mod); } From 6130170e7e9b64c611ee942ec3455dd1a185193d Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Sat, 18 Sep 2010 06:41:35 -0400 Subject: [PATCH 7/8] xfree86: Remove unused refcounting from input drivers Reviewed-by: Alan Coopersmith Reviewed-by: Julien Cristau Signed-off-by: Adam Jackson --- hw/xfree86/common/xf86Helper.c | 5 ----- hw/xfree86/common/xf86Xinput.h | 1 - 2 files changed, 6 deletions(-) diff --git a/hw/xfree86/common/xf86Helper.c b/hw/xfree86/common/xf86Helper.c index 90e0c6702..0172acec2 100644 --- a/hw/xfree86/common/xf86Helper.c +++ b/hw/xfree86/common/xf86Helper.c @@ -125,7 +125,6 @@ xf86AddInputDriver(InputDriverPtr driver, pointer module, int flags) xnfalloc(sizeof(InputDriverRec)); *xf86InputDriverList[xf86NumInputDrivers - 1] = *driver; xf86InputDriverList[xf86NumInputDrivers - 1]->module = module; - xf86InputDriverList[xf86NumInputDrivers - 1]->refCount = 0; } void @@ -284,7 +283,6 @@ xf86AllocateInput(InputDriverPtr drv, int flags) return NULL; new->drv = drv; - drv->refCount++; new->module = DuplicateModule(drv->module, NULL); for (prev = &xf86InputDevs; *prev; prev = &(*prev)->next) @@ -320,9 +318,6 @@ xf86DeleteInput(InputInfoPtr pInp, int flags) if (pInp->module) UnloadModule(pInp->module); - if (pInp->drv) - pInp->drv->refCount--; - /* This should *really* be handled in drv->UnInit(dev) call instead, but * if the driver forgets about it make sure we free it or at least crash * with flying colors */ diff --git a/hw/xfree86/common/xf86Xinput.h b/hw/xfree86/common/xf86Xinput.h index 20a3f1bab..7b60cdfea 100644 --- a/hw/xfree86/common/xf86Xinput.h +++ b/hw/xfree86/common/xf86Xinput.h @@ -103,7 +103,6 @@ typedef struct _InputDriverRec { struct _LocalDeviceRec *pInfo, int flags); pointer module; - int refCount; } InputDriverRec, *InputDriverPtr; /* This is to input devices what the ScrnInfoRec is to screens. */ From 682a3ee60867da027fe1bcda0c8587dd3db9d58e Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Sat, 18 Sep 2010 07:27:13 -0400 Subject: [PATCH 8/8] xfree86: Remove useless module setup functions where appropriate Reviewed-by: Alan Coopersmith Reviewed-by: Julien Cristau Signed-off-by: Adam Jackson --- hw/xfree86/fbdevhw/fbdevhw.c | 10 +--------- hw/xfree86/i2c/bt829_module.c | 9 +-------- hw/xfree86/i2c/fi1236_module.c | 9 +-------- hw/xfree86/i2c/msp3430_module.c | 9 +-------- hw/xfree86/i2c/tda8425_module.c | 9 +-------- hw/xfree86/i2c/tda9850_module.c | 9 +-------- hw/xfree86/i2c/tda9885_module.c | 9 +-------- hw/xfree86/i2c/uda1380_module.c | 9 +-------- hw/xfree86/int10/xf86int10module.c | 23 +---------------------- hw/xfree86/vbe/vbe_module.c | 10 +--------- 10 files changed, 10 insertions(+), 96 deletions(-) diff --git a/hw/xfree86/fbdevhw/fbdevhw.c b/hw/xfree86/fbdevhw/fbdevhw.c index f50d562ca..a5b59e762 100644 --- a/hw/xfree86/fbdevhw/fbdevhw.c +++ b/hw/xfree86/fbdevhw/fbdevhw.c @@ -21,8 +21,6 @@ #define PAGE_MASK (~(getpagesize() - 1)) -static MODULESETUPPROTO(fbdevhwSetup); - static XF86ModuleVersionInfo fbdevHWVersRec = { "fbdevhw", @@ -39,16 +37,10 @@ static XF86ModuleVersionInfo fbdevHWVersRec = _X_EXPORT XF86ModuleData fbdevhwModuleData = { &fbdevHWVersRec, - fbdevhwSetup, + NULL, NULL }; -static pointer -fbdevhwSetup(pointer module, pointer opts, int *errmaj, int *errmin) -{ - return (pointer)1; -} - #include #include #include diff --git a/hw/xfree86/i2c/bt829_module.c b/hw/xfree86/i2c/bt829_module.c index c885b8e10..d87dfa7a0 100644 --- a/hw/xfree86/i2c/bt829_module.c +++ b/hw/xfree86/i2c/bt829_module.c @@ -4,8 +4,6 @@ #include "xf86Module.h" -static MODULESETUPPROTO(bt829Setup); - static XF86ModuleVersionInfo bt829VersRec = { "bt829", @@ -20,9 +18,4 @@ static XF86ModuleVersionInfo bt829VersRec = {0,0,0,0} }; -_X_EXPORT XF86ModuleData bt829ModuleData = { &bt829VersRec, bt829Setup, NULL }; - -static pointer -bt829Setup(pointer module, pointer opts, int *errmaj, int *errmin) { - return (pointer)1; -} +_X_EXPORT XF86ModuleData bt829ModuleData = { &bt829VersRec, NULL, NULL }; diff --git a/hw/xfree86/i2c/fi1236_module.c b/hw/xfree86/i2c/fi1236_module.c index 4016ad0d4..a63f92253 100644 --- a/hw/xfree86/i2c/fi1236_module.c +++ b/hw/xfree86/i2c/fi1236_module.c @@ -4,8 +4,6 @@ #include "xf86Module.h" -static MODULESETUPPROTO(fi1236Setup); - static XF86ModuleVersionInfo fi1236VersRec = { "fi1236", @@ -22,11 +20,6 @@ static XF86ModuleVersionInfo fi1236VersRec = _X_EXPORT XF86ModuleData fi1236ModuleData = { &fi1236VersRec, - fi1236Setup, + NULL, NULL }; - -static pointer -fi1236Setup(pointer module, pointer opts, int *errmaj, int *errmin) { - return (pointer)1; -} diff --git a/hw/xfree86/i2c/msp3430_module.c b/hw/xfree86/i2c/msp3430_module.c index 66b14a277..2ebf1f7b6 100644 --- a/hw/xfree86/i2c/msp3430_module.c +++ b/hw/xfree86/i2c/msp3430_module.c @@ -4,8 +4,6 @@ #include "xf86Module.h" -static MODULESETUPPROTO(msp3430Setup); - static XF86ModuleVersionInfo msp3430VersRec = { "msp3430", @@ -22,11 +20,6 @@ static XF86ModuleVersionInfo msp3430VersRec = _X_EXPORT XF86ModuleData msp3430ModuleData = { &msp3430VersRec, - msp3430Setup, + NULL, NULL }; - -static pointer -msp3430Setup(pointer module, pointer opts, int *errmaj, int *errmin) { - return (pointer)1; -} diff --git a/hw/xfree86/i2c/tda8425_module.c b/hw/xfree86/i2c/tda8425_module.c index 7906e5ea5..ef301b70b 100644 --- a/hw/xfree86/i2c/tda8425_module.c +++ b/hw/xfree86/i2c/tda8425_module.c @@ -4,8 +4,6 @@ #include "xf86Module.h" -static MODULESETUPPROTO(tda8425Setup); - static XF86ModuleVersionInfo tda8425VersRec = { "tda8425", @@ -22,11 +20,6 @@ static XF86ModuleVersionInfo tda8425VersRec = _X_EXPORT XF86ModuleData tda8425ModuleData = { &tda8425VersRec, - tda8425Setup, + NULL, NULL }; - -static pointer -tda8425Setup(pointer module, pointer opts, int *errmaj, int *errmin) { - return (pointer)1; -} diff --git a/hw/xfree86/i2c/tda9850_module.c b/hw/xfree86/i2c/tda9850_module.c index 84f7e861e..8256e7862 100644 --- a/hw/xfree86/i2c/tda9850_module.c +++ b/hw/xfree86/i2c/tda9850_module.c @@ -4,8 +4,6 @@ #include "xf86Module.h" -static MODULESETUPPROTO(tda9850Setup); - static XF86ModuleVersionInfo tda9850VersRec = { "tda9850", @@ -22,11 +20,6 @@ static XF86ModuleVersionInfo tda9850VersRec = _X_EXPORT XF86ModuleData tda9850ModuleData = { &tda9850VersRec, - tda9850Setup, + NULL, NULL }; - -static pointer -tda9850Setup(pointer module, pointer opts, int *errmaj, int *errmin) { - return (pointer)1; -} diff --git a/hw/xfree86/i2c/tda9885_module.c b/hw/xfree86/i2c/tda9885_module.c index 0ce85bba3..3394c184f 100644 --- a/hw/xfree86/i2c/tda9885_module.c +++ b/hw/xfree86/i2c/tda9885_module.c @@ -4,8 +4,6 @@ #include "xf86Module.h" -static MODULESETUPPROTO(tda9885Setup); - static XF86ModuleVersionInfo tda9885VersRec = { "tda9885", @@ -22,11 +20,6 @@ static XF86ModuleVersionInfo tda9885VersRec = _X_EXPORT XF86ModuleData tda9885ModuleData = { &tda9885VersRec, - tda9885Setup, + NULL, NULL }; - -static pointer -tda9885Setup(pointer module, pointer opts, int *errmaj, int *errmin) { - return (pointer)1; -} diff --git a/hw/xfree86/i2c/uda1380_module.c b/hw/xfree86/i2c/uda1380_module.c index 895f8c6f2..67b623ea0 100644 --- a/hw/xfree86/i2c/uda1380_module.c +++ b/hw/xfree86/i2c/uda1380_module.c @@ -4,8 +4,6 @@ #include "xf86Module.h" -static MODULESETUPPROTO(uda1380Setup); - static XF86ModuleVersionInfo uda1380VersRec = { "uda1380", @@ -22,11 +20,6 @@ static XF86ModuleVersionInfo uda1380VersRec = _X_EXPORT XF86ModuleData uda1380ModuleData = { &uda1380VersRec, - uda1380Setup, + NULL, NULL }; - -static pointer -uda1380Setup(pointer module, pointer opts, int *errmaj, int *errmin) { - return (pointer)1; -} diff --git a/hw/xfree86/int10/xf86int10module.c b/hw/xfree86/int10/xf86int10module.c index b4e5865da..41e349e7a 100644 --- a/hw/xfree86/int10/xf86int10module.c +++ b/hw/xfree86/int10/xf86int10module.c @@ -22,8 +22,6 @@ #define combine(a,b) concat(a,b) #define NAME(x) combine(MOD_NAME,x) -static MODULESETUPPROTO(NAME(Setup)); - static XF86ModuleVersionInfo NAME(VersRec) = { STRING(NAME( )), @@ -40,25 +38,6 @@ static XF86ModuleVersionInfo NAME(VersRec) = _X_EXPORT XF86ModuleData NAME(ModuleData) = { &NAME(VersRec), - NAME(Setup), + NULL, NULL }; - -static pointer -NAME(Setup)(pointer module, pointer opts, int *errmaj, int *errmin) -{ - static Bool setupDone = FALSE; - - if (!setupDone) { - setupDone = TRUE; - /* - * Tell the loader about symbols from other modules that this module - * might refer to. - */ - } - /* - * The return value must be non-NULL on success even though there - * is no TearDownProc. - */ - return (pointer)1; -} diff --git a/hw/xfree86/vbe/vbe_module.c b/hw/xfree86/vbe/vbe_module.c index cf37ef951..e8f2e7490 100644 --- a/hw/xfree86/vbe/vbe_module.c +++ b/hw/xfree86/vbe/vbe_module.c @@ -6,8 +6,6 @@ #include "xf86str.h" #include "vbe.h" -static MODULESETUPPROTO(vbeSetup); - static XF86ModuleVersionInfo vbeVersRec = { "vbe", @@ -22,10 +20,4 @@ static XF86ModuleVersionInfo vbeVersRec = {0,0,0,0} }; -_X_EXPORT XF86ModuleData vbeModuleData = { &vbeVersRec, vbeSetup, NULL }; - -static pointer -vbeSetup(pointer module, pointer opts, int *errmaj, int *errmin) -{ - return (pointer)1; -} +_X_EXPORT XF86ModuleData vbeModuleData = { &vbeVersRec, NULL, NULL };