/************************************************************************************************* * 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; }
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); }
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(¶ms->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(¶ms->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; }