如何知道过程是否真的完成了一个dlclose()库?

我在Linux上(Ubuntu 12.04,gcc 4.6.3),尝试弯曲dlopen / close以实现我的意愿,以便制作一个基于插件的应用程序,可以在必要时重新加载插件(例如,如果它们被重新编译) 。

基本理论很简单:插件插件; 使用它,跟踪所有正在使用的符号。 当重新加载的时候,清理所有的符号,并closures插件。

我扔了一个简单的演示程序“test.cpp”:

#include <dlfcn.h> #include <iostream> using namespace std; int main(int argc, char** argv) { if (argc > 1) { void* h = dlopen(argv[1], RTLD_NOW|RTLD_LOCAL); if (!h) { cerr << "ERROR: " << dlerror() << endl; return 1; } cin.get(); if (dlclose(h)) { cerr << "ERROR: " << dlerror() << endl; return 2; } cin.get(); } return 0; } 

编译:

 g++ test.cpp -o test -ldl 

要创build一个可以作为parameter passing给上述代码的简单的库,使用:

 touch libtest.cpp && g++ -rdynamic -shared libtest.cpp -o libtest.so 

然后运行:

 ./test ./libtest.so 

这是问题所在。 如果在按[Enter]一次后(即加载并假定卸载库之后),则运行“pmap”以检查在“test”中加载了哪些库,它会告诉您libtest.so仍然存在! 现在这是尽pipe从dlclose()有效的返回,并没有合理的方式,引用计数可以在此之前边缘1以上(这可以通过尝试第二个dlclose()validation – 它会给出一个错误返回说它已经closures)。

因此,Linux 不会卸载dlopen()ed库(与文档相矛盾),或者'pmap'是错误的。 如果是后者,是否有更可靠的方法来确定一个库是否仍然被加载?

下面的程序我没有观察到

 // file soq.c #include <dlfcn.h> #include <iostream> #include <cstdio> #include <stdlib.h> #include <string.h> #include <unistd.h> using namespace std; int main(int argc, char** argv) { char cmd[60]; snprintf(cmd, sizeof(cmd), "pmap %d", getpid()); if (argc > 1) { void* h = dlopen(argv[1], RTLD_NOW|RTLD_LOCAL); if (!h) { cerr << "ERROR: " << dlerror() << endl; return 1; } cerr << "after dlopen " << argv[1] << endl; system(cmd); cin.get(); if (dlclose(h)) { cerr << "ERROR: " << dlerror() << endl; return 2; } cin.get(); cerr << "after close " << argv[1] << endl; system(cmd); } return 0; } 

正如我所料:

 % ./soq ./libempty.so ./soq ./libempty.so after dlopen ./libempty.so 5276: ./soq ./libempty.so 0000000000400000 8K rx-- /home/basile/tmp/soq 0000000000601000 4K rw--- /home/basile/tmp/soq 0000000001b4d000 132K rw--- [ anon ] 00007f1dbfd01000 4K rx-- /home/basile/tmp/libempty.so 00007f1dbfd02000 2044K ----- /home/basile/tmp/libempty.so 00007f1dbff01000 4K rw--- /home/basile/tmp/libempty.so 00007f1dbff02000 1524K rx-- /lib/x86_64-linux-gnu/libc-2.13.so 00007f1dc007f000 2048K ----- /lib/x86_64-linux-gnu/libc-2.13.so 00007f1dc027f000 16K r---- /lib/x86_64-linux-gnu/libc-2.13.so 00007f1dc0283000 4K rw--- /lib/x86_64-linux-gnu/libc-2.13.so 00007f1dc0284000 20K rw--- [ anon ] 00007f1dc0289000 84K rx-- /lib/x86_64-linux-gnu/libgcc_s.so.1 00007f1dc029e000 2048K ----- /lib/x86_64-linux-gnu/libgcc_s.so.1 00007f1dc049e000 4K rw--- /lib/x86_64-linux-gnu/libgcc_s.so.1 00007f1dc049f000 516K rx-- /lib/x86_64-linux-gnu/libm-2.13.so 00007f1dc0520000 2044K ----- /lib/x86_64-linux-gnu/libm-2.13.so 00007f1dc071f000 4K r---- /lib/x86_64-linux-gnu/libm-2.13.so 00007f1dc0720000 4K rw--- /lib/x86_64-linux-gnu/libm-2.13.so 00007f1dc0721000 928K rx-- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 00007f1dc0809000 2048K ----- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 00007f1dc0a09000 32K r---- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 00007f1dc0a11000 8K rw--- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 00007f1dc0a13000 84K rw--- [ anon ] 00007f1dc0a28000 8K rx-- /lib/x86_64-linux-gnu/libdl-2.13.so 00007f1dc0a2a000 2048K ----- /lib/x86_64-linux-gnu/libdl-2.13.so 00007f1dc0c2a000 4K r---- /lib/x86_64-linux-gnu/libdl-2.13.so 00007f1dc0c2b000 4K rw--- /lib/x86_64-linux-gnu/libdl-2.13.so 00007f1dc0c2c000 128K rx-- /lib/x86_64-linux-gnu/ld-2.13.so 00007f1dc0e1c000 20K rw--- [ anon ] 00007f1dc0e49000 8K rw--- [ anon ] 00007f1dc0e4b000 4K r---- /lib/x86_64-linux-gnu/ld-2.13.so 00007f1dc0e4c000 4K rw--- /lib/x86_64-linux-gnu/ld-2.13.so 00007f1dc0e4d000 4K rw--- [ anon ] 00007fff076c3000 132K rw--- [ stack ] 00007fff077b4000 4K rx-- [ anon ] ffffffffff600000 4K rx-- [ anon ] total 15984K after close ./libempty.so 5276: ./soq ./libempty.so 0000000000400000 8K rx-- /home/basile/tmp/soq 0000000000601000 4K rw--- /home/basile/tmp/soq 0000000001b4d000 132K rw--- [ anon ] 00007f1dbff02000 1524K rx-- /lib/x86_64-linux-gnu/libc-2.13.so 00007f1dc007f000 2048K ----- /lib/x86_64-linux-gnu/libc-2.13.so 00007f1dc027f000 16K r---- /lib/x86_64-linux-gnu/libc-2.13.so 00007f1dc0283000 4K rw--- /lib/x86_64-linux-gnu/libc-2.13.so 00007f1dc0284000 20K rw--- [ anon ] 00007f1dc0289000 84K rx-- /lib/x86_64-linux-gnu/libgcc_s.so.1 00007f1dc029e000 2048K ----- /lib/x86_64-linux-gnu/libgcc_s.so.1 00007f1dc049e000 4K rw--- /lib/x86_64-linux-gnu/libgcc_s.so.1 00007f1dc049f000 516K rx-- /lib/x86_64-linux-gnu/libm-2.13.so 00007f1dc0520000 2044K ----- /lib/x86_64-linux-gnu/libm-2.13.so 00007f1dc071f000 4K r---- /lib/x86_64-linux-gnu/libm-2.13.so 00007f1dc0720000 4K rw--- /lib/x86_64-linux-gnu/libm-2.13.so 00007f1dc0721000 928K rx-- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 00007f1dc0809000 2048K ----- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 00007f1dc0a09000 32K r---- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 00007f1dc0a11000 8K rw--- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 00007f1dc0a13000 84K rw--- [ anon ] 00007f1dc0a28000 8K rx-- /lib/x86_64-linux-gnu/libdl-2.13.so 00007f1dc0a2a000 2048K ----- /lib/x86_64-linux-gnu/libdl-2.13.so 00007f1dc0c2a000 4K r---- /lib/x86_64-linux-gnu/libdl-2.13.so 00007f1dc0c2b000 4K rw--- /lib/x86_64-linux-gnu/libdl-2.13.so 00007f1dc0c2c000 128K rx-- /lib/x86_64-linux-gnu/ld-2.13.so 00007f1dc0e1c000 20K rw--- [ anon ] 00007f1dc0e48000 12K rw--- [ anon ] 00007f1dc0e4b000 4K r---- /lib/x86_64-linux-gnu/ld-2.13.so 00007f1dc0e4c000 4K rw--- /lib/x86_64-linux-gnu/ld-2.13.so 00007f1dc0e4d000 4K rw--- [ anon ] 00007fff076c3000 132K rw--- [ stack ] 00007fff077b4000 4K rx-- [ anon ] ffffffffff600000 4K rx-- [ anon ] total 13936K 

所以你错误地运行你的pmap

顺便说一句,你可以在实践中避免任何错误,正如我的manydl.c示例所示。 在实践中,不打扰dlclose意味着只有一个小的地址空间泄漏,在实践中不是一个大问题。 (你可以减少近百万个不同的共享对象,而不会受到太多的伤害)。

要知道共享对象何时被卸载,请使用dlclose -d插件的“析构函数”(例如C ++中静态数据的析构函数或C代码中的attribute((析构函数) ),因为它们是从内部调用的卸载dlclose