Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shutdownhook not firing with native #465

Closed
rroller opened this issue Jun 12, 2018 · 6 comments
Closed

Shutdownhook not firing with native #465

rroller opened this issue Jun 12, 2018 · 6 comments
Assignees

Comments

@rroller
Copy link

rroller commented Jun 12, 2018

Firing off a CTRL C will not call the shutdown hook in the following example when running as native. It will fire when running with java jar

import java.util.concurrent.CountDownLatch;

public class Agent {
    private final CountDownLatch shutdownLatch;

    public Agent() {
        this.shutdownLatch = new CountDownLatch(1);
    }

    public void run() throws InterruptedException {
        System.out.println("Running");

        // Add a shutdown hook
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            shutdown();
        }));

        try {
            shutdownLatch.await();
            System.out.println("Latch released");
        } catch (InterruptedException e) {
            System.out.println("InterruptedException");
        }
    }

    public synchronized void shutdown() {
        System.out.println("Shutdown called");
        shutdownLatch.countDown();
    }

    public static void main(String[] args) throws Exception {
        new Agent().run();
    }
}
@christianwimmer
Copy link

christianwimmer commented Jun 14, 2018

This boils down to the question "how much should we do during the startup of an application"? We want to do as little as possible during startup, but registering a signal handler would require us to start a new thread that handles the signal and invokes the shutdown hooks.

In addition, we want to be embedding-friendly: we do not want to register any signal handlers unless they are registered explicitly by the user. So even registering a signal handler when the first shutdown hook is installed feels intrusive.

Luckily, you can easily register the signal handler explicitly yourself if you want:

import java.util.concurrent.CountDownLatch;

import sun.misc.Signal;

public class Agent {
    private final CountDownLatch shutdownLatch;

    public Agent() {
        this.shutdownLatch = new CountDownLatch(1);
    }

    public void run() throws InterruptedException {
        // Register a signal handler for Ctrl-C that runs the shutdown hooks
        Signal.handle(new Signal("INT"), sig -> System.exit(0));

        System.out.println("Running");

        // Add a shutdown hook
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            shutdown();
        }));

        try {
            shutdownLatch.await();
            System.out.println("Latch released");
        } catch (InterruptedException e) {
            System.out.println("InterruptedException");
        }
    }

    public synchronized void shutdown() {
        System.out.println("Shutdown called");
        shutdownLatch.countDown();
    }

    public static void main(String[] args) throws Exception {
        new Agent().run();
    }
}

Invoking System.exit on SIGINT gives you the behavior you want, because shutdown hooks run as part of System.exit.

Note that the output Latch released of your application is not guaranteed to happen. It depends on thread scheduling, i.e., the main thread needs to resume in the short time window between the countDown of the latch and the actual exit of the application. On the Java HotSpot VM, shutdown seems to be "slow enough" so that Latch released is printed reliably on my machine, while with a native image shutdown is faster and therefore it is not printed.

@rroller
Copy link
Author

rroller commented Jun 15, 2018

Thanks. This should work for my use-case.

@olpaw
Copy link
Member

olpaw commented Apr 28, 2020

#1592 (comment)

@paul-bjorkstrand
Copy link

@christianwimmer given this is a difference between running with normal java and with a native-image binary, do you think it would be worthwhile to put a note in https://github.com/oracle/graal/blob/master/substratevm/LIMITATIONS.md mentioning the bit about registering a signal handler, perhaps under Features That May Operate Differently in Native Image?

@olyagpl
Copy link
Member

olyagpl commented Oct 16, 2020

@paul-bjorkstrand, information on signal handlers is available on https://github.com/oracle/graal/blob/master/substratevm/Limitations.md#signal-handlers and https://github.com/oracle/graal/blob/master/substratevm/README.md#build-a-native-image pages.
Thanks!

@mageddo
Copy link

mageddo commented Mar 12, 2023

Quoting here (evicting one more click):

native-image now supports out of box signal handlers since 20.1, disabled by default, use --install-exit-handlers, see #1592 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants