struct RBasic* mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) { struct RBasic *p; static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } }; #ifdef MRB_GC_STRESS mrb_garbage_collect(mrb); #endif if (mrb->gc_threshold < mrb->live) { mrb_incremental_gc(mrb); } if (mrb->free_heaps == NULL) { add_heap(mrb); } p = mrb->free_heaps->freelist; mrb->free_heaps->freelist = ((struct free_obj*)p)->next; if (mrb->free_heaps->freelist == NULL) { unlink_free_heap_page(mrb, mrb->free_heaps); } mrb->live++; gc_protect(mrb, p); *(RVALUE *)p = RVALUE_zero; p->tt = ttype; p->c = cls; paint_partial_white(mrb, p); return p; }
void* mrb_realloc(mrb_state *mrb, void *p, size_t len) { void *p2; p2 = (mrb->allocf)(mrb, p, len, mrb->ud); if (!p2 && len > 0 && mrb->heaps) { mrb_garbage_collect(mrb); p2 = (mrb->allocf)(mrb, p, len, mrb->ud); } if (!p2 && len) { if (mrb->out_of_memory) { /* mrb_panic(mrb); */ } else { mrb->out_of_memory = 1; mrb_raise(mrb, E_RUNTIME_ERROR, "Out of memory"); } } else { mrb->out_of_memory = 0; } return p2; }
void test_incremental_gc(void) { mrb_state *mrb = mrb_open(); size_t max = ~0, live = 0, total = 0, freed = 0; RVALUE *free; struct heap_page *page; puts("test_incremental_gc"); mrb_garbage_collect(mrb); gc_assert(mrb->gc_state == GC_STATE_NONE); incremental_gc(mrb, max); gc_assert(mrb->gc_state == GC_STATE_MARK); incremental_gc(mrb, max); gc_assert(mrb->gc_state == GC_STATE_MARK); incremental_gc(mrb, max); gc_assert(mrb->gc_state == GC_STATE_SWEEP); page = mrb->heaps; while (page) { RVALUE *p = page->objects; RVALUE *e = p + MRB_HEAP_PAGE_SIZE; while (p<e) { if (is_black(&p->as.basic)) { live++; } if (is_gray(&p->as.basic) && !is_dead(mrb, &p->as.basic)) { printf("%p\n", &p->as.basic); } p++; } page = page->next; total += MRB_HEAP_PAGE_SIZE; } gc_assert(mrb->gray_list == NULL); incremental_gc(mrb, max); gc_assert(mrb->gc_state == GC_STATE_SWEEP); incremental_gc(mrb, max); gc_assert(mrb->gc_state == GC_STATE_NONE); free = (RVALUE*)mrb->heaps->freelist; while (free) { freed++; free = (RVALUE*)free->as.free.next; } gc_assert(mrb->live == live); gc_assert(mrb->live == total-freed); mrb_close(mrb); }
void* mrb_realloc(mrb_state *mrb, void *p, size_t len) { p = (mrb->allocf)(mrb, p, len); if (!p && len > 0 && mrb->heaps) { mrb_garbage_collect(mrb); p = (mrb->allocf)(mrb, p, len); } return p; }
void* mrb_realloc(mrb_state *mrb, void *p, size_t len) { void *p2; p2 = (mrb->allocf)(mrb, p, len, mrb->ud); if (!p2 && len > 0 && mrb->heaps) { mrb_garbage_collect(mrb); p2 = (mrb->allocf)(mrb, p, len, mrb->ud); } return p2; }
static int mrb_pipe(mrb_state *mrb, int pipes[2]) { int ret; ret = mrb_cloexec_pipe(mrb, pipes); if (ret == -1) { if (errno == EMFILE || errno == ENFILE) { mrb_garbage_collect(mrb); ret = mrb_cloexec_pipe(mrb, pipes); } } return ret; }
int mrb_cloexec_open(mrb_state *mrb, const char *pathname, mrb_int flags, mrb_int mode) { mrb_value emsg; int fd, retry = FALSE; char* fname = mrb_locale_from_utf8(pathname, -1); #ifdef O_CLOEXEC /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */ flags |= O_CLOEXEC; #elif defined O_NOINHERIT flags |= O_NOINHERIT; #endif reopen: fd = open(fname, (int)flags, (fmode_t)mode); if (fd == -1) { if (!retry) { switch (errno) { case ENFILE: case EMFILE: mrb_garbage_collect(mrb); retry = TRUE; goto reopen; } } emsg = mrb_format(mrb, "open %S", mrb_str_new_cstr(mrb, pathname)); mrb_str_modify(mrb, mrb_str_ptr(emsg)); mrb_sys_fail(mrb, RSTRING_PTR(emsg)); } mrb_locale_free(fname); if (fd <= 2) { mrb_fd_cloexec(mrb, fd); } return fd; }
static mrb_value gc_start(mrb_state *mrb, mrb_value obj) { mrb_garbage_collect(mrb); return mrb_nil_value(); }
void test_incremental_gc(void) { mrb_state *mrb = mrb_open(); size_t max = ~0, live = 0, total = 0, freed = 0; RVALUE *free; struct heap_page *page; puts("test_incremental_gc"); change_gen_gc_mode(mrb, FALSE); puts(" in mrb_garbage_collect"); mrb_garbage_collect(mrb); gc_assert(mrb->gc_state == GC_STATE_NONE); puts(" in GC_STATE_NONE"); incremental_gc(mrb, max); gc_assert(mrb->gc_state == GC_STATE_MARK); puts(" in GC_STATE_MARK"); advance_phase(mrb, GC_STATE_SWEEP); gc_assert(mrb->gc_state == GC_STATE_SWEEP); puts(" in GC_STATE_SWEEP"); page = mrb->heaps; while (page) { RVALUE *p = page->objects; RVALUE *e = p + MRB_HEAP_PAGE_SIZE; while (p<e) { if (is_black(&p->as.basic)) { live++; } if (is_gray(&p->as.basic) && !is_dead(mrb, &p->as.basic)) { printf("%p\n", &p->as.basic); } p++; } page = page->next; total += MRB_HEAP_PAGE_SIZE; } gc_assert(mrb->gray_list == NULL); incremental_gc(mrb, max); gc_assert(mrb->gc_state == GC_STATE_SWEEP); incremental_gc(mrb, max); gc_assert(mrb->gc_state == GC_STATE_NONE); free = (RVALUE*)mrb->heaps->freelist; while (free) { freed++; free = (RVALUE*)free->as.free.next; } gc_assert(mrb->live == live); gc_assert(mrb->live == total-freed); puts("test_incremental_gc(gen)"); advance_phase(mrb, GC_STATE_SWEEP); change_gen_gc_mode(mrb, TRUE); gc_assert(mrb->gc_full == FALSE); gc_assert(mrb->gc_state == GC_STATE_NONE); puts(" in minor"); gc_assert(is_minor_gc(mrb)); gc_assert(mrb->majorgc_old_threshold > 0); mrb->majorgc_old_threshold = 0; mrb_incremental_gc(mrb); gc_assert(mrb->gc_full == TRUE); gc_assert(mrb->gc_state == GC_STATE_NONE); puts(" in major"); gc_assert(is_major_gc(mrb)); do { mrb_incremental_gc(mrb); } while (mrb->gc_state != GC_STATE_NONE); gc_assert(mrb->gc_full == FALSE); mrb_close(mrb); }