From 619a72ba893b8262f8d0946183aaa90964f893d5 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Sat, 29 May 2010 19:54:04 -0300 Subject: [PATCH] Add weak reference support for Tango 0.99.9 --- gc/gc.d | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ gc/iface.d | 15 +++++++++ 2 files changed, 105 insertions(+) diff --git a/gc/gc.d b/gc/gc.d index 3e22a0a..ccf347d 100644 --- a/gc/gc.d +++ b/gc/gc.d @@ -84,6 +84,11 @@ private extern (C) void rt_finalize( void* p, bool det = true ); + alias void delegate(Object) DEvent; + extern (C) void rt_attachDisposeEvent(Object h, DEvent e); + extern (C) bool rt_detachDisposeEvent(Object h, DEvent e); + + alias void delegate( void*, void* ) scanFn; extern (C) void rt_scanStaticData( scanFn scan ); @@ -1301,6 +1306,91 @@ class GC stats.usedsize = bsize - flsize; stats.freelistsize = flsize; } + + /******************* weak-reference support *********************/ + + // call locked if necessary + private T locked(T)(in T delegate() code) + { + if (thread_needLock) + synchronized(gcLock) return code(); + else + return code(); + } + + private struct WeakPointer + { + Object reference; + + void ondestroy(Object r) + { + assert(r is reference); + // lock for memory consistency (parallel readers) + // also ensures that weakpointerDestroy can be called while another + // thread is freeing the reference with "delete" + locked!(void)({ reference = null; }); + } + } + + /** + * Create a weak pointer to the given object. + * Returns a pointer to an opaque struct allocated in C memory. + */ + void* weakpointerCreate( Object r ) + { + if (r) + { + // must be allocated in C memory + // 1. to hide the reference from the GC + // 2. the GC doesn't scan delegates added by rt_attachDisposeEvent + // for references + auto wp = cast(WeakPointer*)(libc.malloc(WeakPointer.sizeof)); + if (!wp) + onOutOfMemoryError(); + wp.reference = r; + rt_attachDisposeEvent(r, &wp.ondestroy); + return wp; + } + return null; + } + + /** + * Destroy a weak pointer returned by weakpointerCreate(). + * If null is passed, nothing happens. + */ + void weakpointerDestroy( void* p ) + { + if (p) + { + auto wp = cast(WeakPointer*)p; + // must be extra careful about the GC or parallel threads + // finalizing the reference at the same time + locked!(void)({ + if (wp.reference) + rt_detachDisposeEvent(wp.reference, &wp.ondestroy); + }); + .free(wp); + } + } + + /** + * Query a weak pointer and return either the object passed to + * weakpointerCreate, or null if it was free'd in the meantime. + * If null is passed, null is returned. + */ + Object weakpointerGet( void* p ) + { + if (p) + { + // NOTE: could avoid the lock by using Fawzi style GC counters but + // that'd require core.sync.Atomic and lots of care about memory + // consistency it's an optional optimization see + // http://dsource.org/projects/tango/browser/trunk/user/tango/core/Lifetime.d?rev=5100#L158 + return locked!(Object)({ + return (cast(WeakPointer*)p).reference; + }); + } + } } diff --git a/gc/iface.d b/gc/iface.d index 6f95c5d..260607e 100644 --- a/gc/iface.d +++ b/gc/iface.d @@ -218,3 +218,18 @@ extern (C) void gc_removeRange( void *p ) { _gc.removeRange( p ); } + +extern (C) void* gc_weakpointerCreate( Object r ) +{ + return _gc.weakpointerCreate(r); +} + +extern (C) void gc_weakpointerDestroy( void* wp ) +{ + _gc.weakpointerDestroy(wp); +} + +extern (C) Object gc_weakpointerGet( void* wp ) +{ + return _gc.weakpointerGet(wp); +} -- 2.43.0