如何触发默认信号处理行为? [英] How do I trigger the default signal handling behavior?

查看:28
本文介绍了如何触发默认信号处理行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Signal.handle(new Signal("INT"), new SignalHandler() {@覆盖公共无效句柄(信号信号){//预处理//...//现在做默认行为SignalHandler.SIG_DFL.handle(信号);}});

但是,当我以 SIGINT 发送到此应用程序时,我得到一个 SEGV:

<预><代码>## Java 运行时环境检测到一个致命错误:## SIGSEGV (0xb) at pc=0x0000000000000000, pid=10261, tid=21507## JRE 版本:Java(TM) SE 运行时环境 (8.0_51-b16) (build 1.8.0_51-b16)# Java VM:Java HotSpot(TM) 64 位服务器 VM(25.51-b03 混合模式 bsd-amd64 压缩 oops)# 有问题的框架:# C 0x0000000000000000## 无法写入核心转储.核心转储已被禁用.要启用核心转储,请在再次启动 Java 之前尝试ulimit -c unlimited"## 包含更多信息的错误报告文件保存为:#/private/tmp/hs_err_pid10261.log## 如果您想提交错误报告,请访问:# http://bugreport.java.com/bugreport/crash.jsp# 崩溃发生在本地代码中的 Java 虚拟机之外.# 请参阅有问题的框架以了解在哪里报告错误.#中止陷阱:6

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

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

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

但我没有看到任何相关文件.

<小时>

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

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

A)

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

B)

Signal.handle(new Signal("INT"), new SignalHandler() {@覆盖公共无效句柄(信号信号){System.exit(signal.getNumber() + 128)}});

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

解决方案

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

SIGINTSIGTERMSIGHUP 的默认行为实际上不是 SignalHandler.SIG_DFL.相反,java.lang.Terminator注册一个SignalHandler,实际上只是调用Shutdown.exit():

SignalHandler sh = new SignalHandler() {公共无效句柄(信号 sig){Shutdown.exit(sig.getNumber() + 0200);}};

您可以通过调用 Signal.handle() 来捕获这个 SignalHandler(因为它返回旧的处理程序),或者您可以简单地定义自己的调用 System.exit() 会做同样的事情.

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

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

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.

解决方案

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.

这篇关于如何触发默认信号处理行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆