/************** Debugging ***************************/
//debug = COLLECT_PRINTF; // turn on printf's
-//debug = MEMSTOMP; // stomp on memory
-//debug = SENTINEL; // add underrun/overrrun protection
//debug = PTRCHECK; // more pointer checking
//debug = PTRCHECK2; // thorough but slow pointer checking
import rt.gc.cdgc.bits: GCBits;
import rt.gc.cdgc.stats: GCStats;
-import alloc = rt.gc.cdgc.alloc;
import rt.gc.cdgc.dynarray: DynArray;
+import alloc = rt.gc.cdgc.alloc;
+import opts = rt.gc.cdgc.opts;
import cstdlib = tango.stdc.stdlib;
import cstring = tango.stdc.string;
static import gcc.builtins; // for __builtin_unwind_int
}
-
struct BlkInfo
{
void* base;
void initialize()
{
+ opts.parse(cstdlib.getenv("D_GC_OPTS"));
gcLock = GCLock.classinfo;
gcx = cast(Gcx*) cstdlib.calloc(1, Gcx.sizeof);
if (!gcx)
assert(gcx);
- size += SENTINEL_EXTRA;
+ if (opts.options.sentinel)
+ size += SENTINEL_EXTRA;
// Compute size bin
// Cache previous binsize lookup - Dave Fladebo.
gcx.bucket[bin] = (cast(List*)p).next;
if( !(bits & BlkAttr.NO_SCAN) )
memset(p + size, 0, binsize[bin] - size);
- debug (MEMSTOMP) memset(p, 0xF0, size);
+ if (opts.options.mem_stomp)
+ memset(p, 0xF0, size);
}
else
{
if (!p)
onOutOfMemoryError();
}
- size -= SENTINEL_EXTRA;
- p = sentinel_add(p);
- sentinel_init(p, size);
+ if (opts.options.sentinel) {
+ size -= SENTINEL_EXTRA;
+ p = sentinel_add(p);
+ sentinel_init(p, size);
+ }
if (bits)
{
void *p2;
size_t psize;
- version (SENTINEL)
+ if (opts.options.sentinel)
{
sentinel_Invariant(p);
psize = *sentinel_size(p);
// Shrink in place
synchronized (gcLock)
{
- debug (MEMSTOMP)
+ if (opts.options.mem_stomp)
memset(p + size, 0xF2, psize - size);
pool.freePages(pagenum + newsz, psz - newsz);
}
{
if (i == pagenum + newsz)
{
- debug (MEMSTOMP)
- memset(p + psize, 0xF0,
- size - psize);
+ if (opts.options.mem_stomp)
+ memset(p + psize, 0xF0, size - psize);
memset(pool.pagetable + pagenum +
psz, B_PAGEPLUS, newsz - psz);
return p;
}
body
{
- version (SENTINEL)
+ if (opts.options.sentinel)
{
return 0;
}
}
if (sz < minsz)
return 0;
- debug (MEMSTOMP)
+ if (opts.options.mem_stomp)
memset(p + psize, 0xF0, (psz + sz) * PAGESIZE - psize);
memset(pool.pagetable + pagenum + psz, B_PAGEPLUS, sz);
gcx.p_cache = null;
pool = gcx.findPool(p);
if (!pool) // if not one of ours
return; // ignore
- sentinel_Invariant(p);
- p = sentinel_sub(p);
+ if (opts.options.sentinel) {
+ sentinel_Invariant(p);
+ p = sentinel_sub(p);
+ }
pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE;
biti = cast(size_t)(p - pool.baseAddr) / 16;
gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
size_t n = pagenum;
while (++n < pool.npages && pool.pagetable[n] == B_PAGEPLUS)
npages++;
- debug (MEMSTOMP) memset(p, 0xF2, npages * PAGESIZE);
+ if (opts.options.mem_stomp)
+ memset(p, 0xF2, npages * PAGESIZE);
pool.freePages(pagenum, npages);
}
else
// Add to free list
List *list = cast(List*)p;
- debug (MEMSTOMP) memset(p, 0xF2, binsize[bin]);
+ if (opts.options.mem_stomp)
+ memset(p, 0xF2, binsize[bin]);
list.next = gcx.bucket[bin];
gcx.bucket[bin] = list;
{
assert (p);
- version (SENTINEL)
+ if (opts.options.sentinel)
{
p = sentinel_sub(p);
size_t size = gcx.findSize(p);
{
assert(p);
- sentinel_Invariant(p);
+ if (opts.options.sentinel)
+ sentinel_Invariant(p);
debug (PTRCHECK)
{
Pool* pool;
Bins bin;
size_t size;
- p = sentinel_sub(p);
+ if (opts.options.sentinel)
+ p = sentinel_sub(p);
pool = gcx.findPool(p);
assert(pool);
pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE;
memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1);
p = pool.baseAddr + pn * PAGESIZE;
memset(cast(char *)p + size, 0, npages * PAGESIZE - size);
- debug (MEMSTOMP) memset(p, 0xF1, size);
+ if (opts.options.mem_stomp)
+ memset(p, 0xF1, size);
return p;
Lnomemory:
{
for (; p < ptop; p += size, biti += bitstride)
{
- if (pool.finals.nbits && pool.finals.testClear(biti))
- rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/);
+ if (pool.finals.nbits && pool.finals.testClear(biti)) {
+ if (opts.options.sentinel)
+ rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/);
+ else
+ rt_finalize(cast(List *)p, false/*noStack > 0*/);
+ }
gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
List *list = cast(List *)p;
- debug (MEMSTOMP) memset(p, 0xF3, size);
+ if (opts.options.mem_stomp)
+ memset(p, 0xF3, size);
}
pool.pagetable[pn] = B_FREE;
freed += PAGESIZE;
{
if (!pool.mark.test(biti))
{
- sentinel_Invariant(sentinel_add(p));
+ if (opts.options.sentinel)
+ sentinel_Invariant(sentinel_add(p));
pool.freebits.set(biti);
- if (pool.finals.nbits && pool.finals.testClear(biti))
- rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/);
+ if (pool.finals.nbits && pool.finals.testClear(biti)) {
+ if (opts.options.sentinel)
+ rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/);
+ else
+ rt_finalize(cast(List *)p, false/*noStack > 0*/);
+ }
clrBits(pool, biti, BlkAttr.ALL_BITS);
List *list = cast(List *)p;
- debug (MEMSTOMP) memset(p, 0xF3, size);
+ if (opts.options.mem_stomp)
+ memset(p, 0xF3, size);
freed += size;
}
if (!pool.mark.test(biti))
{
byte *p = pool.baseAddr + pn * PAGESIZE;
- sentinel_Invariant(sentinel_add(p));
- if (pool.finals.nbits && pool.finals.testClear(biti))
- rt_finalize(sentinel_add(p), false/*noStack > 0*/);
+ if (opts.options.sentinel)
+ sentinel_Invariant(sentinel_add(p));
+ if (pool.finals.nbits && pool.finals.testClear(biti)) {
+ if (opts.options.sentinel)
+ rt_finalize(sentinel_add(p), false/*noStack > 0*/);
+ else
+ rt_finalize(p, false/*noStack > 0*/);
+ }
clrBits(pool, biti, BlkAttr.ALL_BITS);
debug(COLLECT_PRINTF) printf("\tcollecting big %x\n", p);
pool.pagetable[pn] = B_FREE;
freedpages++;
- debug (MEMSTOMP) memset(p, 0xF3, PAGESIZE);
+ if (opts.options.mem_stomp)
+ memset(p, 0xF3, PAGESIZE);
while (pn + 1 < pool.npages && pool.pagetable[pn + 1] == B_PAGEPLUS)
{
pn++;
pool.pagetable[pn] = B_FREE;
freedpages++;
- debug (MEMSTOMP)
+ if (opts.options.mem_stomp)
{
p += PAGESIZE;
memset(p, 0xF3, PAGESIZE);
/* ============================ SENTINEL =============================== */
-version (SENTINEL)
-{
- const size_t SENTINEL_PRE = cast(size_t) 0xF4F4F4F4F4F4F4F4UL; // 32 or 64 bits
- const ubyte SENTINEL_POST = 0xF5; // 8 bits
- const uint SENTINEL_EXTRA = 2 * size_t.sizeof + 1;
-
-
- size_t* sentinel_size(void *p) { return &(cast(size_t *)p)[-2]; }
- size_t* sentinel_pre(void *p) { return &(cast(size_t *)p)[-1]; }
- ubyte* sentinel_post(void *p) { return &(cast(ubyte *)p)[*sentinel_size(p)]; }
-
-
- void sentinel_init(void *p, size_t size)
- {
- *sentinel_size(p) = size;
- *sentinel_pre(p) = SENTINEL_PRE;
- *sentinel_post(p) = SENTINEL_POST;
- }
+const size_t SENTINEL_PRE = cast(size_t) 0xF4F4F4F4F4F4F4F4UL; // 32 or 64 bits
+const ubyte SENTINEL_POST = 0xF5; // 8 bits
+const uint SENTINEL_EXTRA = 2 * size_t.sizeof + 1;
- void sentinel_Invariant(void *p)
- {
- assert(*sentinel_pre(p) == SENTINEL_PRE);
- assert(*sentinel_post(p) == SENTINEL_POST);
- }
+size_t* sentinel_size(void *p) { return &(cast(size_t *)p)[-2]; }
+size_t* sentinel_pre(void *p) { return &(cast(size_t *)p)[-1]; }
+ubyte* sentinel_post(void *p) { return &(cast(ubyte *)p)[*sentinel_size(p)]; }
- void *sentinel_add(void *p)
- {
- return p + 2 * size_t.sizeof;
- }
-
-
- void *sentinel_sub(void *p)
- {
- return p - 2 * size_t.sizeof;
- }
-}
-else
+void sentinel_init(void *p, size_t size)
{
- const uint SENTINEL_EXTRA = 0;
-
-
- void sentinel_init(void *p, size_t size)
- {
- }
+ *sentinel_size(p) = size;
+ *sentinel_pre(p) = SENTINEL_PRE;
+ *sentinel_post(p) = SENTINEL_POST;
+}
- void sentinel_Invariant(void *p)
- {
- }
+void sentinel_Invariant(void *p)
+{
+ assert(*sentinel_pre(p) == SENTINEL_PRE);
+ assert(*sentinel_post(p) == SENTINEL_POST);
+}
- void *sentinel_add(void *p)
- {
- return p;
- }
+void *sentinel_add(void *p)
+{
+ return p + 2 * size_t.sizeof;
+}
- void *sentinel_sub(void *p)
- {
- return p;
- }
+void *sentinel_sub(void *p)
+{
+ return p - 2 * size_t.sizeof;
}
--- /dev/null
+/**
+ * This module contains the options managemente code of the garbage collector.
+ *
+ * Copyright: Copyright (C) 2010 Leandro Lucarella <http://www.llucax.com.ar/>
+ * All rights reserved.
+ *
+ * License: Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Leandro Lucarella
+ */
+
+module rt.gc.cdgc.opts;
+
+import cstdlib = tango.stdc.stdlib;
+import cstring = tango.stdc.string;
+
+
+private:
+
+
+const MAX_OPT_LEN = 256;
+
+
+struct Options
+{
+ uint verbose = 0;
+ char[MAX_OPT_LEN] log_file = "";
+ bool sentinel = false;
+ bool mem_stomp = false;
+}
+
+package Options options;
+
+
+void process_option(char* opt_name, char* opt_value)
+{
+ if (cstring.strcmp(opt_name, "verbose") == 0)
+ {
+ options.verbose = cstdlib.atoi(opt_value);
+ }
+ else if (cstring.strcmp(opt_name, "log_file") == 0)
+ {
+ cstring.strcpy(options.log_file.ptr, opt_value);
+ }
+ else if (cstring.strcmp(opt_name, "sentinel") == 0)
+ {
+ if (opt_value[0] == '\0')
+ options.sentinel = true;
+ else
+ options.sentinel = (cstdlib.atoi(opt_value) != 0);
+ }
+ else if (cstring.strcmp(opt_name, "mem_stomp") == 0)
+ {
+ if (opt_value[0] == '\0')
+ options.mem_stomp = true;
+ else
+ options.mem_stomp = (cstdlib.atoi(opt_value) != 0);
+ }
+}
+
+
+package void parse(char* opts_string)
+{
+ char[MAX_OPT_LEN] opt_name;
+ char[MAX_OPT_LEN] opt_value;
+ char* curr = opt_name.ptr;
+ size_t i = 0;
+ if (opts_string is null)
+ return;
+ for (; *opts_string != '\0'; opts_string++)
+ {
+ char c = *opts_string;
+ if (i == MAX_OPT_LEN)
+ {
+ if (c != ':')
+ continue;
+ else
+ i--;
+ }
+ switch (*opts_string)
+ {
+ case ':':
+ curr[i] = '\0';
+ process_option(opt_name.ptr, opt_value.ptr);
+ i = 0;
+ opt_name[0] = '\0';
+ opt_value[0] = '\0';
+ curr = opt_name.ptr;
+ break;
+ case '=':
+ opt_name[i] = '\0';
+ curr = opt_value.ptr;
+ i = 0;
+ break;
+ default:
+ curr[i] = c;
+ ++i;
+ }
+ }
+ if (i == MAX_OPT_LEN)
+ i--;
+ curr[i] = '\0';
+ process_option(opt_name.ptr, opt_value.ptr);
+}
+
+
+unittest
+{
+ with (options) {
+ assert (verbose == 0);
+ assert (log_file[0] == '\0');
+ assert (sentinel == false);
+ assert (mem_stomp == false);
+ }
+ parse("mem_stomp=1:verbose=2");
+ with (options) {
+ assert (verbose == 2);
+ assert (log_file[0] == '\0');
+ assert (sentinel == false);
+ assert (mem_stomp == true);
+ }
+ parse("log_file=12345 67890:verbose=1:sentinel=4:mem_stomp=0");
+ with (options) {
+ assert (verbose == 1);
+ assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
+ assert (sentinel == true);
+ assert (mem_stomp == false);
+ }
+ parse(null);
+ with (options) {
+ assert (verbose == 1);
+ assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
+ assert (sentinel == true);
+ assert (mem_stomp == false);
+ }
+}
+
+
+// vim: set et sw=4 sts=4 :