您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > signal-deliver
Linux内核源码分析之信号传递郭海林2012.11.3信号的处理阶段•信号的产生内核更新目标进程的数据结构以表示新信号以被发送•信号的传递内核强迫目标进程对信号做出反应与信号机制相关的数据结构listflagsinfousersigqueuesi_signosi_errosi_code...struct_info信号响应的三种方式•显示地忽略信号•执行与信号相关的缺省操作–Terminate:进程被终止–Dump:Terminate+Core–Ignore:忽略–Stop:进程被停止,即置为TASK_STOPPED–Continue:置为TASK_RUNNING•通过调用相应的信号处理函数捕获信号(&sighand-action[nr-1])-sa.sa_handler信号检测和响应时机•当前进程由于系统调用、中断或异常而进入系统空间以后,从系统空间返回到用户空间的前夕。•当前进程在内核中进入睡眠以后刚被唤醒的时候(必定是在系统调用中),或者由于不可忽略信号的存在而提前返回到用户空间。do_signal()系统调用的重新执行get_signal_to_deliver()for(;;){//取出一个未加屏蔽的信号signr=dequeue_signal(current,¤t-blocked,info);//没有可处理信号,退出for循环if(!signr)break;//取得信号向量表的表项ka=&sighand-action[signr-1];//根据ka-sa.sa_handler的值进行处理信号//A.显示忽略,继续寻找下一个挂起信号if(ka-sa.sa_handler==SIG_IGN)continue;get_signal_to_deliver()//B.用户自定义的处理函数,跳出break,返回到do_signal()if(ka-sa.sa_handler!=SIG_DFL){*return_ka=*ka;if(ka-sa.sa_flags&SA_ONESHOT)//如果设置了标志SA_ONESHOTka-sa.sa_handler=SIG_DFL;break;/*willreturnnon-zerosignrvalue*/}//C.如果信号处理为默认动作//C1.为Ignore,如SIGCHLD,SIGCONT,SIGURG,SIGWINCH等信号,返回forif(sig_kernel_ignore(signr))/*Defaultisnothing.*/continue;//C2.为Stop,如SIGSTOP,SIGTSTP,SIGTIN,SIGTOU等信号,if(sig_kernel_stop(signr)){...//会调用schedule()切换进程continue;}get_signal_to_deliver()//C3.为Terminate+Core,如SIGQUIT,SIGILL,SIGTRAP,SIGABRT等等信号,执行到C4if(sig_kernel_coredump(signr)){...do_coredump(info-si_signo,info-si_signo,regs);}//C4.为terminate,如SIGXCPU,SIGPROF,SIGPWR,SIGUNUSED等等信号,结束进程do_group_exit(info-si_signo);}//endof'for(;;)'从get_signal_to_deliver()函数返回的情形:①没有非阻塞的信号可选择②选择了一个用户自定义处理的信号捕获信号机制handle_signal()运行在内核态用户定义的信号处理函数运行在用户态在当前进程恢复“正常”执行前,必须先执行用户态的信号处理程序整个过程•在用户态堆栈为信号处理程序预设一个frame,把内核栈“原始frame”保存到此。•内核插入对系统调用sigreturn的代码。•修改内核栈中“原始frame”修改成为执行信号处理程序所需的frame。•返回到用户空间,但执行的是信号处理程序。•信号处理程序执行完之后,通过sigreturn返回到内核空间。•在系统调用sigreturn中从用户态堆栈恢复“原始frame”。•再从内核态返回用户态,继续执行原始的用户程序。handle_signal()-setup_rt_frame()•A.在用户态堆栈上分配一个frame,用来保存内核堆栈上“原始frame”–分配frame:structsigframe*frame=get_sigframe(ka,regs,sizeof(*frame),&fpstate);unsignedlongsp=regs-sp;sp=align_sigframe(sp-frame_size);return(void__user*)sp;示意图(1)用户态堆栈内核态堆栈spip用户程序信号处理程序regespframesigframeretcodeextramaskfpstatescsigpretcodesetup_rt_frame()•B.填充structsigframe__put_user(sig,&frame-sig)ia32_setup_sigcontext(&frame-sc,fpstate,regs,set-sig[0])__copy_to_user(frame-extramask,&set-sig[1],sizeof(frame-extramask))put_user_ex(ptr_to_compat(restorer),&frame-pretcode);put_user_ex(*((u64*)&code),(u64*)frame-retcode);示意图(2)用户态堆栈内核态堆栈spip用户程序信号处理程序regespframesigframeretcodeextramaskfpstatescsigpretcodeint0x80;movl119,%eax;popl%eaxsetup_rt_frame()•C.修改内核堆栈原来frameregs-sp=(unsignedlong)frame;regs-ip=(unsignedlong)ka-sa.sa_handler;/*Make-mregparm=3work*/regs-ax=sig;regs-dx=0;regs-cx=0;loadsegment(ds,__USER32_DS);loadsegment(es,__USER32_DS);regs-cs=__USER32_CS;regs-ss=__USER32_DS;示意图(3)用户态堆栈内核态堆栈spip用户程序信号处理程序regespframesigframeretcodeextramaskfpstatescsigpretcodeint0x80;movl119,%eax;popl%eax内核态--用户态•D.执行信号处理程序示意图(4)用户态堆栈内核态堆栈spip用户程序信号处理程序regsigframeretcodeextramaskfpstatescsigpretcodeint0x80;movl119,%eax;popl%eaxespeip信号处理程序执行ret指令:popl%eip用户态--内核态•E.系统调用sigreturn重回内核态示意图(5)用户态堆栈内核态堆栈spip用户程序信号处理程序regsigframeretcodeextramaskfpstatescsigpretcodeint0x80;movl119,%eax;popl%eaxeipespsys_sigreturn()•F.恢复内核态的原始framestructsigframe*frame=(structsigframe*)(regs-sp-8);__copy_from_user(&set.sig[1],&frame-extramask,sizeof(frame-extramask));restore_sigcontext(regs,&frame-sc,&ax);示意图(6)用户态堆栈内核态堆栈spip用户程序信号处理程序regsigframeretcodeextramaskfpstatescsigpretcodeint0x80;movl119,%eax;popl%eaxeipespframe内核态--用户态•G.回到用户程序正常执行流程回顾•从内核的角度:–怎样从A向B发送一个信号——信号的发送–B怎样执行这个信号——信号的传递•从应用程序的角度:–怎样发送一个信号——kill,tkill,tgkill...–目标进程应该阻塞哪些信号——sigprocmask–目标进程如何响应收到的信号——singnal,sigactionThankUForListening!UnderstandingtheLinuxKernelReadthefuckingsourcecode!
本文标题:signal-deliver
链接地址:https://www.777doc.com/doc-3352873 .html