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

Popular posts from this blog

powershell Start-Process exit code -1073741502 when used with Credential from a windows service environment -

twig - Using Twigbridge in a Laravel 5.1 Package -

c# - LINQ join Entities from HashSet's, Join vs Dictionary vs HashSet performance -