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();
}