发送 SIGTERM 时 VM_Exit 是如何传递给 VM Thread 的?谁来传递?

How is VM_Exit delivered to VM Thread when sending SIGTERM and who does the delivering?

我正在尝试了解 JVM 热点如何处理终止信号(例如 SIGTERM)。我发现 SIGTERM 信号配置设置为 at this pointUserHandler 看起来像(省略注释):

static void UserHandler(int sig, void *siginfo, void *context) {
  if (sig == SIGINT && Atomic::add(1, &sigint_count) > 1) {
    return;
  }
  if (sig == SIGINT && VMError::is_error_reported()) {
    os::die();
  }
  os::signal_notify(sig);
}

所以它所做的就是通知Signal Dispatcher并将接收到的信号编号设置为static volatile jint pending_signals[NSIG+1]

但在 SIGTERM 的情况下,实际的 exit(143) 是在 VM Thread 中完成的。带有 _exit_code = 143VM_Exit 任务以某种方式传递给 VM Thread

问题: 能否提示一下是谁生成了这个 VM_Exit 任务,之后又发给了 VM Thread?我特别关心 143 如何设置为 VM_Exit::_exit_code?

I 运行 gdb 下的 JVM HotSpot 主要有以下 class:

public class Main{
    public static void main(String args[]) throws Exception {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("Shutdown hook is called");
        }));
        Thread.sleep(1000000);
    }
}

并没有发现 Signal Dispatcher 正在发送 VM_Exit 任务。终止发生在 that statement:

JavaCalls::call_virtual(&result,
                        threadObj, thread_klass,
                        vmSymbols::exit_method_name(),
                        vmSymbols::void_method_signature(),
                        THREAD);

SIGTERMSIGINTSIGHUPjava.lang.TerminatorJava code 中处理。

async-profiler 的一个鲜为人知的特性是它可以分析任意本机函数并显示混合的 Java+本机堆栈。例如。如果你想拦截 JVM_Halt 并查看 Java 代码调用它,运行

$ java -agentpath:/path/to/libasyncProfiler.so=start,traces,threads,event=JVM_Halt Main

Started [JVM_Halt] profiling
^CShutdown hook is called
--- 1 events (100.00%), 1 sample
  [ 0] JVM_Halt
  [ 1] java.lang.Shutdown.halt0
  [ 2] java.lang.Shutdown.halt
  [ 3] java.lang.Shutdown.exit
  [ 4] java.lang.Terminator.handle
  [ 5] jdk.internal.misc.Signal.run
  [ 6] java.lang.Thread.run
  [ 7] [SIGINT handler tid=19080]