如何触发默认信号处理行为?

dim*_*414 6 java unix signals

在我的 Java 应用程序中,我想捕获 SIGINT,进行一些预处理,然后让默认行为(进程终止)运行。我想我可以做这样的事情:

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

    // now do default behavior
    SignalHandler.SIG_DFL.handle(signal);
  }
});
Run Code Online (Sandbox Code Playgroud)

但是,当我发送SIGINT到此应用程序时,我收到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
Run Code Online (Sandbox Code Playgroud)

它似乎SignalHandler.SIG_DFL并不意味着直接调用(即使是从其他信号处理代码)。那么如何手动触发呢?

或者,我如何手动复制 的行为SIG_DFL?它似乎相当于:

System.exit(signal.getNumber() + 128)
Run Code Online (Sandbox Code Playgroud)

但我没有看到任何这方面的文件。


另一种表达我的问题的方式:

实际上*这两个代码块之间有区别吗?

A)

Signal.handle(new Signal("INT"), SignalHandler.SIG_DFL);
Run Code Online (Sandbox Code Playgroud)

二)

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

*我知道未记录的行为可能随时发生变化,但 JVM 的退出行为不太可能在中间版本中发生变化。在实践中,简单地详细说明现在发生的情况的答案是可以接受的。

dim*_*414 3

最初注意到这一点的功劳归功于RealSkeptic,但我想在答案中对其进行扩展。

SIGINT事实上, 、SIGTERM、 和的默认行为SIGHUP不是SignalHandler.SIG_DFL。相反,java.lang.Terminator该类注册一个SignalHandler简单的调用Shutdown.exit()

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

SignalHandler您可以通过调用来捕获它Signal.handle()(因为它返回旧的处理程序),或者您可以简单地定义自己的处理程序来调用System.exit()它将执行相同的操作。

请注意,Terminator的调用Shutdown.exit()并不完全是System.exit()。前者是包私有的,这意味着您不能直接调用它。如果安全管理器阻止您调用System.exit(),您将必须捕获原始处理程序并重用它。

警告:这是未记录的行为。Java 的未来版本不太可能但完全有可能改变这种行为。