From: sean Date: Mon, 27 Oct 2008 22:15:16 +0000 (+0000) Subject: First attempt at support for dynamic library loading and unloading. Currently, only... X-Git-Url: https://git.llucax.com/software/druntime.git/commitdiff_plain/bcf5b1203472d877e1f3560ca595cc1341c3783b First attempt at support for dynamic library loading and unloading. Currently, only Windows is supported, and information on static data ranges still needs to be passed to the application GC (see "TODO" in gc/basic and gc/stub). git-svn-id: http://svn.dsource.org/projects/druntime/trunk@38 4a9d5153-6564-4b3f-b5e1-7e8e9dac548f --- diff --git a/src/common/core/runtime.d b/src/common/core/runtime.d index 36607be..3344f23 100644 --- a/src/common/core/runtime.d +++ b/src/common/core/runtime.d @@ -24,7 +24,7 @@ private extern (C) bool rt_term( ExceptionHandler dg = null ); extern (C) void* rt_loadLibrary( in char[] name ); - extern (C) void rt_unloadLibrary( void* ptr ); + extern (C) bool rt_unloadLibrary( void* ptr ); } @@ -116,9 +116,9 @@ struct Runtime * Params: * p = A reference to the library to unload. */ - static void unloadLibrary( void* p ) + static bool unloadLibrary( void* p ) { - rt_unloadLibrary( p ); + return rt_unloadLibrary( p ); } diff --git a/src/compiler/dmd/dmain2.d b/src/compiler/dmd/dmain2.d index 1991bd9..8bccd62 100644 --- a/src/compiler/dmd/dmain2.d +++ b/src/compiler/dmd/dmain2.d @@ -12,6 +12,7 @@ module rt.dmain2; private { + import memory; import util.console; import core.stdc.stddef; import core.stdc.stdlib; @@ -48,15 +49,13 @@ extern (C) void thread_joinAll(); */ extern (C) { - void* gc_getHandle(); - void gc_setHandle(void* p); - void gc_clrHandle(); + void* gc_getProxy(); + void gc_setProxy(void* p); + void gc_clrProxy(); alias void* function() gcGetFn; alias void function(void*) gcSetFn; alias void function() gcClrFn; - alias bool function(ExceptionHandler dg = null) rtInitFn; - alias bool function(ExceptionHandler dg = null) rtTermFn; } extern (C) void* rt_loadLibrary(in char[] name) @@ -69,12 +68,9 @@ extern (C) void* rt_loadLibrary(in char[] name) void* ptr = LoadLibraryA(temp.ptr); if (ptr is null) return ptr; - gcSetFn gcSet = cast(gcSetFn) GetProcAddress(ptr, "_gc_setHandle"); - rtInitFn rtInit = cast(rtInitFn) GetProcAddress(ptr, "_rt_init"); - if (gcSet is null || rtInit is null) - return ptr; - gcSet(gc_getHandle()); - rtInit(); + gcSetFn gcSet = cast(gcSetFn) GetProcAddress(ptr, "gc_setProxy"); + if (gcSet !is null) + gcSet(gc_getProxy()); return ptr; } @@ -84,18 +80,13 @@ extern (C) void* rt_loadLibrary(in char[] name) } } -extern (C) void rt_unloadLibrary(void* ptr) +extern (C) bool rt_unloadLibrary(void* ptr) { version (Windows) { - gcClrFn gcClr = cast(gcClrFn) GetProcAddress(ptr, "_gc_clrHandle"); - rtTermFn rtTerm = cast(rtTermFn) GetProcAddress(ptr, "_rt_term"); - - if (gcClr !is null && rtTerm !is null) - { - rtTerm(); + gcClrFn gcClr = cast(gcClrFn) GetProcAddress(ptr, "gc_clrProxy"); + if (gcClr !is null) gcClr(); - } return FreeLibrary(ptr) != 0; } else version (linux) @@ -178,6 +169,7 @@ extern (C) bool rt_init(ExceptionHandler dg = null) try { gc_init(); + initStaticDataGC(); version (Windows) _minit(); _moduleCtor(); @@ -359,6 +351,7 @@ extern (C) int main(int argc, char **argv) void runAll() { gc_init(); + initStaticDataGC(); version (Windows) _minit(); _moduleCtor(); diff --git a/src/compiler/dmd/memory.d b/src/compiler/dmd/memory.d index 5f09d7e..afd2d90 100644 --- a/src/compiler/dmd/memory.d +++ b/src/compiler/dmd/memory.d @@ -37,6 +37,8 @@ private extern (C) extern void* __libc_stack_end; } } + extern (C) void gc_addRange( void* p, size_t sz ); + extern (C) void gc_removeRange( void *p ); } @@ -130,50 +132,18 @@ private alias __data_start Data_Start; alias _end Data_End; } - - alias void delegate( void*, void* ) scanFn; } -/** - * - */ -extern (C) void rt_scanStaticData( scanFn scan ) -{ - scan(rt_staticDataBottom(), rt_staticDataTop()); -} - -/** - * - */ -extern (C) void* rt_staticDataBottom() -{ - version( Windows ) - { - return &_xi_a; - } - else version( linux ) - { - return &__data_start; - } - else - { - static assert( false, "Operating system not supported." ); - } -} - -/** - * - */ -extern (C) void* rt_staticDataTop() +void initStaticDataGC() { version( Windows ) { - return &_end; + gc_addRange( &_xi_a, &_end - &_xi_a ); } else version( linux ) { - return &_end; + gc_addRange( &__data_start, &_end - &__data_start ); } else { diff --git a/src/gc/basic/gc.d b/src/gc/basic/gc.d index 3f8a642..6b24182 100644 --- a/src/gc/basic/gc.d +++ b/src/gc/basic/gc.d @@ -79,133 +79,241 @@ extern (C) void gc_term() extern (C) void gc_enable() { - _gc.enable(); + if( proxy is null ) + return _gc.enable(); + return proxy.gc_enable(); } extern (C) void gc_disable() { - _gc.disable(); + if( proxy is null ) + return _gc.disable(); + return proxy.gc_disable(); } extern (C) void gc_collect() { - _gc.fullCollect(); + if( proxy is null ) + return _gc.fullCollect(); + return proxy.gc_collect(); } extern (C) void gc_minimize() { - _gc.minimize(); + if( proxy is null ) + return _gc.minimize(); + return proxy.gc_minimize(); } extern (C) uint gc_getAttr( void* p ) { - return _gc.getAttr( p ); + if( proxy is null ) + return _gc.getAttr( p ); + return proxy.gc_getAttr( p ); } extern (C) uint gc_setAttr( void* p, uint a ) { - return _gc.setAttr( p, a ); + if( proxy is null ) + return _gc.setAttr( p, a ); + return proxy.gc_setAttr( p, a ); } extern (C) uint gc_clrAttr( void* p, uint a ) { - return _gc.clrAttr( p, a ); + if( proxy is null ) + return _gc.clrAttr( p, a ); + return proxy.gc_clrAttr( p, a ); } extern (C) void* gc_malloc( size_t sz, uint ba = 0 ) { - return _gc.malloc( sz, ba ); + if( proxy is null ) + return _gc.malloc( sz, ba ); + return proxy.gc_malloc( sz, ba ); } extern (C) void* gc_calloc( size_t sz, uint ba = 0 ) { - return _gc.calloc( sz, ba ); + if( proxy is null ) + return _gc.calloc( sz, ba ); + return proxy.gc_calloc( sz, ba ); } extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 ) { - return _gc.realloc( p, sz, ba ); + if( proxy is null ) + return _gc.realloc( p, sz, ba ); + return proxy.gc_realloc( p, sz, ba ); } extern (C) size_t gc_extend( void* p, size_t mx, size_t sz ) { - return _gc.extend( p, mx, sz ); + if( proxy is null ) + return _gc.extend( p, mx, sz ); + return proxy.gc_extend( p, mx, sz ); } extern (C) size_t gc_reserve( size_t sz ) { - return _gc.reserve( sz ); + if( proxy is null ) + return _gc.reserve( sz ); + return proxy.gc_reserve( sz ); } extern (C) void gc_free( void* p ) { - _gc.free( p ); + if( proxy is null ) + return _gc.free( p ); + return proxy.gc_free( p ); } extern (C) void* gc_addrOf( void* p ) { - return _gc.addrOf( p ); + if( proxy is null ) + return _gc.addrOf( p ); + return proxy.gc_addrOf( p ); } extern (C) size_t gc_sizeOf( void* p ) { - return _gc.sizeOf( p ); + if( proxy is null ) + return _gc.sizeOf( p ); + return proxy.gc_sizeOf( p ); } extern (C) BlkInfo gc_query( void* p ) { - return _gc.query( p ); + if( proxy is null ) + return _gc.query( p ); + return proxy.gc_query( p ); } // NOTE: This routine is experimental. The stats or function name may change // before it is made officially available. extern (C) GCStats gc_stats() { - GCStats stats = void; - _gc.getStats( stats ); - return stats; + if( proxy is null ) + { + GCStats stats = void; + _gc.getStats( stats ); + return stats; + } + // TODO: Add proxy support for this once the layout of GCStats is + // finalized. + //return proxy.gc_stats(); + return GCStats.init; } extern (C) void gc_addRoot( void* p ) { - _gc.addRoot( p ); + if( proxy is null ) + return _gc.addRoot( p ); + return proxy.gc_addRoot( p ); } extern (C) void gc_addRange( void* p, size_t sz ) { - _gc.addRange( p, sz ); + if( proxy is null ) + return _gc.addRange( p, sz ); + return proxy.gc_addRange( p, sz ); } -extern (C) void gc_removeRoot( void *p ) +extern (C) void gc_removeRoot( void* p ) { - _gc.removeRoot( p ); + if( proxy is null ) + return _gc.removeRoot( p ); + return proxy.gc_removeRoot( p ); } -extern (C) void gc_removeRange( void *p ) +extern (C) void gc_removeRange( void* p ) { - _gc.removeRange( p ); + if( proxy is null ) + return _gc.removeRange( p ); + return proxy.gc_removeRange( p ); } -extern (C) void* gc_getHandle() +struct Proxy { - return cast(void*)_gc; + extern (C) void function() gc_enable; + extern (C) void function() gc_disable; + extern (C) void function() gc_collect; + extern (C) void function() gc_minimize; + + extern (C) uint function(void*) gc_getAttr; + extern (C) uint function(void*, uint) gc_setAttr; + extern (C) uint function(void*, uint) gc_clrAttr; + + extern (C) void* function(size_t, uint) gc_malloc; + extern (C) void* function(size_t, uint) gc_calloc; + extern (C) void* function(void*, size_t, uint ba) gc_realloc; + extern (C) size_t function(void*, size_t, size_t) gc_extend; + extern (C) size_t function(size_t) gc_reserve; + extern (C) void function(void*) gc_free; + + extern (C) void* function(void*) gc_addrOf; + extern (C) size_t function(void*) gc_sizeOf; + + extern (C) BlkInfo function(void*) gc_query; + + extern (C) void function(void*) gc_addRoot; + extern (C) void function(void*, size_t) gc_addRange; + + extern (C) void function(void*) gc_removeRoot; + extern (C) void function(void*) gc_removeRange; } -extern (C) void gc_setHandle(void* p) +Proxy pthis; +Proxy* proxy; + +static this() { - void* oldp = gc_getHandle(); - gc_t g = cast(gc_t)p; - if (g.gcversion != gcx.GCVERSION) - throw new Error("incompatible gc versions"); + pthis.gc_enable = &gc_enable; + pthis.gc_disable = &gc_disable; + pthis.gc_collect = &gc_collect; + pthis.gc_minimize = &gc_minimize; + + pthis.gc_getAttr = &gc_getAttr; + pthis.gc_setAttr = &gc_setAttr; + pthis.gc_clrAttr = &gc_clrAttr; + + pthis.gc_malloc = &gc_malloc; + pthis.gc_calloc = &gc_calloc; + pthis.gc_realloc = &gc_realloc; + pthis.gc_extend = &gc_extend; + pthis.gc_reserve = &gc_reserve; + pthis.gc_free = &gc_free; - // Add our static data to the new gc - GC.scanStaticData(g); + pthis.gc_addrOf = &gc_addrOf; + pthis.gc_sizeOf = &gc_sizeOf; - _gc = g; + pthis.gc_query = &gc_query; + + pthis.gc_addRoot = &gc_addRoot; + pthis.gc_addRange = &gc_addRange; + + pthis.gc_removeRoot = &gc_removeRoot; + pthis.gc_removeRange = &gc_removeRange; +} + +extern (C) Proxy* gc_getProxy() +{ + return &pthis; +} + +export extern (C) void gc_setProxy( Proxy* p ) +{ + if( proxy !is null ) + { + // TODO: Decide if this is an error condition. + } + proxy = p; + // TODO: Add known ranges and roots to the proxy. } -extern (C) void gc_endHandle() +export extern (C) void gc_clrProxy() { - GC.unscanStaticData(_gc); + // TODO: Remove known ranges and roots from the proxy. + proxy = null; } diff --git a/src/gc/basic/gcx.d b/src/gc/basic/gcx.d index 0b6d1d0..4c6396e 100644 --- a/src/gc/basic/gcx.d +++ b/src/gc/basic/gcx.d @@ -86,21 +86,16 @@ private extern (C) void* rt_stackBottom(); extern (C) void* rt_stackTop(); - extern (C) void* rt_staticDataBottom(); - extern (C) void* rt_staticDataTop(); extern (C) void rt_finalize( void* p, bool det = true ); - alias void delegate( void*, void* ) scanFn; - - extern (C) void rt_scanStaticData( scanFn scan ); - version (MULTI_THREADED) { extern (C) bool thread_needLock(); extern (C) void thread_suspendAll(); extern (C) void thread_resumeAll(); + alias void delegate( void*, void* ) scanFn; extern (C) void thread_scanAll( scanFn fn, void* curStackTop = null ); } @@ -1126,21 +1121,6 @@ class GC } - static void scanStaticData(gc_t g) - { - //debug(PRINTF) printf("+GC.scanStaticData()\n"); - auto pbot = rt_staticDataBottom(); - auto ptop = rt_staticDataTop(); - g.addRange(pbot, ptop - pbot); - //debug(PRINTF) printf("-GC.scanStaticData()\n"); - } - - static void unscanStaticData(gc_t g) - { - auto pbot = rt_staticDataBottom(); - g.removeRange(pbot); - } - /** * add p to list of roots */ @@ -2262,8 +2242,6 @@ struct Gcx pool.mark.copy(&pool.freebits); } - rt_scanStaticData( &mark ); - version (MULTI_THREADED) { if (!noStack) diff --git a/src/gc/stub/gc.d b/src/gc/stub/gc.d index dd805ef..a5426ff 100644 --- a/src/gc/stub/gc.d +++ b/src/gc/stub/gc.d @@ -57,126 +57,251 @@ extern (C) void gc_term() extern (C) void gc_enable() { - + if( proxy is null ) + return; + return proxy.gc_enable(); } extern (C) void gc_disable() { - + if( proxy is null ) + return; + return proxy.gc_disable(); } extern (C) void gc_collect() { - + if( proxy is null ) + return; + return proxy.gc_collect(); } extern (C) void gc_minimize() { - + if( proxy is null ) + return; + return proxy.gc_minimize(); } extern (C) uint gc_getAttr( void* p ) { - return 0; + if( proxy is null ) + return 0; + return proxy.gc_getAttr( p ); } extern (C) uint gc_setAttr( void* p, uint a ) { - return 0; + if( proxy is null ) + return 0; + return proxy.gc_setAttr( p, a ); } extern (C) uint gc_clrAttr( void* p, uint a ) { - return 0; + if( proxy is null ) + return 0; + return proxy.gc_clrAttr( p, a ); } extern (C) void* gc_malloc( size_t sz, uint ba = 0 ) { - void* p = malloc( sz ); + if( proxy is null ) + { + void* p = malloc( sz ); - if( sz && p is null ) - onOutOfMemoryError(); - return p; + if( sz && p is null ) + onOutOfMemoryError(); + return p; + } + return proxy.gc_malloc( sz, ba ); } extern (C) void* gc_calloc( size_t sz, uint ba = 0 ) { - void* p = calloc( 1, sz ); + if( proxy is null ) + { + void* p = calloc( 1, sz ); - if( sz && p is null ) - onOutOfMemoryError(); - return p; + if( sz && p is null ) + onOutOfMemoryError(); + return p; + } + return proxy.gc_calloc( sz, ba ); } extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 ) { - p = realloc( p, sz ); + if( proxy is null ) + { + p = realloc( p, sz ); - if( sz && p is null ) - onOutOfMemoryError(); - return p; + if( sz && p is null ) + onOutOfMemoryError(); + return p; + } + return proxy.gc_realloc( p, sz, ba ); } extern (C) size_t gc_extend( void* p, size_t mx, size_t sz ) { - return 0; + if( proxy is null ) + return 0; + return proxy.gc_extend( p, mx, sz ); } extern (C) size_t gc_reserve( size_t sz ) { - return 0; + if( proxy is null ) + return 0; + return proxy.gc_reserve( sz ); } extern (C) void gc_free( void* p ) { - free( p ); + if( proxy is null ) + return free( p ); + return proxy.gc_free( p ); } extern (C) void* gc_addrOf( void* p ) { - return null; + if( proxy is null ) + return null; + return proxy.gc_addrOf( p ); } extern (C) size_t gc_sizeOf( void* p ) { - return 0; + if( proxy is null ) + return 0; + return proxy.gc_sizeOf( p ); } extern (C) BlkInfo gc_query( void* p ) { - return BlkInfo.init; + if( proxy is null ) + return BlkInfo.init; + return proxy.gc_query( p ); } +// TODO: Implement range storage. +// TODO: Implement root storage. + extern (C) void gc_addRoot( void* p ) { - + if( proxy is null ) + return; + return proxy.gc_addRoot( p ); } extern (C) void gc_addRange( void* p, size_t sz ) { - + if( proxy is null ) + return; + return proxy.gc_addRange( p, sz ); } extern (C) void gc_removeRoot( void *p ) { - + if( proxy is null ) + return; + return proxy.gc_removeRoot( p ); } extern (C) void gc_removeRange( void *p ) { + if( proxy is null ) + return; + return proxy.gc_removeRange( p ); +} + +struct Proxy +{ + extern (C) void function() gc_enable; + extern (C) void function() gc_disable; + extern (C) void function() gc_collect; + extern (C) void function() gc_minimize; + + extern (C) uint function(void*) gc_getAttr; + extern (C) uint function(void*, uint) gc_setAttr; + extern (C) uint function(void*, uint) gc_clrAttr; + + extern (C) void* function(size_t, uint) gc_malloc; + extern (C) void* function(size_t, uint) gc_calloc; + extern (C) void* function(void*, size_t, uint ba) gc_realloc; + extern (C) size_t function(void*, size_t, size_t) gc_extend; + extern (C) size_t function(size_t) gc_reserve; + extern (C) void function(void*) gc_free; + + extern (C) void* function(void*) gc_addrOf; + extern (C) size_t function(void*) gc_sizeOf; + extern (C) BlkInfo function(void*) gc_query; + + extern (C) void function(void*) gc_addRoot; + extern (C) void function(void*, size_t) gc_addRange; + + extern (C) void function(void*) gc_removeRoot; + extern (C) void function(void*) gc_removeRange; } -extern (C) void* gc_getHandle() +Proxy pthis; +Proxy* proxy; + +static this() { - return null; + pthis.gc_enable = &gc_enable; + pthis.gc_disable = &gc_disable; + pthis.gc_collect = &gc_collect; + pthis.gc_minimize = &gc_minimize; + + pthis.gc_getAttr = &gc_getAttr; + pthis.gc_setAttr = &gc_setAttr; + pthis.gc_clrAttr = &gc_clrAttr; + + pthis.gc_malloc = &gc_malloc; + pthis.gc_calloc = &gc_calloc; + pthis.gc_realloc = &gc_realloc; + pthis.gc_extend = &gc_extend; + pthis.gc_reserve = &gc_reserve; + pthis.gc_free = &gc_free; + + pthis.gc_addrOf = &gc_addrOf; + pthis.gc_sizeOf = &gc_sizeOf; + + pthis.gc_query = &gc_query; + + pthis.gc_addRoot = &gc_addRoot; + pthis.gc_addRange = &gc_addRange; + + pthis.gc_removeRoot = &gc_removeRoot; + pthis.gc_removeRange = &gc_removeRange; } -extern (C) void gc_setHandle(void* p) +extern (C) Proxy* gc_getProxy() { + return &pthis; } -extern (C) void gc_endHandle() +export extern (C) void gc_setProxy( Proxy* p ) { + if( proxy !is null ) + { + // error? + } + proxy = p; + ///foreach range + //proxy.addRange(); + //foreach root + //proxy.addRoot() } +export extern (C) void gc_clrProxy() +{ + // foreach root + // proxy.removeRoot(); + // foreach range + // proxy.removeReange(); + proxy = null; +} \ No newline at end of file