0。概述本文介绍了Linux信号传输的代码执行过程,重点描述了信号传输结束的通知机制。1.ScopeLinux信号处理网上有很多参考资料,比如下面链接里的四篇文章把信号解释的很透彻http://blog.chinaunix.net/uid...这篇文章主要针对linuxsignaltransmission结束时使用的通知机制,即linux如何及时通知目标进程“你有信号要处理,我们赶紧处理”。本文所指内核代码为Linux4.1.12,硬件架构为arm64。2.Linux信号传输过程本章不是重点,应该算是一个备忘笔记。在用户空间发送信号的命令,kill,其实际代码执行流程如下功能确实停止说话,变得懒惰。.3、complete_signal函数是本文的重点,因为信号已经准备好,最终必须通知目标进程尽快处理。我们知道,进程处理信号的时机是在从内核态返回用户态之前,通过ret_to_user函数中的TIF_SIGPENDING标志查询是否有信号需要处理。如果有,则调用do_notify_resume->do_signal进行处理。sigaddset函数是实现第一步,将信号添加到进程的pengding->signal位掩码中。complete_signal函数负责实现第二步,通知进程尽快处理。该函数的执行流程如下Returnstrue;如果进程已经在运行队列中,则返回false。voidsignal_wake_up_state(structtask_struct*t,unsignedintstate){set_tsk_thread_flag(t,TIF_SIGPENDING);/**TASK_WAKEKILL也意味着在停止/跟踪/可杀死的情况下将其唤醒*情况。我们在这里不使用checkt->state因为它有一个竞争*执行另一个处理器并且刚刚进入停止状态。*通过使用wake_up_state,我们确保进程将唤醒并*处理它的死亡信号。*/if(!wake_up_state(t,state|TASK_INTERRUPTIBLE))kick_process(t);}根据signal_wake_up_state函数的代码逻辑,如果wake_up_state函数返回true,则不会执行kick_process。kick_process只有在目标进程已经在运行队列中时才会执行。让我们看一下kick_process函数的实现:/****kick_process-踢一个正在运行的线程进入/退出内核*@p:被踢线程**引起一个正在另一个上运行的进程CPU进入*内核模式,没有任何延迟。(以处理信号。)**注意:此函数不必获取运行队列锁,*因为它要确保远程任务进入*内核。如果IPI竞争并且任务已迁移*到另一个CPU,则不会造成任何伤害并且目的也已实现。*/voidkick_process(structtask_struct*p){intcpu;抢先禁用();cpu=task_cpu(p);如果((cpu!=smp_processor_id())&&task_curr(p))smp_send_reschedule(cpu);preempt_enable();}函数的注释已经写的很清楚了,kick_process的作用就是让进程落入内核,然后有机会在第一次返回userland前处理信号。smp_send_reschedule的本质是向进程所在的核心发送一个IPI中断,这会导致正在运行的进程被中断而进入内核态。但是发送IPI中断还必须满足两个前提:目标进程所在的cpu不是当前cpu,也就是说信号的发送方和接收方不在同一个核上。如果它在核心上,则目标进程必须已经处于内核模式。目标进程在核心上运行。请注意,它正在运行,而不是在运行队列中。4.总结与思考总结本文的主要内容,内核将信号相关信息放入指定进程的pending->signal后,需要通知进程尽快处理。如果进程处于内核态,内核会唤醒进程并将其放入runqueue;如果进程处于用户态或者正在运行,就会向进程所在的核心发送一个IPI中断来打断进程,使其在下次信号处理时有机会回到用户态。一个问题:如果进程A和进程B都是实时进程(调度策略是FIFO),那么A和B都绑定到CPU1上。A的优先级高于B,A正在运行,B也在运行队列中。如果此时用户想通过shell上的kill命令终止进程B,那么进程B是否可以终止退出呢?
