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