]> git.llucax.com Git - software/dgc/cdgc.git/commitdiff
Add weak reference support for Tango 0.99.9
authorLeandro Lucarella <llucax@gmail.com>
Sat, 29 May 2010 22:54:04 +0000 (19:54 -0300)
committerLeandro Lucarella <llucax@gmail.com>
Sun, 30 May 2010 01:47:26 +0000 (22:47 -0300)
gc/gc.d
gc/iface.d

diff --git a/gc/gc.d b/gc/gc.d
index 3e22a0ad58dee8de965dc60741d73799fc000b79..ccf347decf59d719ba8d45c0a64589cce3fc9ac1 100644 (file)
--- 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;
+                  });
+            }
+    }
 }
 
 
index 6f95c5d1e091a5c2823b5ddc73ef79f59e7bdc11..260607eee41b6288022e60e6c5812c03728cc75b 100644 (file)
@@ -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);
+}