Process is still running after SIGINT

I’m new here so, hello everyone!

I’ve got an issue regarding program exiting.
I’m working in Intellij and to exit/stop the program, I have to press the stop button twice (first press sends SIGINT, and second press sends SIGKILL). I don’t like that because I want to gracefully exit the program and it started to get annoying to press the button twice.
Firstly, I added a custom SIGINT handler:

    Signal.handle(new Signal("INT"), new SignalHandler() {
        public void handle(Signal sig) {
            System.out.println("SIGINT! Thread: "+Thread.currentThread().toString());
            Engine.sigint();
            System.exit(0);
        }
    });

Engine.sigint():

public static void sigint(){
    if(!GLFW_initialized) return;
    System.out.println("Engine | Processing SIGINT!");

    glfwSetWindowShouldClose(glfwWindow, true);

    System.out.println("Engine | SIGINT done!");
}

The rest of Engine (at least the GLFW and GL parts) are almost exactly the same as lwjgl.org/guide.
At the end of Engine.init() we have:

loop(); 
end();

Inside Engine.loop():

while(!glfwWindowShouldClose(glfwWindow)){
...
}

Engine.end():

private static void end(){
    System.out.println("Stopped loop, destroying GLFW!");

    glfwFreeCallbacks(glfwWindow);
    glfwDestroyWindow(glfwWindow);

    glfwTerminate();
    glfwSetErrorCallback(null).free();
}

Now, after investigation:

  • When pressing the “X” on the window, the program exits, the SIGINT code is never ran (what is ok), and the program exists with code 0.
    Console:
Stopped loop, destroying GLFW!

Process finished with exit code 0
  • When I stop the program by pressing the stop button in Intellij (sending SIGINT), the SIGINT code runs, but the glfwWindowShouldClose flag isn’t set despite calling glfwSetWindowShouldClose(glfwWindow, true), thus continuing the loop and never exiting.
    Console:
SIGINT! Thread: Thread[SIGINT handler,9,system]
Engine | Processing SIGINT!
Engine | SIGINT done!

Issue conclusion (might not be right, this is what I’m thinking) / TL;DR:

  • glfwSetWindowShouldClose(window, true) doesn’t set the flag to true

I hope I didn’t misread the documentation or am missing something. The JavaDoc says exactly what I want to happen and that the method can be called from any thread.

Edit 1:
I’m working on Linux

I managed to fix this, wohoo.
Firstly I discovered that Signals (SIGINT, SIGTERM, SIGKILL…) are platform dependent and the java Signal Handler might be deprecated and that it’s bad practice.
The alternative is the Shutdown Hook so here is how I replaced the SignalHandler with a Shutdown Hook:
Main.main(…):

public static void main(String[] args){
    Runtime.getRuntime().addShutdownHook(new Thread(()->{
                System.out.println("Main shutdown hook!");
                Engine.shutdown();
                System.out.println("Main shutdown hook done!");
            }
    ));

    Engine.init(args);
}

Engine.shutdown():

public static void shutdown(){
    if(!GLFW_initialized) return;
    System.out.println("Engine | Processing shutdown request!");

    glfwSetWindowShouldClose(glfwWindow, true);

    System.out.println("Engine | Processed shutdown request!");
}

Now, this still wasn’t working but I noticed glfwSetWindowShouldClose(…) actually stops the loop but it fails to run the code after the main loop so I added a Thread.sleep(1000) after setting the shouldClose flag. It worked, but I was unnecessarily waiting too much, so I googled how to await a boolean (or a flag) to switch. Then I found Java: Wait a boolean to become true. I put in private static CountDownLatch shutdownLatch = new CountDownLatch(1) in Engine and put shutdownLatch.countDown() at the end of Engine.end() that is run after the main loop finishes (after the windowShouldClose flag is raised). Then I simply put shutdownLatch.await() in Engine.shutdown() after setting the windowShouldClose flag.

Final result:

Main.main(String[] args):

public static void main(String[] args){
    Runtime.getRuntime().addShutdownHook(new Thread(()->{
                System.out.println("Main shutdown hook!");
                Engine.shutdown();
                System.out.println("Main shutdown hook done!");
            }
    ));

    Engine.init(args);
}

Engine.init(String[] args):

static void init(String[] args){
    ...
    loop();
    end();
}

Engine.loop():

private static void loop(){
    while(!glfwWindowShouldClose(glfwWindow)){
        ...
    }
}

Engine.shutdownLatch:
private static CountDownLatch shutdownLatch = new CountDownLatch(1);

Engine.end():

private static void end(){
    System.out.println("Destroying GLFW!");

    glfwFreeCallbacks(glfwWindow);
    glfwDestroyWindow(glfwWindow);

    glfwTerminate();
    glfwSetErrorCallback(null).free();

    shutdownLatch.countDown();
}

Engine.shutdown():

public static void shutdown(){
    if(!GLFW_initialized) return;
    try{
        System.out.println("Engine | Processing shutdown request!");

        glfwSetWindowShouldClose(glfwWindow, true);

        shutdownLatch.await();

        System.out.println("Engine | Processed shutdown request!");

    } catch(InterruptedException e){
        e.printStackTrace();
    }
}

If you have any better suggestions, please suggest them. I don’t believe this is THE best way to handle stopping.

2 Likes