EmptyEpsilon icon indicating copy to clipboard operation
EmptyEpsilon copied to clipboard

headless/proxy servers ignore SIGINT, preventing termination with Ctrl+C

Open mhthies opened this issue 3 years ago • 1 comments
trafficstars

The latest version of EmptyEpsilon seems to ignore SIGTERM and SIGINT signals, which prevents "normal" graceful termination via Ctrl+C in the command line, especially when started in headless mode (headless or proxy server).

Currently, the only way of stopping a headless EE server is (hard) killing with SIGKILL (killall -9 EmptyEpsilon).

Only tested on Linux (Debian 11 and Archlinux).

mhthies avatar May 15 '22 10:05 mhthies

Guess this happened when we moved to SDL2. Not sure how to prevent/fix it. The headless version is a hacky piece of mess...

daid avatar May 16 '22 12:05 daid

I just finally upgraded to the current release and finally hit this.

If you've enabled the http server, which is likely for headless, you can stop the server with: curl --data "shutdownGame()" http://localhost:8080/exec.lua

jpwgarrison avatar Oct 19 '22 00:10 jpwgarrison

By default SDL2 converts SIGINT and SIGTERM to SDL_QUIT, and I'm not sure headless/proxy modes handle SDL_QUIT.

SDL_HINT_NO_SIGNAL_HANDLERS configures this, so if I edit SeriousProton/src/engine.cpp to override that:

diff --git a/src/engine.cpp b/src/engine.cpp
index d55dead..f093324 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -61,6 +61,7 @@ Engine::Engine()
     } 
 #endif // WIN32
 
+    SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1"); // Otherwise, SDL converts SIGINT to SDL_QUIT, which SP doesn't handle
     SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
     SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
     SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); // Have clicking on a window to get focus generate mouse events. For multimonitor support.

and rebuild, then SIGINT kills the headless server as expected.

oznogon avatar Jan 05 '23 23:01 oznogon

SeriousProton engine.cpp L109-146 contains an if/else that only runs the SDL event queue handling if there's a window (if (Window::all_windows.size() == 0) ... else while(running { SDL_Event event; ...):

void Engine::runMainLoop()
{
    if (Window::all_windows.size() == 0)
    {
    ...
    }else{
        sp::audio::Source::startAudioSystem();
        sp::SystemStopwatch frame_timer;
#ifdef DEBUG
        sp::SystemTimer debug_output_timer;
        debug_output_timer.repeat(5);
#endif
        while(running)
        {
            // Handle events
            SDL_Event event;
            while (SDL_PollEvent(&event))
            {
                // we never get here if headless/proxy
                handleEvent(event);
            }

Filed daid/SeriousProton#217 to handle SDL_QUIT when there's no window.

Noticed this because there's no object count printing every 5 seconds on headless runs of a debug build, which would happen only if that branch of the if statement didn't run in headless mode. (daid/SeriousProton#218)

oznogon avatar Jan 21 '23 05:01 oznogon