1 import core.runtime;
2 import core.stdc.stdio;
3 import core.stdc.string;
4 import core.thread;
5 import core.sys.posix.dlfcn;
6
7 version (DragonFlyBSD) import core.sys.dragonflybsd.dlfcn : RTLD_NOLOAD;
8 version (FreeBSD) import core.sys.freebsd.dlfcn : RTLD_NOLOAD;
9 version (linux) import core.sys.linux.dlfcn : RTLD_NOLOAD;
10 version (NetBSD) import core.sys.netbsd.dlfcn : RTLD_NOLOAD;
11 version (OSX) import core.sys.darwin.dlfcn : RTLD_NOLOAD;
12 version (Solaris) import core.sys.solaris.dlfcn : RTLD_NOLOAD;
13
14 static assert(__traits(compiles, RTLD_NOLOAD), "unimplemented");
15
loadSym(T)16 void loadSym(T)(void* handle, ref T val, const char* mangle)
17 {
18 val = cast(T).dlsym(handle, mangle);
19 }
20
openLib(string s)21 void* openLib(string s)
22 {
23 auto h = Runtime.loadLibrary(s);
24 assert(h !is null);
25
26 loadSym(h, libThrowException, "_D3lib14throwExceptionFZv");
27 loadSym(h, libCollectException, "_D3lib16collectExceptionFDFZvZC9Exception");
28
29 loadSym(h, libAlloc, "_D3lib5allocFZv");
30 loadSym(h, libTlsAlloc, "_D3lib9tls_allocFZv");
31 loadSym(h, libAccess, "_D3lib6accessFZv");
32 loadSym(h, libTlsAccess, "_D3lib10tls_accessFZv");
33 loadSym(h, libFree, "_D3lib4freeFZv");
34 loadSym(h, libTlsFree, "_D3lib8tls_freeFZv");
35
36 loadSym(h, libSharedStaticCtor, "_D3lib18shared_static_ctorOk");
37 loadSym(h, libSharedStaticDtor, "_D3lib18shared_static_dtorOk");
38 loadSym(h, libStaticCtor, "_D3lib11static_ctorOk");
39 loadSym(h, libStaticDtor, "_D3lib11static_dtorOk");
40
41 return h;
42 }
43
closeLib(void * h)44 void closeLib(void* h)
45 {
46 Runtime.unloadLibrary(h);
47 }
48
49 __gshared
50 {
51 void function() libThrowException;
52 Exception function(void delegate()) libCollectException;
53
54 void function() libAlloc;
55 void function() libTlsAlloc;
56 void function() libAccess;
57 void function() libTlsAccess;
58 void function() libFree;
59 void function() libTlsFree;
60
61 shared uint* libSharedStaticCtor;
62 shared uint* libSharedStaticDtor;
63 shared uint* libStaticCtor;
64 shared uint* libStaticDtor;
65 }
66
testEH()67 void testEH()
68 {
69 bool passed;
70 try
71 libThrowException();
72 catch (Exception e)
73 passed = true;
74 assert(passed); passed = false;
75
76 assert(libCollectException({throw new Exception(null);}) !is null);
77 assert(libCollectException({libThrowException();}) !is null);
78 }
79
testGC()80 void testGC()
81 {
82 import core.memory;
83 libAlloc();
84 libTlsAlloc();
85 libAccess();
86 libTlsAccess();
87 GC.collect();
88 libTlsAccess();
89 libAccess();
90 libTlsFree();
91 libFree();
92 }
93
testInit()94 void testInit()
95 {
96
97 assert(*libStaticCtor == 1);
98 assert(*libStaticDtor == 0);
99 static void run()
100 {
101 assert(*libSharedStaticCtor == 1);
102 assert(*libSharedStaticDtor == 0);
103 assert(*libStaticCtor == 2);
104 assert(*libStaticDtor == 0);
105 }
106 auto thr = new Thread(&run);
107 thr.start();
108 thr.join();
109 assert(*libSharedStaticCtor == 1);
110 assert(*libSharedStaticDtor == 0);
111 assert(*libStaticCtor == 2);
112 assert(*libStaticDtor == 1);
113 }
114
findModuleInfo(string name)115 const(ModuleInfo)* findModuleInfo(string name)
116 {
117 foreach (m; ModuleInfo)
118 if (m.name == name) return m;
119 return null;
120 }
121
runTests(string libName)122 void runTests(string libName)
123 {
124 assert(findModuleInfo("lib") is null);
125 auto handle = openLib(libName);
126 assert(findModuleInfo("lib") !is null);
127
128 testEH();
129 testGC();
130 testInit();
131
132 closeLib(handle);
133 assert(findModuleInfo("lib") is null);
134 }
135
main(string[]args)136 void main(string[] args)
137 {
138 auto name = args[0] ~ '\0';
139 const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
140 name = name[0 .. pathlen] ~ "lib.so";
141
142 runTests(name);
143
144 // lib is no longer resident
145 name ~= '\0';
146 assert(.dlopen(name.ptr, RTLD_LAZY | RTLD_NOLOAD) is null);
147 name = name[0 .. $-1];
148
149 auto thr = new Thread({runTests(name);});
150 thr.start();
151 thr.join();
152 }
153