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 16 void loadSym(T)(void* handle, ref T val, const char* mangle) 17 { 18 val = cast(T).dlsym(handle, mangle); 19 } 20 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 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 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 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 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 115 const(ModuleInfo)* findModuleInfo(string name) 116 { 117 foreach (m; ModuleInfo) 118 if (m.name == name) return m; 119 return null; 120 } 121 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 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