linux内核中的信号机制--信号处理
CPU architecture:ARM920T
Author:ce123(http://blog.csdn.net/ce123)
当进程被调度时,会调用do_notify_resume()来处理信号队列中的信号。信号处理主要就是调用sighand_struct结构中对应的信号处理函数。do_notify_resume()(arch/arm/kernel/signal.c)函数的定义如下:
[plain]view plaincopyprint?
- asmlinkagevoid
- do_notify_resume(structpt_regs*regs,unsignedintthread_flags,intsyscall)
- {
- if(thread_flags&_TIF_SIGPENDING)
- do_signal(¤t->blocked,regs,syscall);
- }
[plain]view plaincopyprint?
- /*
- *Notethatinitisaspecialprocess:itdoesntgetsignalsitdoesnt
- *wanttohandle.ThusyoucannotkillinitevenwithaSIGKILLevenby
- *mistake.
- *
- *Notethatwegothroughthesignalstwice:oncetocheckthesignalsthat
- *thekernelcanhandle,andthenwebuildalltheuser-levelsignalhandling
- *stack-framesinonegoafterthat.
- */
- staticintdo_signal(sigset_t*oldset,structpt_regs*regs,intsyscall)
- {
- structk_sigactionka;
- siginfo_tinfo;
- intsignr;
- /*
- *Wewantthecommoncasetogofast,which
- *iswhywemayincertaincasesgetherefrom
- *kernelmode.Justreturnwithoutdoinganything
- *ifso.
- */
- if(!user_mode(regs))//regs保存的是进入内核态之前的寄存器现场,必须为用户模式,否则直接返回
- return0;
- if(try_to_freeze())
- gotono_signal;
- if(current->ptrace&PT_SINGLESTEP)
- ptrace_cancel_bpt(current);//和调试相关,我们在后面的文章中会具体分析
- signr=get_signal_to_deliver(&info,&ka,regs,NULL);//取出等待处理的信号
- if(signr>0){
- handle_signal(signr,&ka,&info,oldset,regs,syscall);//处理信号
- if(current->ptrace&PT_SINGLESTEP)
- ptrace_set_bpt(current);
- return1;
- }
- no_signal:
- /*
- *Nosignaltodelivertotheprocess-restartthesyscall.
- */
- if(syscall){
- if(regs->ARM_r0==-ERESTART_RESTARTBLOCK){
- if(thumb_mode(regs)){
- regs->ARM_r7=__NR_restart_syscall;
- regs->ARM_pc-=2;
- }else{
- u32__user*usp;
- regs->ARM_sp-=12;
- usp=(u32__user*)regs->ARM_sp;
- put_user(regs->ARM_pc,&usp[0]);
- /*swi__NR_restart_syscall*/
- put_user(0xef000000|__NR_restart_syscall,&usp[1]);
- /*ldrpc,[sp],#12*/
- put_user(0xe49df00c,&usp[2]);
- flush_icache_range((unsignedlong)usp,
- (unsignedlong)(usp+3));
- regs->ARM_pc=regs->ARM_sp+4;
- }
- }
- if(regs->ARM_r0==-ERESTARTNOHAND||
- regs->ARM_r0==-ERESTARTSYS||
- regs->ARM_r0==-ERESTARTNOINTR){
- restart_syscall(regs);
- }
- }
- if(current->ptrace&PT_SINGLESTEP)
- ptrace_set_bpt(current);
- return0;
- }
执行do_signal()函数时,进程一定处于内核空间,通常进程只有通过中断或者系统调用才能进入内核空间,regs保存着系统调用或者中断时的现场。user_mode()根据regs中的cpsr寄存器来判断是中断现场环境还是用户态环境。如果不是用户态环境,就不对信号进行任何处理,直接从do_signal()函数返回。
如果user_mode()函数发现regs的现场是内核态,那就意味着这不是一次系统调用的返回,也不是一次普通的中断返回,而是一次嵌套中断返回(或者在系统调用过程中发生了中断)。此时大概的执行路径应该是这样的:假设进场现在运行在用户态,此时发生一次中断,进场进入内核态(此时user_mode(regs)返回1,意味着中断现场是用户态。),此后在中断返回前,发生了一个更高优先级的中断,于是CPU开始执行高优先级的处理函数(此时user_mode(regs)返回0,意味着中断现场是在内核态)。当高优先级中断处理结束后,在它返回时,是不应该处理信号的,因为信号的优先级比中断的优先级低。在这种情况下,对信号的处理将会延迟到低优先级中断处理结束之后。相对于Windows内核来说,尽管linux内核中没有一组显式的操作函数来实现这一系列的优先级管理方案,但是linux内核和Windows内核都使用了同样的机制,优先级关系为:高优先级中断->低优先级中断->软中断(类似Windows内中的DPC)->信号(类似Windows内核中的APC)->进程运行。
如果user_mode(regs)返回1,接下来会执行(中间略去一下和本文关系不大的代码)get_signal_to_deliver(),这个函数从当前进程的信号队列(保存Private Signal Queue和Shared Signal Queue)取出等待处理的信号(调用dequeue_s
linux内核信号机制信号处 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)