Skip to content

Commit

Permalink
Fix local server startup and shutdown blocking the main thread
Browse files Browse the repository at this point in the history
Co-authored-by: sfan5 <sfan5@live.de>
  • Loading branch information
grorp and sfan5 committed Apr 5, 2024
1 parent b2982a6 commit fd8e021
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 10 deletions.
57 changes: 48 additions & 9 deletions src/client/game.cpp
Expand Up @@ -66,6 +66,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "shader.h"
#include "sky.h"
#include "threading/lambda.h"
#include "translation.h"
#include "util/basic_macros.h"
#include "util/directiontables.h"
Expand Down Expand Up @@ -1014,12 +1015,6 @@ Game::Game() :

Game::~Game()
{
delete client;
delete soundmaker;
sound_manager.reset();

delete server; // deleted first to stop all server threads

delete hud;
delete camera;
delete quicktune;
Expand Down Expand Up @@ -1268,6 +1263,28 @@ void Game::shutdown()
sleep_ms(100);
}
}

delete client;
delete soundmaker;
sound_manager.reset();

auto stop_thread = runInThread([=] {
delete server;
}, "ServerStop");

FpsControl fps_control;
fps_control.reset();

while (stop_thread->isRunning()) {
m_rendering_engine->run();
f32 dtime;
fps_control.limit(device, &dtime);
showOverlayMessage(N_("Shutting down..."), dtime, 0, false);
}

stop_thread->rethrow();

// to be continued in Game::~Game
}


Expand Down Expand Up @@ -1373,11 +1390,33 @@ bool Game::createSingleplayerServer(const std::string &map_dir,

server = new Server(map_dir, gamespec, simple_singleplayer_mode, bind_addr,
false, nullptr, error_message);
server->start();

copyServerClientCache();
auto start_thread = runInThread([=] {
server->start();
copyServerClientCache();
}, "ServerStart");

return true;
input->clear();
bool success = true;

FpsControl fps_control;
fps_control.reset();

while (start_thread->isRunning()) {
if (!m_rendering_engine->run() || input->cancelPressed())
success = false;
f32 dtime;
fps_control.limit(device, &dtime);

if (success)
showOverlayMessage(N_("Creating server..."), dtime, 5);
else
showOverlayMessage(N_("Shutting down..."), dtime, 0, false);
}

start_thread->rethrow();

return success;
}

void Game::copyServerClientCache()
Expand Down
1 change: 0 additions & 1 deletion src/debug.h
Expand Up @@ -19,7 +19,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#pragma once

#include <iostream>
#include <exception>
#include <cassert>
#include "gettime.h"
Expand Down
64 changes: 64 additions & 0 deletions src/threading/lambda.h
@@ -0,0 +1,64 @@
// Minetest
// SPDX-License-Identifier: LGPL-2.1-or-later

#pragma once

#include <exception>
#include <functional>
#include <memory>
#include "debug.h"
#include "threading/thread.h"

/**
* Class returned by `runInThread`.
*
* Provides the usual thread methods along with `rethrow()`.
*/
class LambdaThread : public Thread
{
friend std::unique_ptr<LambdaThread> runInThread(
const std::function<void()> &, const std::string &);
public:
/// Re-throw a caught exception, if any. Can only be called after thread exit.
void rethrow()
{
sanity_check(!isRunning());
if (m_exptr)
std::rethrow_exception(m_exptr);
}

private:
// hide methods
LambdaThread(const std::string &name="") : Thread(name) {}
using Thread::start;

std::function<void()> m_fn;
std::exception_ptr m_exptr;

void *run()
{
try {
m_fn();
} catch(...) {
m_exptr = std::current_exception();
}
return nullptr;
};
};

/**
* Run a lambda in a separate thread.
*
* Exceptions will be caught.
* @param fn function to run
* @param thread_name name for thread
* @return thread object of type `LambdaThread`
*/
std::unique_ptr<LambdaThread> runInThread(const std::function<void()> &fn,
const std::string &thread_name = "")
{
std::unique_ptr<LambdaThread> t(new LambdaThread(thread_name));
t->m_fn = fn;
t->start();
return t;
}
1 change: 1 addition & 0 deletions src/threading/thread.h
Expand Up @@ -59,6 +59,7 @@ class Thread {
Thread(const std::string &name="");
virtual ~Thread();
DISABLE_CLASS_COPY(Thread)
// Note: class cannot be moved since other references exist

/*
* Begins execution of a new thread at the pure virtual method Thread::run().
Expand Down

0 comments on commit fd8e021

Please sign in to comment.