loader: Remove a silly layer of reference counting
libdl will refcount objects for us just fine, thanks. Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com> Reviewed-by: Julien Cristau <jcristau@debian.org> Signed-off-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
		
							parent
							
								
									0438002cd2
								
							
						
					
					
						commit
						ab7f057ce9
					
				| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,21 +57,6 @@
 | 
			
		|||
#include <X11/Xfuncproto.h>
 | 
			
		||||
#include <X11/Xmd.h>
 | 
			
		||||
 | 
			
		||||
/* 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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue