| import core.runtime; |
| import core.stdc.stdio; |
| import core.stdc.string; |
| import core.thread; |
| |
| import core.sys.posix.dlfcn; |
| |
| version (DragonFlyBSD) import core.sys.dragonflybsd.dlfcn : RTLD_NOLOAD; |
| version (FreeBSD) import core.sys.freebsd.dlfcn : RTLD_NOLOAD; |
| version (linux) import core.sys.linux.dlfcn : RTLD_NOLOAD; |
| version (NetBSD) import core.sys.netbsd.dlfcn : RTLD_NOLOAD; |
| version (OSX) import core.sys.darwin.dlfcn : RTLD_NOLOAD; |
| version (Solaris) import core.sys.solaris.dlfcn : RTLD_NOLOAD; |
| |
| static assert(__traits(compiles, RTLD_NOLOAD), "unimplemented"); |
| |
| void loadSym(T)(void* handle, ref T val, const char* mangle) |
| { |
| val = cast(T).dlsym(handle, mangle); |
| } |
| |
| void* openLib(string s) |
| { |
| auto h = Runtime.loadLibrary(s); |
| assert(h !is null); |
| |
| loadSym(h, libThrowException, "_D3lib14throwExceptionFZv"); |
| loadSym(h, libCollectException, "_D3lib16collectExceptionFDFZvZC9Exception"); |
| |
| loadSym(h, libAlloc, "_D3lib5allocFZv"); |
| loadSym(h, libTlsAlloc, "_D3lib9tls_allocFZv"); |
| loadSym(h, libAccess, "_D3lib6accessFZv"); |
| loadSym(h, libTlsAccess, "_D3lib10tls_accessFZv"); |
| loadSym(h, libFree, "_D3lib4freeFZv"); |
| loadSym(h, libTlsFree, "_D3lib8tls_freeFZv"); |
| |
| loadSym(h, libSharedStaticCtor, "_D3lib18shared_static_ctorOk"); |
| loadSym(h, libSharedStaticDtor, "_D3lib18shared_static_dtorOk"); |
| loadSym(h, libStaticCtor, "_D3lib11static_ctorOk"); |
| loadSym(h, libStaticDtor, "_D3lib11static_dtorOk"); |
| |
| return h; |
| } |
| |
| void closeLib(void* h) |
| { |
| Runtime.unloadLibrary(h); |
| } |
| |
| __gshared |
| { |
| void function() libThrowException; |
| Exception function(void delegate()) libCollectException; |
| |
| void function() libAlloc; |
| void function() libTlsAlloc; |
| void function() libAccess; |
| void function() libTlsAccess; |
| void function() libFree; |
| void function() libTlsFree; |
| |
| shared uint* libSharedStaticCtor; |
| shared uint* libSharedStaticDtor; |
| shared uint* libStaticCtor; |
| shared uint* libStaticDtor; |
| } |
| |
| void testEH() |
| { |
| bool passed; |
| try |
| libThrowException(); |
| catch (Exception e) |
| passed = true; |
| assert(passed); passed = false; |
| |
| assert(libCollectException({throw new Exception(null);}) !is null); |
| assert(libCollectException({libThrowException();}) !is null); |
| } |
| |
| void testGC() |
| { |
| import core.memory; |
| libAlloc(); |
| libTlsAlloc(); |
| libAccess(); |
| libTlsAccess(); |
| GC.collect(); |
| libTlsAccess(); |
| libAccess(); |
| libTlsFree(); |
| libFree(); |
| } |
| |
| void testInit() |
| { |
| |
| assert(*libStaticCtor == 1); |
| assert(*libStaticDtor == 0); |
| static void run() |
| { |
| assert(*libSharedStaticCtor == 1); |
| assert(*libSharedStaticDtor == 0); |
| assert(*libStaticCtor == 2); |
| assert(*libStaticDtor == 0); |
| } |
| auto thr = new Thread(&run); |
| thr.start(); |
| thr.join(); |
| assert(*libSharedStaticCtor == 1); |
| assert(*libSharedStaticDtor == 0); |
| assert(*libStaticCtor == 2); |
| assert(*libStaticDtor == 1); |
| } |
| |
| const(ModuleInfo)* findModuleInfo(string name) |
| { |
| foreach (m; ModuleInfo) |
| if (m.name == name) return m; |
| return null; |
| } |
| |
| void runTests(string libName) |
| { |
| assert(findModuleInfo("lib") is null); |
| auto handle = openLib(libName); |
| assert(findModuleInfo("lib") !is null); |
| |
| testEH(); |
| testGC(); |
| testInit(); |
| |
| closeLib(handle); |
| assert(findModuleInfo("lib") is null); |
| } |
| |
| void main(string[] args) |
| { |
| auto name = args[0] ~ '\0'; |
| const pathlen = strrchr(name.ptr, '/') - name.ptr + 1; |
| name = name[0 .. pathlen] ~ "lib.so"; |
| |
| runTests(name); |
| |
| // lib is no longer resident |
| name ~= '\0'; |
| assert(.dlopen(name.ptr, RTLD_LAZY | RTLD_NOLOAD) is null); |
| name = name[0 .. $-1]; |
| |
| auto thr = new Thread({runTests(name);}); |
| thr.start(); |
| thr.join(); |
| } |