]> git.llucax.com Git - software/dgc/cdgc.git/commitdiff
Allow mapping shared memory to allocate bitsets
authorLeandro Lucarella <llucax@gmail.com>
Fri, 20 Aug 2010 01:40:30 +0000 (22:40 -0300)
committerLeandro Lucarella <llucax@gmail.com>
Fri, 20 Aug 2010 01:40:30 +0000 (22:40 -0300)
The concurrent GC will fork() to run the collection, so it need to share
the mark bits to let the original process know the results of the mark
phase.

rt/gc/cdgc/alloc.d
rt/gc/cdgc/bits.d

index 845fccbc1530c157a22acfea12a7ed7a6a57eed7..eeeab73528428a37d6cab5b61a36737165fd8dc2 100644 (file)
@@ -36,12 +36,29 @@ else
 
 // Public interface/Documentation
 
+/**
+ * Visibility of the mapped memory.
+ */
+enum Vis
+{
+    PRIV, /// Private to this process
+    SHARED, /// Shared across fork()ed processes (only when HAVE_SHARED)
+}
+
 version (D_Ddoc) {
 
+/**
+ * Indicates if an implementation support mapping shared memory.
+ *
+ * The value shown here is just demostrative, the real value is defined based
+ * on the OS it's being compiled in.
+ */
+const HAVE_SHARED = false;
+
 /**
  * Map memory.
  */
-void* os_mem_map(size_t nbytes);
+void* os_mem_map(size_t nbytes, Vis vis = Vis.PRIV);
 
 /**
  * Unmap memory allocated with os_mem_map().
@@ -49,39 +66,53 @@ void* os_mem_map(size_t nbytes);
  *      true  success
  *      false failure
  */
-bool os_mem_unmap(void* base, size_t nbytes);
+bool os_mem_unmap(void* base, size_t nbytes, Vis vis = Vis.PRIV);
 
 }
 
 // Implementations
 else static if (is(typeof(VirtualAlloc))) {
-    void* os_mem_map(size_t nbytes)
+    enum { HAVE_SHARED = false }
+
+    void* os_mem_map(size_t nbytes, Vis vis = Vis.PRIV)
     {
+        assert (vis == Vis.PRIV);
         return VirtualAlloc(null, nbytes, MEM_RESERVE | MEM_COMMIT,
                 PAGE_READWRITE);
     }
 
-    bool os_mem_unmap(void* base, size_t nbytes)
+    bool os_mem_unmap(void* base, size_t nbytes, Vis vis = Vis.PRIV)
     {
+        assert (vis == Vis.PRIV);
         return VirtualFree(base, 0, MEM_RELEASE) != 0;
     }
+
 }
 
 else static if (is(typeof(mmap)) && is(typeof(MAP_ANON))) {
-    void* os_mem_map(size_t nbytes)
+    enum { HAVE_SHARED = true }
+
+    void* os_mem_map(size_t nbytes, Vis vis = Vis.PRIV)
     {
-        void* p = mmap(null, nbytes,
-                PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+        auto flags = MAP_ANON;
+        if (vis == Vis.SHARED)
+            flags |= MAP_SHARED;
+        else // PRIV
+            flags |= MAP_PRIVATE;
+        void* p = mmap(null, nbytes, PROT_READ | PROT_WRITE, flags, -1, 0);
         return (p == MAP_FAILED) ? null : p;
     }
 
-    bool os_mem_unmap(void* base, size_t nbytes)
+    bool os_mem_unmap(void* base, size_t nbytes, Vis vis = Vis.PRIV)
     {
+        // vis is not necessary to unmap
         return munmap(base, nbytes) == 0;
     }
 }
 
 else static if (is(typeof(malloc))) {
+    enum { HAVE_SHARED = false }
+
     // NOTE: This assumes malloc granularity is at least (void*).sizeof.  If
     //       (req_size + PAGESIZE) is allocated, and the pointer is rounded up
     //       to PAGESIZE alignment, there will be space for a void* at the end
@@ -91,8 +122,9 @@ else static if (is(typeof(malloc))) {
 
     const size_t PAGE_MASK = PAGESIZE - 1;
 
-    void* os_mem_map(size_t nbytes)
+    void* os_mem_map(size_t nbytes, Vis vis = Vis.PRIV)
     {
+        assert (vis == Vis.PRIV);
         byte* p, q;
         p = cast(byte* ) malloc(nbytes + PAGESIZE);
         q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK);
@@ -100,8 +132,9 @@ else static if (is(typeof(malloc))) {
         return q;
     }
 
-    bool os_mem_unmap(void* base, size_t nbytes)
+    bool os_mem_unmap(void* base, size_t nbytes, Vis vis = Vis.PRIV)
     {
+        assert (vis == Vis.PRIV);
         free(*cast(void**)(cast(byte*) base + nbytes));
         return true;
     }
index 4d2536275f2bd133217d5a639ca6ced3b1ba7971..9a8d1b48a7bdec9ad7fe50ee525defec2090bf2f 100644 (file)
@@ -26,7 +26,8 @@
 
 module rt.gc.cdgc.bits;
 
-import cstdlib = tango.stdc.stdlib;
+import rt.gc.cdgc.alloc: os_mem_map, os_mem_unmap, Vis;
+
 import cstring = tango.stdc.string;
 
 private extern (C) void onOutOfMemoryError();
@@ -60,15 +61,21 @@ struct GCBits
     size_t nwords = 0;    // allocated words in data[] excluding sentinals
     size_t nbits = 0;     // number of bits in data[] excluding sentinals
 
-    void Dtor()
+    /// Get the number of bytes needed to store nbits bits
+    size_t data_size()
+    {
+        return (nwords + 2) * uint.sizeof; // +2 for sentinels
+    }
+
+    void Dtor(Vis vis = Vis.PRIV)
     {
-        // Even when free() can be called with a null pointer, the extra call
-        // might be significant. On hard GC benchmarks making the test for null
-        // here (i.e. not making the call) can reduce the GC time by almost
-        // ~5%.
+        // Even when os_mem_unmap() can be called with a null pointer, the
+        // extra call might be significant. On hard GC benchmarks making the
+        // test for null here (i.e. not making the call) can reduce the GC time
+        // by almost ~5%.
         if (data)
         {
-            cstdlib.free(data);
+            os_mem_unmap(data, data_size, vis);
             data = null;
         }
     }
@@ -81,11 +88,11 @@ struct GCBits
         }
     }
 
-    void alloc(size_t nbits)
+    void alloc(size_t nbits, Vis vis = Vis.PRIV)
     {
         this.nbits = nbits;
-        nwords = (nbits + (BITS_PER_WORD - 1)) >> BITS_SHIFT;
-        data = cast(uint*)cstdlib.calloc(nwords + 2, uint.sizeof);
+        this.nwords = (nbits + (BITS_PER_WORD - 1)) >> BITS_SHIFT;
+        this.data = cast(uint*) os_mem_map(data_size, vis);
         if (!data)
             onOutOfMemoryError();
     }