module gc.cell;
import cstdlib = tango.stdc.stdlib;
+import mman = tango.stdc.posix.sys.mman;
package:
*/
static Cell* alloc(size_t size, uint attr = 0)
{
- auto cell = cast(Cell*) cstdlib.malloc(size + Cell.sizeof);
- if (cell is null)
+ // The capacity is increased to the number of bytes used by the minimun
+ // number of pages needed to allocate the requested size.
+ size_t capacity = size + 4096 - size % 4096;
+ // Allocate one page for the cell header and as many pages as necessary
+ // for the cell data using mmap(2). Page size is assumed to be 4096.
+ auto ptr = mman.mmap(null, 4096 + capacity,
+ mman.PROT_READ | mman.PROT_WRITE,
+ mman.MAP_PRIVATE | mman.MAP_ANON, -1, 0);
+ if (ptr == mman.MAP_FAILED)
return null;
- cell.capacity = size;
+ auto cell = cast(Cell*) ptr;
+ cell.capacity = capacity;
cell.size = size;
cell.attr = cast(BlkAttr) attr;
cell.marked = true;
/// Free a cell allocated by Cell.alloc().
static void free(Cell* cell)
{
- cstdlib.free(cell);
+ // Unmap the mmap(2)ed memory. The extra page (4096) is the cell header.
+ int r = mman.munmap(cell, 4096 + cell.capacity);
+ assert (r != -1);
}
/**
{
if (ptr is null)
return null;
- return cast(Cell*) (cast(byte*) ptr - Cell.sizeof);
+ // Subtract one page to the pointer to get the start of the cell header.
+ return cast(Cell*) (cast(byte*) ptr - 4096);
}
/// Get the base address of the object stored in the cell.
void* ptr()
{
- return cast(void*) (cast(byte*) this + Cell.sizeof);
+ // Add one page to the header pointer to get the start of the cell data.
+ return cast(void*) (cast(byte*) this + 4096);
}
/// Return true if the cell should be finalized, false otherwise.
// Standard imports
import cstring = tango.stdc.string;
+import mman = tango.stdc.posix.sys.mman;
+// XXX: missing in Tango 0.99.8 for Linux
+extern (C) int mprotect(void*, size_t, int);
// Debug imports
this.live_list.unlink(cell);
if (cell.has_finalizer)
rt_finalize(cell.ptr, false);
+ // Forbid the mutator read/write cell data
+ int r = mprotect(cast(byte*) cell + 4096, cell.capacity,
+ mman.PROT_NONE);
+ assert (r != -1);
this.free_list.link(cell);
}
}
return null;
reuse:
+ // Allow the mutator to read/write cell data
+ int r = mprotect(cast(byte*) cell + 4096, cell.capacity,
+ mman.PROT_READ | mman.PROT_WRITE);
+ assert (r != -1);
cell.size = size;
cell.attr = cast(BlkAttr) attr;
*/
void* realloc(void* ptr, size_t size, uint attr=0)
{
+ debug (gc_malloc) printf("gc.realloc(%p, %u, %u)\n", ptr, size, attr);
// Undercover malloc()
if (ptr is null)
// We have enough capacity already, just change the size
if (cell.capacity >= size) {
+ debug (gc_malloc)
+ printf("gc.realloc() - cell has %zu capacity, no need to "
+ "realloc\n", cell.capacity);
cell.size = size;
return cell.ptr;
}
auto cell = Cell.alloc(size);
if (cell is null)
return 0;
+ // Forbid the mutator read/write cell data
+ int r = mprotect(cast(byte*) cell + 4096, cell.capacity,
+ mman.PROT_NONE);
+ assert (r != -1);
this.free_list.link(cell);
return cell.capacity;
}
*/
void free(void* ptr)
{
+ debug (gc_malloc) printf("gc.free(%p)\n", ptr);
+
if (ptr is null)
return;
auto cell = this.live_list.pop(ptr);
assert (cell !is null);
+ // Forbid the mutator read/write cell data
+ int r = mprotect(cast(byte*) cell + 4096, cell.capacity,
+ mman.PROT_NONE);
+ assert (r != -1);
+
this.free_list.link(cell);
}