Saturday, October 10, 2009

How to know when Java Virtual Machine is shutting down

The question is: why would someone need to know such thing?

You already have the jdk's Runtime.getRuntime().addShutdownHook() method that adds your thread to be called when the jvm is shutting down. So why another way?

Well, I would have asked the same thing if I didn't experience an unusual situation.
(For the inpatient reader that wants to skip the story, you can jump directly to the answer)

I was working on a complex web aplication that was running in a jBoss/Tomcat container. We needed a clean server shutdown in order to release  the resources (connection pools, sockets, temporary files, etc). At a certain moment the team members noticed that the undeploy operation worked well while the majority of the shutdowns (but not all) were hanging at a certain point. The displayed reason was a strange exception raised from the AWT thread:

Exception in thread "AWT-Windows" java.lang.IllegalStateException: Shutdown in progress
at java.lang.Shutdown.add(Shutdown.java:81)
at java.lang.Runtime.addShutdownHook(Runtime.java:190)

We could not understand why the exception would come from the AWT as we were not using at all the AWT in our application... Or at least we didn't know it... However, who was calling the Runtime.addShutdownHook() and why was it driving to a jvm crash?

After digging around the problem I discovered that, indeed, we were using AWT, although indirectly, by using a reporting engine. And that reporting engine was using classes of AWT to do it's job. The reporting library that we were using was packaged as a Struts plugin. The plugin's contract is simple: Struts calls the  init() method at startup and the destroy()method at shutdown, on all the registered plugins. The plugin's control class was a singleton that was simply redirecting the destroy() calls to it's internal methods. Of course, after creating an instance of itself.
So what? you may say. This is the normal way to do such things.
Yes, only that, in this particular case, unless you used the reporting feature while working with the application, the reporting engine was not initialized until shutdown. So, at server's shutdown, Struts was calling destroy on all it's plugins and at his turn the reporting plugin, inside it's destroy() method, was calling ReportsInitializer.getInstance().shutdown(). And... Boom! JVM freeze.

Ok, but why? It's just a class instance that does something within itself! What might drive it to crash all the system?
Well, the nice part is just coming. So, we have a system shutdown and a Struts plugin called that is instantiating some class that uses some AWT elements inside. It does not look like something to be scared of... Only that there is a catch: when a class AWT is instantiated, the AWT Toolkit itself adds a ShutDownHook  to the  Runtime. I haven't yet dug inside to understand why. But, as java specs state, it is illegal to add a  ShutdownHook  if the JVM shutdown sequence has already started.
Some people consider that this behavior inside AWT is a bug, because AWT should check itself if the JVM is shutting down before attempting to add its own ShutdownHook.
Ok. now, we found the reason why all happened. What next? I evaluated three possible solutions:
- to add a generic thread exception handler and simply "swallow" this exception.
- to add a myself a ShutdownHook and set some flag on the reporting reporting plugin not to instantiate anymore the reporting initializer.
- to detect (inside the destroy method in the plugin) if the virtual machine is shutting down and skip calling the reporting initializer.

The solution I chose was the last, because the generic thread exception handler couldn't prevent the exception to happen, and for the second option, the order in which JVM calls the ShutdownHooks  is not guaranteed, so you'll never know if it will be called before or after the Struts's own ShutdownHook, making of the solution a non deterministic one.

So I made some research to see if I may possibly know at any time if the Java Virtual Machine is shutting down. I discovered that when java.lang.Runtime.exit(int status) is called, it forwards the call to a class named java.lang.Shutdown.exit(int status), that calls all the ShutdownHooks before calling the native halt() method. Inside this class there are fields describing the state of the system. Unfortunately the class is private package and there is no public method that returns the System's state. But luckily, in Java we have the blessed reflection. So, here comes the answer:


private boolean isSystemShuttingDown() {
  try {
    Field running = Class.forName("java.lang.Shutdown").getDeclaredField("RUNNING");
    Field state = Class.forName("java.lang.Shutdown").getDeclaredField("state");
    running.setAccessible(true);
    state.setAccessible(true);
    return state.getInt(null) > running.getInt(null);
  }
  catch (Exception ex) {
    ex.printStackTrace();
    return false;
  }
}

I would not advise anyone to use this on a daily basis unless he is exceptionally needing such a solution, primarily because:
- the java.lang.Shutdown class is a package private class in the JDK and it may be changed or removed in any upcoming release. Of course, for custom built projects, that usually run for a long time on a single jdk version this is not such a big issue.
- In public distributions there is a chance that the SecurityManager is set to forbid the access to jdk internals. But again, inside custom projects you can configure your own SecurityManager.

I hope that you enjoyed reading this post and I am waiting for your comments.

Greetings,
Dikran

P.S. Thanks to Alex Gorbatchev for his excellent SyntaxHighlighter.

1 comment :

  1. Thanks. After searching for 3 days with different search strings, was finally able to find something useful.
    Would be very interested if you have any more secure update on this too !!
    Thanks,
    Kapil

    ReplyDelete