c - dlclose does not close library open file handles -
i dynamically loading library dlopen
, closing dlclose
. expected library resources freed once dlclose
completed, there still open file descriptors library after dlclose
call. wondering how make sure library unloaded in middle of program execution, such cleans of resources.
my code below:
#include <cl/cl.h> #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <dlfcn.h> #include <string.h> #include <dirent.h> #include <fcntl.h> #include <unistd.h> #define max_path_length 80 int deviceq() { cl_int ret; void * libhandle = dlopen("/usr/lib64/libopencl.so", rtld_lazy); cl_int (* clgetplatformids)(cl_uint, cl_platform_id*, cl_uint*) = dlsym( libhandle, "clgetplatformids" ); cl_int (* clgetdeviceids)(cl_platform_id, cl_device_type, cl_uint, cl_device_id*, cl_uint*) = dlsym(libhandle, "clgetdeviceids"); /********************** preamble **************************************/ cl_device_id device_id = null; cl_platform_id platform_id = null; cl_uint ret_num_devices; cl_uint ret_num_platforms; ret = clgetplatformids(1, &platform_id, &ret_num_platforms); if (ret != cl_success) { perror("failed platform ids"); } else if (ret_num_platforms != 1) { fprintf(stderr, "number of platforms returned %d\n", ret_num_platforms); exit(1); } printf("read platform ids\n"); ret = clgetdeviceids(platform_id, cl_device_type_gpu, 1, &device_id, &ret_num_devices); if (ret != cl_success) { perror("failed device ids"); } else if (ret_num_devices != 1) { fprintf(stderr, "number of returned devices %d\n", ret_num_devices); exit(1); } printf("read device ids\n"); /********************** preamble **************************************/ /***************** release , free ****************************/ dlclose(libhandle); /***************** release , free ****************************/ return 0; } size_t closefiledescriptors(void ** arr) { // step 1 - pid pid_t pid = getpid(); //printf("pid %d\n", pid); char path[max_path_length]; memset(path, '\0', max_path_length); sprintf(path, "/proc/%d/fd", pid); int fd; dir * d = opendir(path); struct dirent *dir; struct stat s; char dirpath[max_path_length]; char realpath[max_path_length]; size_t index = 0; if (d) { while ((dir = readdir(d)) != null) { if (strcmp(dir->d_name, ".") != 0 && strcmp(dir->d_name, "..") != 0) { fd = atoi(dir->d_name); if (fstat(fd, &s) != 0) { perror("fstat failed"); } memset(dirpath, '\0', max_path_length); strcpy(dirpath, path); strcat(dirpath, "/"); strcat(dirpath, dir->d_name); #ifdef s_iflnk if (s.st_mode & s_iflnk) { #else if (s_islnk(s.st_mode)) { #endif memset(realpath, '\0', max_path_length); #ifdef readlink readlink(dirpath, realpath, max_path_length); printf("%s -> %s\n", dirpath, realpath); #else printf("[readlink not defined] %s\n", dirpath); #endif } else { printf("not link: %s (proceeding anyway)\n", dirpath); //printf("not link: %s (ignoring)\n", dirpath); //continue; } if (fd > 2) { //int fdflags = fcntl(fd, f_getfd); int fdflags = fcntl(fd, f_getfl); if (fdflags == -1) { perror("fcntl failed"); } //off_t offset = lseek(fd, 0, seek_cur); off_t offset = 0; if (offset == -1) { perror("lseek failed"); } if (arr != null) { /* arr[index] = (filedata *) malloc(sizeof (filedata)); arr[index]->flags = fdflags; arr[index]->offset = offset; arr[index]->fd = fd; strcpy(arr[index]->fdpath, realpath);*/ } index++; // ignore stdin, stdout, stderr printf("closing fd %d (flags %d, offset %zd)\n", fd, fdflags, offset); close(fd); } } } closedir(d); } else { fprintf(stderr, "could not open directory %s\n", path); } return index; } int main () { deviceq(); printf("=> closing open file descriptors\n"); closefiledescriptors (null); deviceq(); return 0; }
your expectation wrong. when call dlclose(3), "plugin" (actually shared object) "closed" (actually, may be munmap
-ed), not resources (in particular file descriptors, , possibly heap allocated memory) has used.
in addition, on linux specifically, dlclose
calling so-called destructor functions of plugin (those declared __attribute__((destructor))
, read function attributes in gcc).
if coding shared library, might design some resources released @ dlclose
time (by having appropriate finalizations run thru destructor functions). in general, not possible (and should documented convention).
resources address space in virtual memory (obtained mmap(2) etc...) , file descriptors (obtained open(2), socket(2), pipe(2) etc etc...) global (and common) entire process. possible (and legitimate, if documented) acquire resource (e.g. open file descriptor) in 1 shared library , release in 1 (or in main program).
since resource "belongs" entire process, makes no sense speak of releasing resources acquired library.
so closefiledescriptors
quite huge mistake (and leaks other resources).
(iirc, opencl api has way release resources, e.g. devices, contexts, kernels, etc.... forgot ugly details; see clreleasecontext
, clreleasememobject
, many more, including implementation specific ones.)
reading more garbage collection widen mind.
read drepper's paper: how write shared library & credentials(7)
if absolutely need release opencl related resources early, more sensible way might start different child process dedicated opencl things, , use clever ipc mechanisms (e.g. pipe(7), shm_overview(7), sem_overview(7), etc...) terminate (properly) child process once opencl stuff done. take advantage of fact kernel cleaning resources used defunct process (don't forget wait
... -e.g. using waitpid(2)- avoid having zombie processes). if not familiar that, read advanced linux programming first.
Comments
Post a Comment