fix race when initializing context in lokinet main.

when we configure but fail to start up, we can hit a case when we
have a context that is configured but not setup or running. when we
try to sigterm/sigint we get stuck and cannot exit as the
llarp::Context shared_ptr global is nullptr but dangles elsewhere.

we make it so that we fufill a promose if we fully configure and setup
successfully right before running the event loop main for it. this
makes it so we bail if setup was not completed and exit our process.
pull/2119/head
Jeff Becker 1 year ago
parent e3e9b16ddf
commit eca944c427
No known key found for this signature in database
GPG Key ID: 025C02EE3A092F2D

@ -1,4 +1,5 @@
#include <chrono>
#include <exception>
#include <llarp/config/config.hpp> // for ensure_config
#include <llarp/constants/version.hpp>
#include <llarp.hpp>
@ -7,6 +8,9 @@
#include <llarp/util/fs.hpp>
#include <llarp/util/str.hpp>
#include <llarp/router/abstractrouter.hpp>
#include <memory>
#ifdef _WIN32
#include <llarp/win32/service_manager.hpp>
#include <dbghelp.h>
@ -62,7 +66,10 @@ namespace
void
handle_signal(int sig);
static void
run_main_context(std::optional<fs::path> confFile, const llarp::RuntimeOptions opts);
run_main_context(
std::optional<fs::path> confFile,
const llarp::RuntimeOptions opts,
std::promise<std::shared_ptr<llarp::Context>>& startup);
// variable declarations
static auto logcat = llarp::log::Cat("main");
@ -499,7 +506,20 @@ namespace
SetUnhandledExceptionFilter(&GenerateDump);
#endif
std::thread main_thread{[configFile, opts] { run_main_context(configFile, opts); }};
std::promise<std::shared_ptr<llarp::Context>> startup;
std::thread main_thread{
[configFile, opts, &startup] { run_main_context(configFile, opts, startup); }};
try
{
auto ftr = startup.get_future();
ctx = ftr.get();
}
catch (std::exception& ex)
{
oxen::log::error(logcat, "startup fail: {}", ex.what());
return 1;
}
auto ftr = exit_code.get_future();
do
@ -567,7 +587,10 @@ namespace
// this sets up, configures and runs the main context
static void
run_main_context(std::optional<fs::path> confFile, const llarp::RuntimeOptions opts)
run_main_context(
std::optional<fs::path> confFile,
const llarp::RuntimeOptions opts,
std::promise<std::shared_ptr<llarp::Context>>& startup)
{
llarp::LogInfo(fmt::format("starting up {} {}", llarp::VERSION_FULL, llarp::RELEASE_MOTTO));
try
@ -586,14 +609,15 @@ namespace
{
llarp::LogError("failed to parse configuration");
exit_code.set_value(1);
startup.set_value(nullptr);
return;
}
// change cwd to dataDir to support relative paths in config
fs::current_path(conf->router.m_dataDir);
ctx = std::make_shared<llarp::Context>();
ctx->Configure(std::move(conf));
auto _ctx = std::make_shared<llarp::Context>();
_ctx->Configure(std::move(conf));
signal(SIGINT, handle_signal);
signal(SIGTERM, handle_signal);
@ -605,23 +629,23 @@ namespace
try
{
ctx->Setup(opts);
_ctx->Setup(opts);
}
catch (llarp::util::bind_socket_error& ex)
{
llarp::LogError(fmt::format("{}, is lokinet already running? 🤔", ex.what()));
exit_code.set_value(1);
startup.set_exception(std::current_exception());
return;
}
catch (std::exception& ex)
{
llarp::LogError(fmt::format("failed to start up lokinet: {}", ex.what()));
exit_code.set_value(1);
startup.set_exception(std::current_exception());
return;
}
llarp::util::SetThreadName("llarp-mainloop");
auto result = ctx->Run(opts);
startup.set_value(_ctx);
auto result = _ctx->Run(opts);
exit_code.set_value(result);
}
catch (std::exception& e)

@ -185,7 +185,7 @@ namespace llarp
void
Context::SigINT()
{
if (router)
if (router and router->IsRunning())
{
llarp::log::debug(logcat, "Handling SIGINT");
/// async stop router on sigint

Loading…
Cancel
Save