Example #1
0
	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;
	}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
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;
}