예제 #1
0
파일: gc_collect.c 프로젝트: munraj/cherigc
void
gc_collect(void)
{
	int rc;

	switch (gc_state_c->gs_mark_state) {
	case GC_MS_MARK:
		gc_resume_marking();
		break;
	case GC_MS_SWEEP:
		gc_resume_sweeping();
		break;
	case GC_MS_NONE:
		gc_debug("beginning a new collection");
#ifdef GC_COLLECT_STATS
		gc_state_c->gs_nmark = 0;
		gc_state_c->gs_nmarkbytes = 0;
		gc_state_c->gs_nsweep = 0;
		gc_state_c->gs_nsweepbytes = 0;
		gc_state_c->gs_ntcollect++;
#endif
		/* Update the VM info. */
		if (gc_vm_tbl_update(&gc_state_c->gs_vt) != GC_SUCC) {
			gc_error("gc_vm_tbl_update");
			return;
		}
		gc_print_vm_tbl(&gc_state_c->gs_vt);
		/* Get the trusted stack. */
		rc = gc_cheri_get_ts(gc_state_c->gs_gts_c);
		if (rc != 0) {
			gc_error("gc_cheri_get_ts error: %d", rc);
			return;
		}
		gc_start_marking();
		/* Because we're not incremental yet: */
		/*while (gc_state_c->mark_state != GC_MS_SWEEP)
			gc_resume_marking();
		while (gc_state_c->mark_state != GC_MS_NONE)
			gc_resume_sweeping();*/
		while (gc_state_c->gs_mark_state != GC_MS_NONE)
			gc_resume_marking();
		/* Restore the trusted stack. */
		rc = gc_cheri_put_ts(gc_state_c->gs_gts_c);
		if (rc != 0) {
			gc_error("gc_cheri_put_ts error: %d", rc);
		return;
	}

		break;
	default:
		/* NOTREACHABLE */
		GC_NOTREACHABLE_ERROR();
		break;
	}
}
예제 #2
0
파일: gc_vm.c 프로젝트: munraj/cherigc
int
gc_vm_tbl_update(_gc_cap struct gc_vm_tbl *vt)
{
#ifdef GC_USE_LIBPROCSTAT
	struct procstat *ps;
	struct kinfo_vmentry *kv;
	struct kinfo_proc *kp;
	unsigned cnt, i;

	ps = procstat_open_sysctl();
	if (ps == NULL)
		return (GC_ERROR);
	cnt = 0;
	kp = procstat_getprocs(ps, KERN_PROC_PID, getpid(), &cnt);
	if (kp == NULL)
		return (GC_ERROR);
	gc_debug("getprocs retrieved %u procs", cnt);
	kv = procstat_getvmmap(ps, kp, &cnt);
	if (kv == NULL)
		return (GC_ERROR);
	gc_debug("getvmmap retrieved %u entries", cnt);
	if (vt->vt_sz < cnt)
		return (GC_TOO_SMALL);
	vt->vt_nent = cnt;
	for (i = 0; i < vt->vt_nent; i++) {
		vt->vt_ent[i].ve_start = kv[i].kve_start;
		vt->vt_ent[i].ve_end = kv[i].kve_end;
		vt->vt_ent[i].ve_prot = kv[i].kve_protection;
		vt->vt_ent[i].ve_type = kv[i].kve_type;
		vt->vt_ent[i].ve_gctype = 0;
		gc_vm_tbl_track(vt, &vt->vt_ent[i]);
	}
	procstat_freevmmap(ps, kv);
	procstat_freeprocs(ps, kp);
	procstat_close(ps);
	return (GC_SUCC);
#else /* !GC_USE_LIBPROCSTAT */
	return (GC_ERROR);
#endif /* GC_USE_LIBPROCSTAT */
}
예제 #3
0
파일: gc.c 프로젝트: GJDuck/SMCHR
/*
 * GC collection.
 */
extern void GC_collect(void)
{
    // Is collection enabled?
    if (!gc_enabled)
        return;

    // Initialize marking
    gc_debug("collect [stage=init_marks]");
    gc_mark_init();

    gc_debug("collect [stage=mark]");
    struct gc_root_s root_0;
    gc_root_t root = &root_0;
    root->ptr = (void *)gc_stacktop();
    root->size = gc_stackbottom - root->ptr;
    root->ptrptr = &root->ptr;
    root->sizeptr = &root->size;
    root->elemsize = 1;
    root->next = gc_roots;
    gc_root_t roots = root;

    gc_mark(roots);
    gc_sweep();
}
예제 #4
0
파일: gc.c 프로젝트: GJDuck/SMCHR
/*
 * GC handle error.
 */
extern void GC_handle_error(bool fatal, int err)
{
    if (err != 0)
        errno = err;
    gc_debug("error occured [fatal=%d, errno=%s]\n", fatal,
        strerror(errno));
    gc_error_func_t func = gc_error_func;
    if (func != NULL)
        func();
    if (fatal)
    {
        fprintf(stderr, "GC fatal error (%s)\n", strerror(errno));
        abort();
    }
}
예제 #5
0
파일: gc_vm.c 프로젝트: munraj/cherigc
_gc_cap struct gc_vm_ent *
gc_vm_tbl_find_btbl(_gc_cap struct gc_vm_tbl *vt, _gc_cap struct gc_btbl *bt)
{
	size_t i;
	_gc_cap struct gc_vm_ent *ve;
	uint64_t start, end;

	start = gc_cheri_getbase(bt->bt_base);
	end = start + gc_cheri_getlen(bt->bt_base);
	for (i = 0; i < vt->vt_nent; i++) {
		ve = &vt->vt_ent[i];
		gc_debug("search:[%llx,%llx] cur:[%llx,%llx]",
			start,end,ve->ve_start,ve->ve_end);
		if (ve->ve_start == start && ve->ve_end == end)
			return (ve);
	}

	return (NULL);
}
예제 #6
0
파일: gc.c 프로젝트: GJDuck/SMCHR
/*
 * GC marking.
 */
static void gc_mark(gc_root_t roots)
{
    gc_markstack_t stack =
        (gc_markstack_t)(gc_markstack + GC_MARK_STACK_SIZE);
    stack--;
    stack->startptr = NULL;
    stack->endptr   = NULL;

    gc_used_size = 0;
 
    while (true)
    {
        void **ptrptr = stack->startptr;
        void **endptr = stack->endptr;
        if (ptrptr == NULL)
        {
            // Attempt to find some work from the root list.
            if (roots != NULL)
            {
                ptrptr = (void **)*roots->ptrptr;
                size_t size = (*roots->sizeptr)*roots->elemsize;
                endptr = ptrptr + size/sizeof(void *);
                roots = roots->next;
                goto gc_mark_loop_inner;
            }

            gc_debug("collect [stage=sweep]");
            return;
        }
        else
            stack++;

        uint32_t pushed;
gc_mark_loop_inner:

        pushed = 0;
        while (ptrptr < endptr)
        {
            void *ptr = *ptrptr;
            ptrptr++;

            if (!gc_isptr(ptr))
            {
                // 'ptr' is not a value that points to anywhere in the GC's
                // reserved virtual memory addresses; not a GC pointer.
                continue;
            }
            gc_read_prefetch(ptrptr);
            size_t idx = gc_index(ptr);
            gc_region_t region = __gc_regions + idx;
            if (ptr >= region->freeptr || ptr < region->startptr) 
            {
                // 'ptr' points to memory that hasn't been allocated yet, or
                // cannot be collected yet; not a GC pointer.
                continue;
            }

            // 'ptr' has been deemed to be a GC pointer; check if it has been
            // marked;
            uint32_t size = region->size;
            uint32_t ptridx = (uint32_t)(gc_objidx(ptr) - region->startidx);
            if (!gc_mark_index(region->markptr, ptridx))
            {
                // 'ptr' is already marked; no need to follow it.
                continue;
            }
 
            gc_used_size += size;
            ptr = region->startptr + (size_t)ptridx*(size_t)size;
            gc_read_prefetch(ptr);

            // Push onto mark stack:
            stack--;
            stack->startptr = (void **)ptr;
            stack->endptr = (void **)(ptr + size);

            if (pushed > GC_MAX_MARK_PUSH)
            {
                void **tmp_ptrptr = stack[pushed].startptr;
                void **tmp_endptr = stack[pushed].endptr;
                stack[pushed].startptr = ptrptr;
                stack[pushed].endptr   = endptr;
                ptrptr = tmp_ptrptr;
                endptr = tmp_endptr;
                pushed = 0;
            }
            pushed++;
        }
    }
}
예제 #7
0
파일: gc.c 프로젝트: GJDuck/SMCHR
/*
 * GC memory allocation.
 */
extern void *GC_malloc_index(size_t idx)
{
    gc_region_t region = __gc_regions + idx;
    void *ptr;

    // (0) Check if we need to collect.
    gc_maybe_collect(region->size);
    
    // (1) First, attempt to allocate from the freelist.
    gc_freelist_t freelist = region->freelist, next;
    if (freelist != NULL)
    {
nonempty_freelist:
        next = gc_unhide(freelist->next);
        region->freelist = next;
        ptr = (void *)freelist;
        return ptr;
    }

    // (2) Next, attempt to allocated from marked memory.
    if (region->markstartptr < region->markendptr)
    {
        ptr = region->markstartptr;
        uint32_t ptridx = (uint32_t)(gc_objidx(ptr) - region->startidx);
        uint8_t *markptr = region->markptr;
        for (size_t i = 0; i < GC_FREELIST_LEN && ptr < region->markendptr; )
        {
            if (!gc_is_marked_index(markptr, ptridx))
            {
                gc_freelist_t freenode = (gc_freelist_t)ptr;
                freenode->next = gc_hide(freelist);
                freelist = freenode;
                i++;
            }
            ptr += region->size;
            ptridx++;
        }
        region->markstartptr = ptr;
        region->freelist = freelist;
        if (freelist != NULL)
            goto nonempty_freelist;
    }

    // (3) Next, attempt to allocate from fresh space.
    ptr = region->freeptr;
    region->freeptr = ptr + region->size;
    if (ptr >= region->endptr)
    {
        gc_handle_error(false, ENOMEM);
        return NULL;
    }

    // Check if we can access the memory.
    if (ptr + region->size >= region->protectptr)
    {
        void *protectptr = region->protectptr;
        size_t protectlen = GC_PROTECT_LEN*GC_PAGESIZE;
        protectlen = (protectlen < region->size? region->size:
            protectlen);
        if (gc_protect_memory(protectptr, protectlen) != 0)
        {
            gc_debug("protect failed");
            gc_handle_error(false, 0);
            return NULL;
        }
        region->protectptr = protectptr + protectlen;
    }

    return ptr;
}
예제 #8
0
파일: gc.c 프로젝트: GJDuck/SMCHR
/*
 * GC initialization.
 */
extern bool GC_init(void)
{
    if (gc_inited)
        return true;    // Already initialised.

    gc_debug("initializing");

    // Check that we are in a 64-bit environment.
    if (sizeof(void *) != sizeof(uint64_t) ||
        sizeof(double) != sizeof(uint64_t))
    {
        errno = ENOEXEC;
        return false;
    }

    // Find the stack:
    gc_stackbottom = gc_get_stackbottom();
    
    // Reserve a large chunk of the virtual address space for the GC.
    void *gc_memory = gc_get_memory();
    if (gc_memory != GC_MEMORY)
        goto init_error;

    // Initialize all of the region information structures.
    for (size_t i = 0; i < GC_NUM_REGIONS; i++)
    {
        void *startptr = GC_MEMORY + i*GC_REGION_SIZE;
        size_t unit = gc_index_unit(i);
        size_t size = (i - gc_unit_offset(unit))*unit + unit;
        uintptr_t offset = (uintptr_t)startptr % size;
        if (offset != 0)
            startptr += size - offset;
        gc_region_t region = __gc_regions + i;
        region->size         = size;
        region->inv_size     = (UINT64_MAX / size) + 1;
        region->freelist     = NULL;
        region->startptr     = startptr;
        region->endptr       = startptr + GC_REGION_SIZE;
        region->freeptr      = startptr;
        region->protectptr   = startptr;
        region->markstartptr = startptr;
        region->markendptr   = startptr;
        region->markptr      = NULL;
        region->startidx     = gc_objidx(startptr);
    }

    // Reserve virtual space for the mark stack.
    gc_markstack = gc_get_mark_memory(GC_MARK_STACK_SIZE);
    if (gc_markstack == NULL)
        goto init_error;

    gc_inited = true;
    return true;

    int saved_errno;
init_error:
    saved_errno = errno;
    if (gc_markstack != NULL)
        gc_free_memory(gc_markstack, GC_MARK_STACK_SIZE);
    if (gc_memory != NULL)
        gc_free_memory(GC_MEMORY, GC_NUM_REGIONS*GC_REGION_SIZE);
    errno = saved_errno;
    return false;
}