add signal handlers; closes #564

This commit is contained in:
Martin Michelsen
2024-10-21 22:38:58 -07:00
parent 086b2d411a
commit a9a15600b2
6 changed files with 114 additions and 1 deletions
+7
View File
@@ -46,6 +46,7 @@
#include "Server.hh"
#include "ServerShell.hh"
#include "ServerState.hh"
#include "SignalWatcher.hh"
#include "StaticGameData.hh"
#include "Text.hh"
#include "TextIndex.hh"
@@ -2727,6 +2728,7 @@ Action a_run_server_replay_log(
shared_ptr<ServerShell> shell;
shared_ptr<ReplaySession> replay_session;
shared_ptr<SignalWatcher> signal_watcher;
if (is_replay) {
config_log.info("Starting proxy server");
state->proxy_server = make_shared<ProxyServer>(base, state);
@@ -2842,6 +2844,11 @@ Action a_run_server_replay_log(
state->http_server->listen(netloc.first, netloc.second);
}
}
#ifndef PHOSG_WINDOWS
config_log.info("Enabling signal watcher");
signal_watcher = make_shared<SignalWatcher>(state);
#endif
}
if (!state->username.empty()) {
+11 -1
View File
@@ -232,6 +232,7 @@ CommandDefinition c_reload(
teams - reindex all BB teams\n\
text-index - reload in-game text\n\
word-select - regenerate the Word Select translation table\n\
all - do all of the above\n\
Reloading will not affect items that are in use; for example, if an Episode\n\
3 battle is in progress, it will continue to use the previous map and card\n\
definitions. Similarly, BB clients are not forced to disconnect or reload\n\
@@ -242,7 +243,16 @@ CommandDefinition c_reload(
+[](CommandArgs& args) {
auto types = phosg::split(args.args, ' ');
for (const auto& type : types) {
if (type == "bb-keys") {
if (type == "all") {
args.s->forward_to_event_thread([s = args.s]() {
try {
s->load_all();
} catch (const exception& e) {
fprintf(stderr, "FAILED: %s\n", e.what());
fprintf(stderr, "Some configuration may have been reloaded. Fix the underlying issue and try again.\n");
}
});
} else if (type == "bb-keys") {
args.s->load_bb_private_keys(true);
} else if (type == "accounts") {
args.s->load_accounts(true);
+63
View File
@@ -0,0 +1,63 @@
#include "SignalWatcher.hh"
#include <event2/event.h>
#include <stdio.h>
#include <string.h>
#include <phosg/Random.hh>
#include <phosg/Strings.hh>
#include "ReceiveCommands.hh"
#include "SendCommands.hh"
#include "ServerState.hh"
#include "StaticGameData.hh"
using namespace std;
SignalWatcher::SignalWatcher(shared_ptr<ServerState> state)
: log("[SignalWatcher] "),
state(state),
sigusr1_event(evsignal_new(this->state->base.get(), SIGUSR1, &SignalWatcher::dispatch_on_signal, this), event_free),
sigusr2_event(evsignal_new(this->state->base.get(), SIGUSR2, &SignalWatcher::dispatch_on_signal, this), event_free) {
event_add(this->sigusr1_event.get(), nullptr);
event_add(this->sigusr2_event.get(), nullptr);
}
void SignalWatcher::dispatch_on_signal(evutil_socket_t signal, short what, void* ctx) {
if (what != EV_SIGNAL) {
throw logic_error("dispatch_on_signal called for non-signal event");
}
reinterpret_cast<SignalWatcher*>(ctx)->on_signal(signal);
}
void SignalWatcher::on_signal(int signum) {
switch (signum) {
case SIGUSR1:
this->log.info("Received SIGUSR1; reloading config.json");
this->state->forward_to_event_thread([s = this->state]() {
try {
s->load_config_early();
s->load_config_late();
fprintf(stderr, "Configuration update complete\n");
} catch (const exception& e) {
fprintf(stderr, "FAILED: %s\n", e.what());
fprintf(stderr, "Some configuration may have been reloaded. Fix the underlying issue and try again.\n");
}
});
break;
case SIGUSR2:
this->log.info("Received SIGUSR2; reloading config.json and all dependencies");
this->state->forward_to_event_thread([s = this->state]() {
try {
s->load_all();
fprintf(stderr, "Configuration update complete\n");
} catch (const exception& e) {
fprintf(stderr, "FAILED: %s\n", e.what());
fprintf(stderr, "Some configuration may have been reloaded. Fix the underlying issue and try again.\n");
}
});
break;
default:
this->log.warning("Unknown signal received: %d", signum);
}
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <memory>
#include <string>
#include <thread>
#include <event2/event.h>
#include "ServerState.hh"
class SignalWatcher : public std::enable_shared_from_this<SignalWatcher> {
public:
explicit SignalWatcher(std::shared_ptr<ServerState> state);
SignalWatcher(const SignalWatcher&) = delete;
SignalWatcher(SignalWatcher&&) = delete;
SignalWatcher& operator=(const SignalWatcher&) = delete;
SignalWatcher& operator=(SignalWatcher&&) = delete;
~SignalWatcher() = default;
protected:
phosg::PrefixedLogger log;
std::shared_ptr<ServerState> state;
std::unique_ptr<struct event, void (*)(struct event*)> sigusr1_event;
std::unique_ptr<struct event, void (*)(struct event*)> sigusr2_event;
static void dispatch_on_signal(evutil_socket_t, short, void* ctx);
void on_signal(int signum);
};