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