From 961eb25ca3a5f1865be75da53b81bafb32529295 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Thu, 19 Aug 2010 22:40:30 -0300 Subject: [PATCH] Allow mapping shared memory to allocate bitsets 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 | 53 +++++++++++++++++++++++++++++++++++++--------- rt/gc/cdgc/bits.d | 27 ++++++++++++++--------- 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/rt/gc/cdgc/alloc.d b/rt/gc/cdgc/alloc.d index 845fccb..eeeab73 100644 --- a/rt/gc/cdgc/alloc.d +++ b/rt/gc/cdgc/alloc.d @@ -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; } diff --git a/rt/gc/cdgc/bits.d b/rt/gc/cdgc/bits.d index 4d25362..9a8d1b4 100644 --- a/rt/gc/cdgc/bits.d +++ b/rt/gc/cdgc/bits.d @@ -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(); } -- 2.43.0