Exemplo n.º 1
0
/*************************************************************************************************
 * Threads
 */
mt_thread mt_thread_create(
    pfn_mt_thread_kernel kernel_fn, pfn_mt_thread_init init_fn, pfn_mt_thread_release release_fn,
    enum mt_thread_priority pr, size_t local_mem_sz, size_t tmp_mem_sz, void* param1, void* param2)
{
    static uint count = 0;
    result_t r;
    mt_thread thread = (mt_thread)ALLOC(sizeof(struct mt_thread_data), 0);
    if (thread == NULL)
        return NULL;
    memset(thread, 0x00, sizeof(struct mt_thread_data));

    if (local_mem_sz > 0)   {
        r = mem_freelist_create(mem_heap(), &thread->local_mem, local_mem_sz, 0);
        if (IS_FAIL(r)) {
            FREE(thread);
            return NULL;
        }
        mem_freelist_bindalloc(&thread->local_mem, &thread->local_alloc);
    }

    if (tmp_mem_sz > 0) {
        r = mem_stack_create(mem_heap(), &thread->tmp_mem, tmp_mem_sz, 0);
        if (IS_FAIL(r)) {
            FREE(thread);
            return NULL;
        }
        mem_stack_bindalloc(&thread->tmp_mem, &thread->tmp_alloc);
    }

    thread->kernel_fn = kernel_fn;
    thread->init_fn = init_fn;
    thread->release_fn = release_fn;
    thread->param1 = param1;
    thread->param2 = param2;
    thread->pr = pr;

    char e1name[32];
    char e2name[32];
    sprintf(e1name, "stop:t(%d)", count);
    sprintf(e2name, "resume:t(%d)", count);
    count++;

    thread->events[EVENT_STOP] = CreateEvent(NULL, TRUE, FALSE, e1name);
    thread->events[EVENT_RESUME] = CreateEvent(NULL, TRUE, TRUE, e2name);

    if (thread->events[EVENT_STOP] == NULL || thread->events[EVENT_RESUME] == NULL)
        return NULL;

    HANDLE t = CreateThread(NULL, 0, thread_callback, thread, 0, (DWORD*)&thread->id);
    if (t == NULL) {
        mt_thread_destroy(thread);
        return NULL;
    }

    thread->t = t;

    switch (pr)   {
    case MT_THREAD_NORMAL:    SetThreadPriority(thread->t, THREAD_PRIORITY_NORMAL);    break;
    case MT_THREAD_HIGH:      SetThreadPriority(thread->t, THREAD_PRIORITY_HIGHEST);   break;
    case MT_THREAD_LOW:       SetThreadPriority(thread->t, THREAD_PRIORITY_LOWEST);    break;
    }

    return thread;
}
Exemplo n.º 2
0
void test_freelist()
{
    const uint item_cnt = 100000;
    const uint max_size = item_cnt * 1024;
    void** ptrs = (void**)ALLOC(item_cnt*sizeof(void*), 0);
    uint* h = (uint*)ALLOC(item_cnt*sizeof(uint), 0);
    size_t* sizes = (size_t*)ALLOC(item_cnt*sizeof(size_t), 0);

    uint free_cnt = 0;

    struct freelist_alloc freelist;
    struct allocator alloc;
    mem_freelist_create(mem_heap(), &freelist, max_size, 0);
    mem_freelist_bindalloc(&freelist, &alloc);

    uint64 t1 = timer_querytick();

    log_printf(LOG_TEXT, "allocating %d items from freelist (with hash validation)...", item_cnt);
    for (uint i = 0; i < item_cnt; i++)    {
        int s = rand_geti(8, 1024);
        ASSERT(s <= 1024);
        ptrs[i] = A_ALLOC(&alloc, s, 6);
        ASSERT(ptrs[i]);

        if (i > 0 && rand_flipcoin(50))  {
            uint idx_tofree = rand_geti(0, i-1);
            if (ptrs[idx_tofree] != NULL)   {
                A_FREE(&alloc, ptrs[idx_tofree]);
                ptrs[idx_tofree] = NULL;
            }
        }

        // random fill the buffer
        memset(ptrs[i], 0x00, s);

        h[i] = hash_murmur32(ptrs[i], s, 100);
        sizes[i] = s;
    }

    // check if the remaining buffers are untouched
    for (uint i = 0; i < item_cnt; i++)   {
        if (ptrs[i] != NULL)    {
#if defined(_DEBUG_)
            uint hh = hash_murmur32(ptrs[i], sizes[i], 100);
            ASSERT(h[i] == hh);
#endif
        }
    }

    for (uint i = 0; i < item_cnt; i++)   {
        //if (rand_flipcoin(50))  {
        if (ptrs[i] != NULL)    {
            A_FREE(&alloc, ptrs[i]);
            free_cnt ++;
            ptrs[i] = NULL;
        }
        //}
    }

    /* report leaks */
    uint leaks_cnt = mem_freelist_getleaks(&freelist, NULL);
    if (leaks_cnt > 0)
        log_printf(LOG_TEXT, "%d leaks found", leaks_cnt);

    mem_freelist_destroy(&freelist);
    log_print(LOG_TEXT, "done.");
    log_printf(LOG_TEXT, "took %f ms.",
        timer_calctm(t1, timer_querytick())*1000.0f);

    FREE(ptrs);
    FREE(h);
    FREE(sizes);
}
Exemplo n.º 3
0
result_t eng_init(const struct init_params* params)
{
    result_t r = RET_OK;

    ASSERT(g_eng == NULL);
    g_eng = (struct engine*)ALLOC(sizeof(struct engine), 0);
    if (g_eng == 0)
        return err_printn(__FILE__, __LINE__, RET_OUTOFMEMORY);
    memset(g_eng, 0x00, sizeof(struct engine));

    eng_zero();

    memcpy(&g_eng->params, params, sizeof(struct init_params));

    hw_getinfo(&g_eng->hwinfo, HWINFO_ALL);

    /* console (before anything else) */
    if (BIT_CHECK(params->flags, ENG_FLAG_CONSOLE))	{
		r |= con_init(params->console_lines_max);
		if (IS_FAIL(r))
			return RET_FAIL;
		log_outputfunc(TRUE, con_log, NULL);
    }

    /* show build options */
#if !defined(FULL_VERSION)
#error "must define FULL_VERSION macro"
#endif

    time_t raw_tm;
    time(&raw_tm);

    log_printf(LOG_TEXT, "init darkhammer engine v%s build[%s, %s, %s, %s], time: %s", 
        FULL_VERSION,
#if defined(_DEBUG_)
    		"debug"
#else
    		"release"
#endif
    		,
#if defined(_PROFILE_)
    		"profile"
#else
    		"no-profile"
#endif
    		,
#if defined(_X86_)
    		"x86"
#elif defined(_X64_)
    		"x64"
#endif
    		,
#if defined(_ENABLEASSERT_)
    		"assert"
#else
    		"no-assert"
#endif
            , asctime(localtime(&raw_tm)));

    /* hardware info */
    hw_printinfo(&g_eng->hwinfo, HWINFO_ALL);

    size_t tmp_sz = params->dev.buffsize_tmp;
    size_t data_sz = data_sz = params->dev.buffsize_data;
    tmp_sz = tmp_sz != 0 ? ((size_t)tmp_sz*1024) : FRAME_STACK_SIZE;
    data_sz = data_sz != 0 ? ((size_t)data_sz*1024) : DATA_SIZE;

    /* allocators */
    /* dynamic allocator for data in dev (editor) mode, stack allocator in game (normal) mode */
    if (BIT_CHECK(params->flags, ENG_FLAG_OPTIMIZEMEMORY))   {
        /* lsr (load-stay-resident) allocator for essential engine data */
        r |= mem_stack_create(mem_heap(), &g_eng->lsr_stack, LSR_SIZE, MID_DATA);
        mem_stack_bindalloc(&g_eng->lsr_stack, &g_eng->lsr_alloc);

        r |= mem_freelist_create(mem_heap(), &g_eng->data_freelist, data_sz, MID_DATA);
        mem_freelist_bindalloc(&g_eng->data_freelist, &g_eng->data_alloc);
    }   else    {
        mem_heap_bindalloc(&g_eng->data_alloc);
        mem_heap_bindalloc(&g_eng->lsr_alloc);

        g_eng->data_alloc.alloc_fn = eng_allocfn_data;
        g_eng->data_alloc.alignedalloc_fn = eng_alignedallocfn_data;
        g_eng->lsr_alloc.alloc_fn = eng_allocfn_lsr;
        g_eng->lsr_alloc.alignedalloc_fn = eng_alignedallocfn_lsr;

        r = RET_OK;
    }

    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: out of memory for allocators");
        return RET_FAIL;
    }

    /* timer manager and frame timer */
    g_eng->timer = timer_createinstance(TRUE);

    /* add engine's own data path to file-mgr */
    if (params->data_path != NULL)   {
        char data_path_ext[DH_PATH_MAX];
        path_getfileext(data_path_ext, params->data_path);
        if (str_isequal_nocase(data_path_ext, "pak"))    {
            if (IS_FAIL(pak_open(&g_eng->data_pak, mem_heap(), params->data_path, 0)))    {
                err_print(__FILE__, __LINE__, "engine init: could not open data pak");
                return RET_FAIL;
            }
        }   else   {
            if (!util_pathisdir(params->data_path)) {
                err_print(__FILE__, __LINE__, "engine init: data path is not valid");
                return RET_FAIL;
            }
            fio_addvdir(params->data_path, FALSE);
        }
        /* assume that share directory is same as data dir */
        path_getdir(g_eng->share_dir, params->data_path);
    }   else    {
        char data_path[DH_PATH_MAX];
        char share_dir[DH_PATH_MAX];
#ifndef SHARE_DIR
        char exe_dir[DH_PATH_MAX];
        path_join(share_dir, util_getexedir(exe_dir), "..", NULL);
        path_norm(share_dir, share_dir);
#else
        path_norm(share_dir, SHARE_DIR);
#endif
        path_join(data_path, share_dir, "data", NULL);
        if (!util_pathisdir(data_path)) {
            err_print(__FILE__, __LINE__, "engine init: data path is not valid");
            return RET_FAIL;
        }

        fio_addvdir(data_path, FALSE);  /* set default (config.h configured on build) data dir */
        strcpy(g_eng->share_dir, share_dir);
    }

    uint rs_flags = 0;
    /* activate hot loading in DEV mode */
    rs_flags |= BIT_CHECK(params->flags, ENG_FLAG_DEV) ? RS_FLAG_HOTLOADING : 0;
    if (!BIT_CHECK(params->flags, ENG_FLAG_DISABLEBGLOAD))  {
        rs_flags |= RS_FLAG_PREPARE_BGLOAD;
    }

    /* task manager */
    uint thread_cnt = maxui(g_eng->hwinfo.cpu_core_cnt - 1, 1);
    r = tsk_initmgr(thread_cnt, 0, tmp_sz, 0);
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init task-mgr");
        return RET_FAIL;
    }
    struct allocator* tmp_alloc = tsk_get_tmpalloc(0);
    A_SAVE(tmp_alloc);

    /* resource manager (with only 1 thread for multi-thread loading) */
    r = rs_initmgr(rs_flags, 1);
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init res-mgr");
        return RET_FAIL;
    }
    rs_set_dataalloc(&g_eng->lsr_alloc);

    /* graphics renderer */
    r = gfx_init(&params->gfx);
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init gfx");
        return RET_FAIL;
    }

    /* debug HUD */
    r = hud_init(BIT_CHECK(params->flags, ENG_FLAG_CONSOLE));
    if (IS_FAIL(r))	{
        err_print(__FILE__, __LINE__, "engine init failed: could not init debug-hud");
        return RET_FAIL;
    }

    /* Physics */
    if (!BIT_CHECK(params->flags, ENG_FLAG_DISABLEPHX)) {
        r = phx_init(params);
        if (IS_FAIL(r)) {
            err_print(__FILE__, __LINE__, "engine init failed: could not init physics");
            return RET_FAIL;
        }
    }

    /* component manager */
    r = cmp_initmgr();
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init cmp-mgr");
        return RET_FAIL;
    }
    cmp_set_globalalloc(&g_eng->data_alloc, tsk_get_tmpalloc(0));

    /* world manager */
    r = wld_initmgr();
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init world-mgr");
        return RET_FAIL;
    }

    /* scene manager */
    r = scn_initmgr();
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init scene-mgr");
        return RET_FAIL;
    }

    /* init lua */
    r = sct_init(&params->sct, BIT_CHECK(params->flags, ENG_FLAG_DEV) ? TRUE : FALSE);
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init script engine");
        return RET_FAIL;
    }

    /* web-server */
#if defined(_PROFILE_)
    r = prf_initmgr();
    if (IS_FAIL(r))	{
    	log_print(LOG_WARNING, "profiler manager init failed: service will not be available");
    	prf_releasemgr();
    }
#endif

    /* lod-scheme */
    r = lod_initmgr();
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: could not init lod-scheme");
        return RET_FAIL;
    }

    /* init basic resources */
    r = rs_init_resources();
    if (IS_FAIL(r)) {
        err_print(__FILE__, __LINE__, "engine init failed: coult not init res-mgr resources");
        return RET_FAIL;
    }

    /* switch back to normal data allocator */
    rs_set_dataalloc(&g_eng->data_alloc);

    /* enable background-loading if res-mgr is prepared for (see above rs_initmgr) */
    if (gfx_check_feature(GFX_FEATURE_THREADED_CREATES))
        rs_add_flags(RS_FLAG_BGLOADING);
    log_print(LOG_TEXT, "init ok: ready.");

    /* init world vars */
    eng_world_regvars();

    /* engine specific console commnads */
    con_register_cmd("showfps", eng_console_showfps, NULL, "showfps [1*/0]");
    con_register_cmd("showft", eng_console_showft, NULL, "showft [1*/0]");
    con_register_cmd("showgraph", eng_console_showgraph, NULL, "showgraph [ft][fps][drawcalls]");
    con_register_cmd("lockfps", eng_console_lockfps, NULL, "lockfps [fps]");

    /* execute console commands - should be the final stage if initialization */
    if (BIT_CHECK(params->flags, ENG_FLAG_CONSOLE))	{
		for (uint i = 0; i < params->console_cmds_cnt; i++)	{
			con_exec(params->console_cmds + i*128);
		}
    }

    A_LOAD(tmp_alloc);
    return RET_OK;
}