How do I trigger the default signal handling behavior?

南楼画角 提交于 2019-12-07 08:07:32

问题


In my Java application I want to capture SIGINTs, do some pre-processing, and then let the default behavior (process termination) run. I would think I could do something like this:

Signal.handle(new Signal("INT"), new SignalHandler() {
  @Override
  public void handle(Signal signal) {
    // preprocessing
    // ...

    // now do default behavior
    SignalHandler.SIG_DFL.handle(signal);
  }
});

However when I send at SIGINT to this application, I get a SEGV:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x0000000000000000, pid=10261, tid=21507
#
# JRE version: Java(TM) SE Runtime Environment (8.0_51-b16) (build 1.8.0_51-b16)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.51-b03 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# C  0x0000000000000000
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /private/tmp/hs_err_pid10261.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Abort trap: 6

It seems SignalHandler.SIG_DFL is not meant to be called directly (even from other signal handling code). So how can I manually trigger it?

Alternatively, how can I manually replicate the behavior of SIG_DFL? It appears to be equivalent to:

System.exit(signal.getNumber() + 128)

but I don't see any documentation to that effect.


Another way to phrase my question:

In practice* is there a difference between these two code blocks?

A)

Signal.handle(new Signal("INT"), SignalHandler.SIG_DFL);

B)

Signal.handle(new Signal("INT"), new SignalHandler() {
  @Override
  public void handle(Signal signal) {
    System.exit(signal.getNumber() + 128)
  }});

*I know undocumented behavior could change at any time, but it's unlikely that the JVM's exit behavior will change mid-version. An answer that simply details what happens now is acceptable, in practice.


回答1:


I think the key to the mystery here is that SIG_DFL is not the original handler for SIGINT.

The following code worked for me:

    Signal sigInt = new Signal("INT");

    // First register with SIG_DFL, just to get the old handler.
    final SignalHandler oldHandler = Signal.handle(sigInt, SignalHandler.SIG_DFL );

    // Now register the actual handler
    Signal.handle(sigInt, new SignalHandler(){

        @Override
        public void handle(Signal signal) {
            System.err.println("Sigint is being handled");
            oldHandler.handle(signal);
        }

    });

This does not cause the segmentation violation, and instead terminates the program as expected (after printing the sample text).




回答2:


Credit for originally noticing this goes to RealSkeptic, but I wanted to expand on it in an answer.

The default behavior for SIGINT, SIGTERM, and SIGHUP is not, in fact, SignalHandler.SIG_DFL. Instead, the java.lang.Terminator class registers a SignalHandler that does, in fact, simply call Shutdown.exit():

SignalHandler sh = new SignalHandler() {
    public void handle(Signal sig) {
      Shutdown.exit(sig.getNumber() + 0200);
    }
};

You can capture this SignalHandler by calling Signal.handle() (since it returns the old handler), or you can simply define your own handler that calls System.exit() which will do the same thing.

Note that Terminator's call to Shutdown.exit() is not exactly the same as System.exit(). The former is package-private, meaning you can't call it directly. If a security manager prevents you from calling System.exit(), you'll have to capture the original handler and reuse it.

Warning: this is undocumented behavior. It's unlikely but entirely possible that future releases of Java could change this behavior.




回答3:


Exiting with 128+signal number seems to be typical on Unix/Linux.

  • Are there any standard exit status codes in Linux?

For more evidence, see also:

  • http://journal.thobe.org/2013/02/jvms-and-kill-signals.html

Browsing the source code on OpenJDK suggests that the default behaviour is to allow the underlying C Runtime or OS default action to proceed.

In any case this is only typical behaviour, and as you point out is not documented. Exit codes are not standardized - generally there is a convention that zero means success, and nonzero failure, but even the first part is not always adhered to. Therefore it is for you to define your own exit codes.



来源:https://stackoverflow.com/questions/32190311/how-do-i-trigger-the-default-signal-handling-behavior

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!