linux 的线程和信号
基于 NPTL 的线程库,多线程应用中的每个线程有自己独特的线程 ID,并共享同一个进程ID。应用程序可以通过调用 kill(getpid(),signo)
将信号发送到进程,如果进程中当前正在执行的线程没有阻碍此信号,则会被中断,线号处理函数会在此线程的上下文背景中执行。应用程序也可以通过调用 pthread_kill(pthread_t thread, int sig)
将信号发送给指定的线程,则线号处理函数会在此指定线程的上下文背景中执行。
java里信号掩码的集合
unblocked_sigs |
SIGILL SIGSEGV SIGBUS SIGFPE SR_signum SHUTDOWN1_SIGNAL(SIGHUP) SHUTDOWN2_SIGNAL(SIGINT) SHUTDOWN3_SIGNAL(SIGTERM) |
vm_sigs |
BREAK_SIGNAL (SIGQUIT) |
allowdebug_blocked_sigs |
SHUTDOWN1_SIGNAL(SIGHUP) SHUTDOWN2_SIGNAL(SIGINT) SHUTDOWN3_SIGNAL(SIGTERM) |
SIG_BLOCK |
NULL |
在多线程的应用中,每个线程可以通过调用pthread_signmask()设置本线程的信号掩码,可以设置阻塞的信号,但信号SIGKILL/SIGSTOP是不能被设置成阻塞的。
在java中,每个线程都设置了在表格中的信号掩码,特别提到的是vm_sigs,这是只有一个quit 的信号结合,当没有设置启动参数 -Xrs (=ReduceSignalUsage)的时候,其他的线程设置成阻塞的,除了vm thread。
Java里信号处理的函数
在linux里可以设置进程级别的信号的处理函数,在内核中信号值及进程针对该信号的处理函数建立了映射关系,主要有2个函数来设置信号处理函数:signal(),sigaction()。函数具体可以参考http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html
在java 里,下面的2个函数是用于设置信号处理的函数
void os::Linux::set_signal_handler(int sig, bool set_installed)
void* os:signal(int signal_number, void* handler)
下面的源码是java里面定义的os:user_handler
在函数的末尾调用了os:signal_notify,从而和os::signal_wait 对应起来,关于signal dispatcher 的具体实现可以参考笔者的另一篇博客(http://blog.csdn.net/raintungli/article/details/7034005)。
signal dispatcher 线程通过sem_wait会在等待,当进程接到信号SIGQUIT的时候,只有vm thread会被中断(见上面分析),而进入UserHandler 函数,通过调用 os::signal_notify 去通告signal dispatcher 线程,让 signal dispatch 线程去处理信号。
在信号设计里,因为信号中断是在内核态调用的,内核调用了线程注入了自己的信号函数,一般只允许在该函数里处理简单的事物,所以在java里面专门设计了处理信号后续的线程(signal dispatcher),接受到信号的线程通过信号函数notify到处理信号的线程(signal dispatcher ),最后由该线程做后续的事情。比如线程dump
关于信号中断的内核态和用户态的如何嵌入,可以参考(Linux内核信号处理机制介绍)