在java 中調用Signal的方法handle可以去注冊一個信號的處理函數,方法的如下:
public static synchronized SignalHandler handle(Signal sig,
SignalHandler handler) {
....
}
比如常用的addShutdownHook鉤子函數裡,就是在 Terminator.setup();的時候將Shutdown.exit 的函數注冊到了信號SHUTDOWN1_SIGNAL(SIGHUP),SHUTDOWN2_SIGNAL(SIGINT),SHUTDOWN3_SIGNAL(SIGTERM)中,當線程接受到信號時,通過調用函數Shutdown.exit的調用hook中的鉤子函數。
在筆者的文章(java 中關於信號的處理在linux下的實現)也提到jdk如何處理信號的,那麼調用handle裡是不是直接就把這個方法注冊進了信號處理呢?
請注意,handle是一個java的方法,而注冊信號函數是c的代碼,顯然不能簡單的將java的方法直接提供給c調用,其次信號處理函數是在內核態中處理,安全性和執行時間的長短將影響到內核的信號調度。
先看java源碼,如下面所示
public static synchronized SignalHandler handle(Signal sig,
SignalHandler handler)
throws IllegalArgumentException {
long newH = (handler instanceof NativeSignalHandler) ?
((NativeSignalHandler)handler).getHandler() : 2;
long oldH = handle0(sig.number, newH);
if (oldH == -1) {
throw new IllegalArgumentException
("Signal already used by VM: " + sig);
}
signals.put(new Integer(sig.number), sig);
synchronized (handlers) {
SignalHandler oldHandler = (SignalHandler)handlers.get(sig);
handlers.remove(sig);
if (newH == 2) {
handlers.put(sig, handler);
}
if (oldH == 0) {
return SignalHandler.SIG_DFL;
} else if (oldH == 1) {
return SignalHandler.SIG_IGN;
} else if (oldH == 2) {
return oldHandler;
} else {
return new NativeSignalHandler(oldH);
}
}
}
在native code hand0裡並沒有將handle的方法傳進去,只是傳了一個整型值。
在c++代碼中hand0裡調用了函數 JVM_RegisterSignal,具體來看一下這個函數的實現
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) {
/* The following are already used by the VM. */
case INTERRUPT_SIGNAL:
case SIGFPE:
case SIGILL:
case SIGSEGV:
/* The following signal is used by the VM to dump thread stacks unless
ReduceSignalUsage is set, in which case the user is allowed to set
his own _native_ handler for this signal; thus, in either case,
we do not allow JVM_RegisterSignal to change the handler. */
case BREAK_SIGNAL:
return (void *)-1;
/* The following signals are used for Shutdown Hooks support. However, if
ReduceSignalUsage (-Xrs) is set, Shutdown Hooks must be invoked via
System.exit(), Java is not allowed to use these signals, and the the
user is allowed to set his own _native_ handler for these signals and
invoke System.exit() as needed. Terminator.setup() is avoiding
registration of these signals when -Xrs is present.
- If the HUP signal is ignored (from the nohup) command, then Java
is not allowed to use this signal.
*/
case SHUTDOWN1_SIGNAL:
case SHUTDOWN2_SIGNAL:
case SHUTDOWN3_SIGNAL:
if (ReduceSignalUsage) return (void*)-1;
if (os::Linux::is_sig_ignored(sig)) return (void*)1;
}
void* oldHandler = os::signal(sig, newHandler);
if (oldHandler == os::user_handler()) {
return (void *)2;
} else {
return oldHandler;
}
JVM_END
void* newHandler = handler == (void *)2
? os::user_handler()
: handler;