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).

This commit is contained in:
Sean Kelly 2008-10-27 22:15:16 +00:00
parent db1536183f
commit 30c428a710
6 changed files with 324 additions and 150 deletions

View file

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

View file

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

View file

@ -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()
void initStaticDataGC()
{
version( Windows )
{
return &_xi_a;
gc_addRange( &_xi_a, &_end - &_xi_a );
}
else version( linux )
{
return &__data_start;
}
else
{
static assert( false, "Operating system not supported." );
}
}
/**
*
*/
extern (C) void* rt_staticDataTop()
{
version( Windows )
{
return &_end;
}
else version( linux )
{
return &_end;
gc_addRange( &__data_start, &_end - &__data_start );
}
else
{

View file

@ -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;
// Add our static data to the new gc
GC.scanStaticData(g);
pthis.gc_getAttr = &gc_getAttr;
pthis.gc_setAttr = &gc_setAttr;
pthis.gc_clrAttr = &gc_clrAttr;
_gc = g;
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_endHandle()
extern (C) Proxy* gc_getProxy()
{
GC.unscanStaticData(_gc);
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.
}
export extern (C) void gc_clrProxy()
{
// TODO: Remove known ranges and roots from the proxy.
proxy = null;
}

View file

@ -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)

View file

@ -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 );
}
extern (C) void* gc_getHandle()
struct Proxy
{
return null;
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()
{
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_endHandle()
extern (C) Proxy* gc_getProxy()
{
return &pthis;
}
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;
}