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 while(getRun()) { /*// Wait for output queue to flush. // Allow 2 in queue, this makes less frametime jitter. // Umm actually, there is no much difference if(m_queue_out.size() >= 2) { sleep_ms(3); continue; }*/ QueuedMeshUpdate *q = m_queue_in.pop(); if(q == NULL) { sleep_ms(3); continue; } ScopeProfiler sp(g_profiler, "Client: Mesh making"); scene::SMesh *mesh_new = NULL; mesh_new = makeMapBlockMesh(q->data); MeshUpdateResult r; r.p = q->p; r.mesh = mesh_new; r.ack_block_to_server = q->ack_block_to_server; /*infostream<<"MeshUpdateThread: Processed " <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")" <<std::endl;*/ m_queue_out.push_back(r); delete q; } END_DEBUG_EXCEPTION_HANDLER(errorstream) return NULL; }
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; }