void * Thread() { log_register_thread("MapThread"); DSTACK(__FUNCTION_NAME); BEGIN_DEBUG_EXCEPTION_HANDLER ThreadStarted(); porting::setThreadName("Map"); porting::setThreadPriority(15); auto time = porting::getTimeMs(); while(!StopRequested()) { auto time_now = porting::getTimeMs(); try { if (!m_server->AsyncRunMapStep((time_now - time)/1000.0f)) std::this_thread::sleep_for(std::chrono::milliseconds(100)); else std::this_thread::sleep_for(std::chrono::milliseconds(10)); #ifdef NDEBUG } catch (BaseException &e) { errorstream<<"MapThread: exception: "<<e.what()<<std::endl; } catch(std::exception &e) { errorstream<<"MapThread: exception: "<<e.what()<<std::endl; } catch (...) { errorstream<<"MapThread: Ooops..."<<std::endl; #else } catch (int) { //nothing #endif } time = time_now; } END_DEBUG_EXCEPTION_HANDLER(errorstream) return nullptr; }
void * MeshUpdateThread::Thread() { ThreadStarted(); log_register_thread("MeshUpdateThread"); DSTACK(__FUNCTION_NAME); BEGIN_DEBUG_EXCEPTION_HANDLER porting::setThreadName("MeshUpdateThread"); while(!StopRequested()) { QueuedMeshUpdate *q = m_queue_in.pop(); if(q == NULL) { sleep_ms(3); continue; } ScopeProfiler sp(g_profiler, "Client: Mesh making"); MapBlockMesh *mesh_new = new MapBlockMesh(q->data, m_camera_offset); if(mesh_new->getMesh()->getMeshBufferCount() == 0) { delete mesh_new; mesh_new = NULL; } MeshUpdateResult r; r.p = q->p; r.mesh = mesh_new; r.ack_block_to_server = q->ack_block_to_server; m_queue_out.push_back(r); delete q; } END_DEBUG_EXCEPTION_HANDLER(errorstream) return NULL; }
void *EmergeThread::Thread() { ThreadStarted(); log_register_thread("EmergeThread" + itos(id)); DSTACK(__FUNCTION_NAME); BEGIN_DEBUG_EXCEPTION_HANDLER v3s16 last_tried_pos(-32768,-32768,-32768); // For error output v3s16 p; u8 flags = 0; map = (ServerMap *)&(m_server->m_env->getMap()); emerge = m_server->m_emerge; mapgen = emerge->mapgen[id]; enable_mapgen_debug_info = emerge->mapgen_debug_info; porting::setThreadName("EmergeThread"); while (!StopRequested()) try { if (!popBlockEmerge(&p, &flags)) { qevent.wait(); continue; } last_tried_pos = p; if (blockpos_over_limit(p)) continue; bool allow_generate = flags & BLOCK_EMERGE_ALLOWGEN; EMERGE_DBG_OUT("p=" PP(p) " allow_generate=" << allow_generate); /* Try to fetch block from memory or disk. If not found and asked to generate, initialize generator. */ BlockMakeData data; MapBlock *block = NULL; std::map<v3s16, MapBlock *> modified_blocks; if (getBlockOrStartGen(p, &block, &data, allow_generate) && mapgen) { { ScopeProfiler sp(g_profiler, "EmergeThread: Mapgen::makeChunk", SPT_AVG); TimeTaker t("mapgen::make_block()"); mapgen->makeChunk(&data); if (enable_mapgen_debug_info == false) t.stop(true); // Hide output } { //envlock: usually 0ms, but can take either 30 or 400ms to acquire JMutexAutoLock envlock(m_server->m_env_mutex); ScopeProfiler sp(g_profiler, "EmergeThread: after " "Mapgen::makeChunk (envlock)", SPT_AVG); map->finishBlockMake(&data, modified_blocks); block = map->getBlockNoCreateNoEx(p); if (block) { /* Do some post-generate stuff */ v3s16 minp = data.blockpos_min * MAP_BLOCKSIZE; v3s16 maxp = data.blockpos_max * MAP_BLOCKSIZE + v3s16(1,1,1) * (MAP_BLOCKSIZE - 1); // Ignore map edit events, they will not need to be sent // to anybody because the block hasn't been sent to anybody MapEditEventAreaIgnorer ign(&m_server->m_ignore_map_edit_events_area, VoxelArea(minp, maxp)); try { // takes about 90ms with -O1 on an e3-1230v2 m_server->getScriptIface()->environment_OnGenerated( minp, maxp, emerge->getBlockSeed(minp)); } catch(LuaError &e) { m_server->setAsyncFatalError(e.what()); } EMERGE_DBG_OUT("ended up with: " << analyze_block(block)); m_server->m_env->activateBlock(block, 0); } } } /* Set sent status of modified blocks on clients */ // Add the originally fetched block to the modified list if (block) modified_blocks[p] = block; if (modified_blocks.size() > 0) { m_server->SetBlocksNotSent(modified_blocks); } } catch (VersionMismatchException &e) { std::ostringstream err; err << "World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl; err << "----"<<std::endl; err << "\""<<e.what()<<"\""<<std::endl; err << "See debug.txt."<<std::endl; err << "World probably saved by a newer version of Minetest."<<std::endl; m_server->setAsyncFatalError(err.str()); } catch (SerializationError &e) { std::ostringstream err; err << "Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl; err << "----"<<std::endl; err << "\""<<e.what()<<"\""<<std::endl; err << "See debug.txt."<<std::endl; err << "You can ignore this using [ignore_world_load_errors = true]."<<std::endl; m_server->setAsyncFatalError(err.str()); } END_DEBUG_EXCEPTION_HANDLER(errorstream) log_deregister_thread(); return NULL; }
void* AsyncWorkerThread::Thread() { ThreadStarted(); // Register thread for error logging char number[21]; snprintf(number, sizeof(number), "%u", threadnum); log_register_thread(std::string("AsyncWorkerThread_") + number); porting::setThreadName((std::string("AsyncWorkTh_") + number).c_str()); lua_State *L = getStack(); std::string script = getServer()->getBuiltinLuaPath() + DIR_DELIM + "init.lua"; if (!loadScript(script)) { errorstream << "AsyncWorkerThread execution of async base environment failed!" << std::endl; abort(); } lua_getglobal(L, "core"); if (lua_isnil(L, -1)) { errorstream << "Unable to find core within async environment!"; abort(); } // Main loop while (!StopRequested()) { // Wait for job LuaJobInfo toProcess = jobDispatcher->getJob(); if (toProcess.valid == false || StopRequested()) { continue; } lua_getfield(L, -1, "job_processor"); if (lua_isnil(L, -1)) { errorstream << "Unable to get async job processor!" << std::endl; abort(); } luaL_checktype(L, -1, LUA_TFUNCTION); // Call it lua_pushlstring(L, toProcess.serializedFunction.data(), toProcess.serializedFunction.size()); lua_pushlstring(L, toProcess.serializedParams.data(), toProcess.serializedParams.size()); int result = lua_pcall(L, 2, 1, m_errorhandler); if (result) { PCALL_RES(result); toProcess.serializedResult = ""; } else { // Fetch result size_t length; const char *retval = lua_tolstring(L, -1, &length); toProcess.serializedResult = std::string(retval, length); } lua_pop(L, 1); // Pop retval // Put job result jobDispatcher->putJobResult(toProcess); } lua_pop(L, 1); // Pop core log_deregister_thread(); return 0; }
void* AsyncWorkerThread::worker_thread_main() { //register thread for error logging char number[21]; snprintf(number,sizeof(number),"%d",m_threadnum); log_register_thread(std::string("AsyncWorkerThread_") + number); porting::setThreadName( std::string(std::string("AsyncWorkTh_") + number).c_str()); /** prepare job lua environment **/ lua_newtable(m_LuaStack); lua_setglobal(m_LuaStack, "engine"); lua_getglobal(m_LuaStack, "engine"); int top = lua_gettop(m_LuaStack); lua_pushstring(m_LuaStack, DIR_DELIM); lua_setglobal(m_LuaStack, "DIR_DELIM"); lua_pushstring(m_LuaStack, std::string(porting::path_share + DIR_DELIM + "builtin").c_str()); lua_setglobal(m_LuaStack, "SCRIPTDIR"); m_JobDispatcher->PrepareEnvironment(m_LuaStack,top); std::string asyncscript = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM + "async_env.lua"; lua_pushcfunction(m_LuaStack, async_worker_ErrorHandler); m_luaerrorhandler = lua_gettop(m_LuaStack); if(!runScript(asyncscript)) { infostream << "AsyncWorkderThread::worker_thread_main execution of async base environment failed!" << std::endl; assert("no future with broken builtin async environment scripts" == 0); } /** main loop **/ while(!StopRequested()) { //wait for job LuaJobInfo toprocess = m_JobDispatcher->getJob(); if (toprocess.valid == false) { continue; } if (StopRequested()) { continue; } //first push error handler lua_pushcfunction(m_LuaStack, script_error_handler); int errorhandler = lua_gettop(m_LuaStack); lua_getglobal(m_LuaStack, "engine"); if(lua_isnil(m_LuaStack, -1)) assert("unable to find engine within async environment" == 0); lua_getfield(m_LuaStack, -1, "job_processor"); if(lua_isnil(m_LuaStack, -1)) assert("Someone managed to destroy a async worker engine!" == 0); luaL_checktype(m_LuaStack, -1, LUA_TFUNCTION); //call it lua_pushlstring(m_LuaStack, toprocess.serializedFunction.c_str(), toprocess.serializedFunction.length()); lua_pushlstring(m_LuaStack, toprocess.serializedParams.c_str(), toprocess.serializedParams.length()); if (StopRequested()) { continue; } if(lua_pcall(m_LuaStack, 2, 2, errorhandler)) { script_error(m_LuaStack); toprocess.serializedResult = "ERROR"; } else { //fetch result const char *retval = lua_tostring(m_LuaStack, -2); unsigned int lenght = lua_tointeger(m_LuaStack,-1); toprocess.serializedResult = std::string(retval,lenght); } if (StopRequested()) { continue; } //put job result m_JobDispatcher->putJobResult(toprocess); } log_deregister_thread(); return 0; }