System源码浅析- initializeSystemClass(setup)

前情提要

在前面已经介绍过 System与initializeSystemClass 在此不做过多解释,没有看到的希望去查看!
System源码浅析- initializeSystemClass(initProperties)
System源码浅析- initializeSystemClass(saveAndRemoveProperties)
System源码浅析- initializeSystemClass(setXXX0)
System源码浅析- initializeSystemClass(loadLibrary)
System源码浅析- initializeSystemClass(setup)
System源码浅析- initializeSystemClass( setJavaLangAccess)

setup

/*
    setup 和 teardown 的调用已经在关闭锁上同步了,所以这里不需要进一步同步
 */

static void setup() {
    if (handler != null) return;
    SignalHandler sh = new SignalHandler() {
        public void handle(Signal sig) {
            Shutdown.exit(sig.getNumber() + 0200);
        }
    };
    handler = sh;

    // When -Xrs is specified the user is responsible for
    // ensuring that shutdown hooks are run by calling
    // System.exit()
    try {
        Signal.handle(new Signal("INT"), sh);
    } catch (IllegalArgumentException e) {
    }
    try {
        Signal.handle(new Signal("TERM"), sh);
    } catch (IllegalArgumentException e) {
    }
}

exit

/* 
    由执行所有安全检查的 Runtime.exit 调用。也由系统提供的终止事件的处理程序调用,它应该传递一个非零状态代码。
 */
static void exit(int status) {
    boolean runMoreFinalizers = false;
    synchronized (lock) {
        if (status != 0) runFinalizersOnExit = false;
        switch (state) {
        case RUNNING:       /* Initiate shutdown */
            state = HOOKS;
            break;
        case HOOKS:         /* Stall and halt */
            break;
        case FINALIZERS:
            if (status != 0) {
                /* Halt immediately on nonzero status */
                halt(status);
            } else {
                /* Compatibility with old behavior:
                 * Run more finalizers and then halt
                 */
                runMoreFinalizers = runFinalizersOnExit;
            }
            break;
        }
    }
    if (runMoreFinalizers) {
        runAllFinalizers();
        halt(status);
    }
    synchronized (Shutdown.class) {
        /* 在类对象上同步,导致任何其他尝试启动关闭的线程无限期停止
         */
        sequence();
        halt(status);
    }
}

halt

/*
    暂停方法在暂停锁上同步,以避免损坏关闭时删除文件列表。它调用真正的本机停止方法。
 */
static void halt(int status) {
    synchronized (haltLock) {
        halt0(status);
    }
}

Java_java_lang_Shutdown_halt0

JNIEXPORT void JNICALL
Java_java_lang_Shutdown_halt0(JNIEnv *env, jclass ignored, jint code)
{
    JVM_Halt(code);
}

JVM_Halt

JVM_ENTRY_NO_ENV(void, JVM_Halt(jint code))
  before_exit(thread);
  vm_exit(code);
JVM_END

before_exit

// Note: before_exit() can be executed only once, if more than one threads
//       are trying to shutdown the VM at the same time, only one thread
//       can run before_exit() and all other threads must wait.
void before_exit(JavaThread * thread) {
  #define BEFORE_EXIT_NOT_RUN 0
  #define BEFORE_EXIT_RUNNING 1
  #define BEFORE_EXIT_DONE    2
  static jint volatile _before_exit_status = BEFORE_EXIT_NOT_RUN;

  // 注意:不要使用 Mutex 来保护整个 before_exit(),
  // 因为 JVMTI post_thread_end_event 和 post_vm_death_event 将运行本机代码。
  // CAS 或 OSMutex 可以正常工作,但是我们需要为 Safepoint 操作线程状态。
  // 这里我们使用 Monitor wait() 和 notify_all() 进行同步。
  { MutexLocker ml(BeforeExit_lock);
    switch (_before_exit_status) {
    case BEFORE_EXIT_NOT_RUN:
      _before_exit_status = BEFORE_EXIT_RUNNING;
      break;
    case BEFORE_EXIT_RUNNING:
      while (_before_exit_status == BEFORE_EXIT_RUNNING) {
        BeforeExit_lock->wait();
      }
      assert(_before_exit_status == BEFORE_EXIT_DONE, "invalid state");
      return;
    case BEFORE_EXIT_DONE:
      return;
    }
  }
   // 主要是关闭之前的一些准备工作。
  // 这个和 Win32 的 _onexit procs 之间的唯一区别是这个版本在任何线程被杀死之前被调用。
  ExitProc* current = exit_procs;
  while (current != NULL) {
    ExitProc* next = current->next();
    current->evaluate();
    delete current;
    current = next;
  }

  // 如果我们报告错误,则在退出时永远挂起。
  if (ShowMessageBoxOnError && is_error_reported()) {
    os::infinite_sleep();
  }

  // 终止观察者线程 - 必须在取消注册任何周期性任务之前
  if (PeriodicTask::num_tasks() > 0)
    WatcherThread::stop();

  // 收集的打印统计信息(分析...)
  if (Arguments::has_profile()) {
    FlatProfiler::disengage();
    FlatProfiler::print(10);
  }

  // 关闭 StatSampler 任务
  StatSampler::disengage();
  StatSampler::destroy();

  // 停止并发 GC 线程
  Universe::heap()->stop();

  // 打印 GC/heap 相关信息。
  if (PrintGCDetails) {
    Universe::print();
    AdaptiveSizePolicyOutput(0);
    if (Verbose) {
      ClassLoaderDataGraph::dump_on(gclog_or_tty);
    }
  }

  if (PrintBytecodeHistogram) {
    BytecodeHistogram::print();
  }

  if (JvmtiExport::should_post_thread_life()) {
    JvmtiExport::post_thread_end(thread);
  }


  EventThreadEnd event;
  if (event.should_commit()) {
    event.set_thread(JFR_THREAD_ID(thread));
    event.commit();
  }

  JFR_ONLY(Jfr::on_vm_shutdown();)

  // 即使还没有 JVMTI 环境也总是调用,因为环境可能会延迟附加,并且 JVMTI 必须跟踪 VM 执行的阶段
  JvmtiExport::post_vm_death();
  Threads::shutdown_vm_agents();

  // 终止信号线程 注意:我们不会等到它真正死掉。
  os::terminate_signal_thread();

  print_statistics();
  Universe::heap()->print_tracing_info();

  { MutexLocker ml(BeforeExit_lock);
    _before_exit_status = BEFORE_EXIT_DONE;
    BeforeExit_lock->notify_all();
  }

  if (VerifyStringTableAtExit) {
    int fail_cnt = 0;
    {
      MutexLocker ml(StringTable_lock);
      fail_cnt = StringTable::verify_and_compare_entries();
    }

    if (fail_cnt != 0) {
      tty->print_cr("ERROR: fail_cnt=%d", fail_cnt);
      guarantee(fail_cnt == 0, "unexpected StringTable verification failures");
    }
  }

  #undef BEFORE_EXIT_NOT_RUN
  #undef BEFORE_EXIT_RUNNING
  #undef BEFORE_EXIT_DONE
}

vm_exit

void vm_exit(int code) {
  Thread* thread = ThreadLocalStorage::is_initialized() ?
    ThreadLocalStorage::get_thread_slow() : NULL;
  if (thread == NULL) {
    // we have serious problems -- just exit
    vm_direct_exit(code);
  }

  if (VMThread::vm_thread() != NULL) {
    // 启动 VM_Exit 操作以将 VM 带到安全点并退出
    VM_Exit op(code);
    if (thread->is_Java_thread())
      ((JavaThread*)thread)->set_thread_state(_thread_in_vm);
    VMThread::execute(&op);
    // 永远不应该到达这里;但万一VM Thread有问题。
    vm_direct_exit(code);
  } else {
    // VM线程不见了,直接退出
    vm_direct_exit(code);
  }
  ShouldNotReachHere();
}

vm_direct_exit

void vm_direct_exit(int code) {
  notify_vm_shutdown();
  os::wait_for_keypress_at_exit();
  ::exit(code);
}

handle

public static synchronized SignalHandler handle(Signal var0, SignalHandler var1) throws IllegalArgumentException {
    long var2 = var1 instanceof NativeSignalHandler ? ((NativeSignalHandler)var1).getHandler() : 2L;
    long var4 = handle0(var0.number, var2);
    // SIGFPE SIGBREAK    JVM 已经使用过了
    if (var4 == -1L) {
        throw new IllegalArgumentException("Signal already used by VM or OS: " + var0);
    } else {
        signals.put(var0.number, var0);
        synchronized(handlers) {
            SignalHandler var7 = (SignalHandler)handlers.get(var0);
            handlers.remove(var0);
            if (var2 == 2L) {
                handlers.put(var0, var1);
            }

            if (var4 == 0L) {
                return SignalHandler.SIG_DFL;
            } else if (var4 == 1L) {
                return SignalHandler.SIG_IGN;
            } else {
                return (SignalHandler)(var4 == 2L ? var7 : new NativeSignalHandler(var4));
            }
        }
    }
}

handle0

private static native long handle0(int var0, long var1);

Java_sun_misc_Signal_handle0

Java_sun_misc_Signal_handle0(JNIEnv *env, jclass cls, jint sig, jlong handler)
{
    return ptr_to_jlong(JVM_RegisterSignal(sig, jlong_to_ptr(handler)));
}

JVM_RegisterSignal 这个不同平台会有不同的实现,我这里浅析windows。

JVM_ENTRY_NO_ENV(void*, JVM_RegisterSignal(jint sig, void* handler))
  // Copied from classic vm
  // signals_md.c       1.4 98/08/23
  void* newHandler = handler == (void *)2
                   ? os::user_handler()
                   : handler;
  switch (sig) {
   case SIGFPE:
     return (void *)-1; /* already used by VM */
   case SIGBREAK:
     if (!ReduceSignalUsage) return (void *)-1;

    /* 
    以下信号用于 Shutdown Hooks 支持。但是,如果设置了 ReduceSignalUsage (-Xrs),则必须通过 System.exit() 调用 Shutdown Hooks,Java 不允许使用这些信号,并且允许用户为这些信号设置自己的 _native_ handler 并调用 System.exit() 根据需要。 Terminator.setup() 在存在 -Xrs 时避免注册这些信号。 
    */
   case SHUTDOWN1_SIGNAL:
   case SHUTDOWN2_SIGNAL:
     if (ReduceSignalUsage) return (void*)-1;
  }

  void* oldHandler = os::signal(sig, newHandler);
  if (oldHandler == os::user_handler()) {
      return (void *)2;
  } else {
      return oldHandler;
  }
JVM_END

JVM中的信息标识

/*
 *实际信号值。将其他值与信号一起使用会产生 SIG_ERR 返回值。
 *
 * 注意: SIGINT 在用户按下 Ctrl-C 时产生
 *       SIGILL 未经测试。
 *       SIGFPE 似乎不起作用?
 *       SIGSEGV 没有捕捉到对 NULL 指针的写入(这会关闭您的应用程序;您能说“分段违规核心转储”吗?)。
 *       SIGTERM 究竟来自什么样的终止请求?
 *       SIGBREAK 确实是通过按 Ctrl-Break 产生的。
 *       SIGABRT 是通过调用 abort 产生的。
 */
#define    SIGINT    2  /* Interactive attention */
#define    SIGILL    4  /* Illegal instruction */
#define    SIGFPE    8  /* Floating point error */
#define    SIGSEGV       11 /* Segmentation violation */
#define    SIGTERM       15 /* Termination request */
#define SIGBREAK   21 /* Control-break */
#define    SIGABRT       22 /* Abnormal termination (abort) */

#define NSIG 23     /* maximum signal number + 1 */

os::signal

void* os::signal(int signal_number, void* handler) {
  if ((signal_number == SIGBREAK) && (!ReduceSignalUsage)) {
    void (*oldHandler)(int) = sigbreakHandler;
    sigbreakHandler = (void (*)(int)) handler;
    return (void*) oldHandler;
  } else {
    return (void*)::signal(signal_number, (void (*)(int))handler);
  }
}