歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Java 中關於自定義信號在Linux下的實現

在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; 

Copyright © Linux教程網 All Rights Reserved