| import core.thread, core.memory, core.atomic; |
| |
| // test init |
| shared uint gctor, gdtor, tctor, tdtor; |
| shared static this() { if (atomicOp!"+="(gctor, 1) != 1) assert(0); } |
| shared static ~this() { if (atomicOp!"+="(gdtor, 1) != 1) assert(0); } |
| static this() { atomicOp!"+="(tctor, 1); } |
| static ~this() { atomicOp!"+="(tdtor, 1); } |
| |
| // test GC |
| __gshared Object root; |
| void alloc() { root = new Object(); } |
| void access() { assert(root.toString() !is null); } // vtbl call will fail if finalized |
| void free() { root = null; } |
| |
| Object tls_root; |
| void tls_alloc() { tls_root = new Object(); } |
| void tls_access() { assert(tls_root.toString() !is null); } // vtbl call will fail if finalized |
| void tls_free() { tls_root = null; } |
| |
| void stack(alias func)() |
| { |
| // allocate some extra stack space to not keep references to GC memory on the scanned stack |
| ubyte[1024] buf = void; |
| func(); |
| } |
| |
| void testGC() |
| { |
| import core.memory; |
| |
| stack!alloc(); |
| stack!tls_alloc(); |
| stack!access(); |
| stack!tls_access(); |
| GC.collect(); |
| stack!tls_access(); |
| stack!access(); |
| stack!tls_free(); |
| stack!free(); |
| } |
| |
| extern(C) int runTests() |
| { |
| try |
| { |
| assert(atomicLoad!(MemoryOrder.acq)(gctor) == 1); |
| assert(atomicLoad!(MemoryOrder.acq)(gdtor) == 0); |
| assert(atomicLoad!(MemoryOrder.acq)(tctor) >= 1); |
| assert(atomicLoad!(MemoryOrder.acq)(tdtor) >= 0); |
| // test some runtime functionality |
| testGC(); |
| new Thread(&testGC).start.join; |
| } |
| catch (Throwable) |
| { |
| return false; |
| } |
| return true; |
| } |
| |
| // Provide a way to initialize D from C programs that are D agnostic. |
| import core.runtime : rt_init, rt_term; |
| |
| extern(C) int plugin_init() |
| { |
| return rt_init(); |
| } |
| |
| extern(C) int plugin_term() |
| { |
| return rt_term(); |
| } |