Catching Ctrl+C signal throws exception "Job manager has been shut down"
Asked Answered
D

2

7

I'm trying to add support for signals (especially for Ctrl+C). My Tool is written in Java and I would like to perform cleanup when Ctrl+C is caught. My main file is Application and there is the following peace of code:

if (ArgDefinitions.getInstance().hasOption(ArgNames.EXECUTE)) {
    performShutdownHooks(); 
    preformRun();
}

The Application parses the user's options and runs the proper method. So when the user uses the execute option and clicks Ctrl+C, I would like the program to stop and clean the area. I added the performShutdownHooks method in order to handle the signal and it looks as follows:

private void performShutdownHooks() {
    Runtime.getRuntime().addShutdownHook(new Thread() {
        @Override
        public void run() {
            performCleanup();
        }
    });
}

It does what I want - if I run the tool and kill it while it runs, it does the cleanup (it runs a special command in the background). The problem comes up when I don't stop it. I get the following exception:

Exception in thread "Thread-2" java.lang.IllegalStateException: Job manager has been shut down.
        at org.eclipse.core.internal.jobs.JobManager.schedule(JobManager.java:1104)
        at org.eclipse.core.internal.jobs.InternalJob.schedule(InternalJob.java:427)
        at org.eclipse.core.runtime.jobs.Job.schedule(Job.java:436)
        at glichautil.CommandExecutor.runCommandInBackground(CommandExecutor.java:134)
        at glicha.core.Application.performCleanup(Application.java:869)
        at glicha.core.Application.access$0(Application.java:838)
        at glicha.core.Application$1.run(Application.java:985)
        

I think that the performShutdownHooks runs at the end, even though I didn't try to kill it. Maybe something else kills it but it shouldn't because if I'll comment out the method call performShutdownHooks(), it works regular (without throwing any exceptions). That makes me believe that, for some reason, the method performShutdownHooks is being run even though I didn't press Ctrl+C. Is there something I need to add to the performShutdownHooks method in order to solve it? Maybe I missed something about addShutdownHook? If this is the right explanation of the issue, then I think that if I could somehow unmake it run at the end, then it would solve the problem. It could be also possible that some other threads that being used in the code are being kill and for some reason execute that method.

EDIT: I think that I have manged to understand why it works like this. Before entering my ShutdownHooks method, it prints:

Job found still running after platform shutdown.
Jobs should be canceled by the plugin that scheduled them during shutdown: glicha.testmanager.HandleParallelJobs.

I guess, this what invokes ShutdownHooks. The problem is, I don't have an idea how to solve it. I read from the docs:

The Java virtual machine shuts down in response to two kinds of events:

  • The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or

  • The virtual machine is terminated in response to a user interrupt, such as typing Ctrl+C, or a system-wide event, such as user logoff or system shutdown.

So I guess, that when the plugin shuts down, it invokes ShutdownHooks (correct me if I'm wrong). The issue is that I don't understand how I can separate between those two possibilities. I would like to catch only the signals and perform cleanup but I don't want to do it if one of the the VM shutsdown. Any ideas on how I should approach this issue?

Delorisdelorme answered 4/6, 2019 at 23:5 Comment(5)
I'm facing the similar problem. Have you solved it?Antineutron
Hi @kickstart, Please see my edit.Delorisdelorme
What does your performCleanup method actually do? What is this 'glicha' thing that is causing the shutdown, is it your code or some 3rd party framework?Vierra
@Vierra Hi, thank you for the reply. Glicha is the name of the tool. performClenup stops all running jobs. Schedule is a 3rd part framework (Maybe even built-in in Java).Delorisdelorme
Incoherent code snippets are not particularly helpful. Please update your question, transforming it into an MCVE. I need something I can compile and run in order to reproduce your problem. Your extensive prose is nice but does not help me much there. You cannot expect anyone to recreate your problem from textual information only. Specifically I don't understand at all why you only want to perform a clean-up if Ctrl-C is pressed and not if the application exits in another way. Why not just code defensively and handle exceptions in the shutdown hook?Mindimindless
V
0

One of the common issues with a shutdown hook is that there is no guaranteed order of shuting down things. I assume in your case the Schedule framework might already have a shutdown hook on its own, which already performs a cleanup (stopping the tasks).

The javadoc related to shutdown hooks explains somewhat that you can not rely on the existance of other resources as they might have already been shutdown.

Now when you try to do that in your Shutdown hook, you might receive above mentioned error, depending on the execution order of the shutdown hook`s.


All that isn`t really what you asked for, but I guess that you might not have a problem at all. I'd rather have a discussion about the following things

  • What is the reason you want to have a shutdown hook in the first place?
  • Why do (feel that) you need to stop the running jobs on your own?

You might want to add the code you run when doing the cleanup to your question. According to the information I have you might want to shutdown something that has already been shutdown.


If you still want to do some Singal interception, there actually is a way, but I wouldn't recommend it. According to this link, https://www.javaspecialists.eu/archive/Issue043.html, you could use the Signal class of the sun.misc.* package.

The sun.misc package only contains unofficial API`s that might be removed without further notice at any time. There seems to be no official API which supports your use case (at least to my knowledge).

Vierra answered 8/6, 2019 at 16:52 Comment(0)
B
0

You can override the SecurityManager checkExit(int status) method - this works if System.exit(status) is called anywhere explicitly - however, it doesn't set the status when the application exits "normally" (no active threads), or an error kills the VM.

System.setSecurityManager(new ExitMonitorSecurityManager());
Runtime.getRuntime().addShutdownHook(new Thread(new MyShutdownHook()));

private static class ExitMonitorSecurityManager extends SecurityManager {

        @Override
        public void checkPermission(Permission perm) {
            //Something;
        }

        @Override
        public void checkPermission(Permission perm, Object context) {
            //Something
        }

        @Override
        public void checkExit(int status) {
            System.out.println("Setting exit value via security manager...");
            MyShutdownHook.EXIT_STATUS = status;
        }
    }

    private static class MyShutdownHook implements Runnable {

        public static Integer EXIT_STATUS;

        public void run() {

            System.out.println("In MyShutdownHook - exit status is " + EXIT_STATUS);
        }
    }
Barrage answered 14/6, 2019 at 17:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.