// 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().
* 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
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);
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;
}
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();
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;
}
}
}
}
- 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();
}