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

Java 工具(jmap,jstack)在Linux上的源碼分析(二)信號處理

當java虛擬機啟動的時候,會啟動很多內部的線程,這些線程主要在thread.cpp裡的create_vm方法體裡實現

而在thread.cpp裡主要起了2個線程來處理信號相關的

  1. JvmtiExport::enter_live_phase();  
  2.   
  3. // Signal Dispatcher needs to be started before VMInit event is posted   
  4. os::signal_init();  
  5.   
  6. // Start Attach Listener if +StartAttachListener or it can't be started lazily   
  7. if (!DisableAttachMechanism) {  
  8.   if (StartAttachListener || AttachListener::init_at_startup()) {  
  9.     AttachListener::init();  
  10.   }  
  11. }  

1. Signal Dispatcher 線程

在os.cpp中的signal_init()函數中,啟動了signal dispatcher 線程,對signal dispather 線程主要是用於處理信號,等待信號並且分發處理,可以詳細看signal_thread_entry的方法

  1. static void signal_thread_entry(JavaThread* thread, TRAPS) {  
  2.   os::set_priority(thread, NearMaxPriority);  
  3.   while (true) {  
  4.     int sig;  
  5.     {  
  6.       // FIXME : Currently we have not decieded what should be the status   
  7.       //         for this java thread blocked here. Once we decide about   
  8.       //         that we should fix this.   
  9.       sig = os::signal_wait();  
  10.     }  
  11.     if (sig == os::sigexitnum_pd()) {  
  12.        // Terminate the signal thread   
  13.        return;  
  14.     }  
  15.   
  16.     switch (sig) {  
  17.       case SIGBREAK: {  
  18.         // Check if the signal is a trigger to start the Attach Listener - in that   
  19.         // case don't print stack traces.   
  20.         if (!DisableAttachMechanism && AttachListener::is_init_trigger()) {  
  21.           continue;  
  22.         }  
  23.         // Print stack traces   
  24.         // Any SIGBREAK operations added here should make sure to flush   
  25.         // the output stream (e.g. tty->flush()) after output.  See 4803766.   
  26.         // Each module also prints an extra carriage return after its output.   
  27.         VM_PrintThreads op;  
  28.         VMThread::execute(&op);  
  29.         VM_PrintJNI jni_op;  
  30.         VMThread::execute(&jni_op);  
  31.         VM_FindDeadlocks op1(tty);  
  32.         VMThread::execute(&op1);  
  33.         Universe::print_heap_at_SIGBREAK();  
  34.         if (PrintClassHistogram) {  
  35.           VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */,  
  36.                                    true /* need_prologue */);  
  37.           VMThread::execute(&op1);  
  38.         }  
  39.         if (JvmtiExport::should_post_data_dump()) {  
  40.           JvmtiExport::post_data_dump();  
  41.         }  
  42.         break;  
  43.       }  
  44.       default: {  
  45.         // Dispatch the signal to java   
  46.         HandleMark hm(THREAD);  
  47.         klassOop k = SystemDictionary::resolve_or_null(vmSymbolHandles::sun_misc_Signal(), THREAD);  
  48.         KlassHandle klass (THREAD, k);  
  49.         if (klass.not_null()) {  
  50.           JavaValue result(T_VOID);  
  51.           JavaCallArguments args;  
  52.           args.push_int(sig);  
  53.           JavaCalls::call_static(  
  54.             &result,  
  55.             klass,  
  56.             vmSymbolHandles::dispatch_name(),  
  57.             vmSymbolHandles::int_void_signature(),  
  58.             &args,  
  59.             THREAD  
  60.           );  
  61.         }  
  62.         if (HAS_PENDING_EXCEPTION) {  
  63.           // tty is initialized early so we don't expect it to be null, but   
  64.           // if it is we can't risk doing an initialization that might   
  65.           // trigger additional out-of-memory conditions   
  66.           if (tty != NULL) {  
  67.             char klass_name[256];  
  68.             char tmp_sig_name[16];  
  69.             const char* sig_name = "UNKNOWN";  
  70.             instanceKlass::cast(PENDING_EXCEPTION->klass())->  
  71.               name()->as_klass_external_name(klass_name, 256);  
  72.             if (os::exception_name(sig, tmp_sig_name, 16) != NULL)  
  73.               sig_name = tmp_sig_name;  
  74.             warning("Exception %s occurred dispatching signal %s to handler"  
  75.                     "- the VM may need to be forcibly terminated",  
  76.                     klass_name, sig_name );  
  77.           }  
  78.           CLEAR_PENDING_EXCEPTION;  
  79.         }  
  80.       }  
  81.     }  
  82.   }  
  83. }  

可以看到通過os::signal_wait();等待信號,而在linux裡是通過sem_wait()來實現,接受到SIGBREAK(linux 中的QUIT)信號的時候(關於信號處理請參考筆者的另一篇:Java 中關於信號的處理在Linux下的實現 http://www.linuxidc.com/Linux/2012-01/51212.htm),第一次通過調用 AttachListener::is_init_trigger()初始化attach listener線程,詳細見2.Attach Listener 線程。

  1. 第一次收到信號,會開始初始化,當初始化成功,將會直接返回,而且不返回任何線程stack的信息(通過socket file的操作返回),並且第二次將不在需要初始化。如果初始化不成功,將直接在控制台的outputstream中打印線程棧信息。
  2. 第二次收到信號,如果已經初始化過,將直接在控制台中打印線程的棧信息。如果沒有初始化,繼續初始化,走和第一次相同的流程。
Copyright © Linux教程網 All Rights Reserved