linux signal产生(发送)

本文详细介绍了Linux内核中信号的发送过程,包括sys_tkill、sys_kill等函数,以及信号如何从pending队列中取出并处理。讨论了线程、线程组和进程组间的信号发送差异,并解析了send_signal函数的实现,涉及到信号预处理、查找处理信号的线程等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不论是内核发送信号(硬件异常-SIGSEGV等、软件通知-SIGPIPE等、终端键-SIGINT等),还是用户进程发送信号(kill系统调用),都要由内核将信号记录到相应(轻量级)进程描述符中的信号相关结构中、唤醒被阻塞的目标进程等。
在信号发送阶段,内核将信号添加到信号pending队列中;在信号传递阶段,内核将信号从pending队列中取出,并处理(包括调用用户自定义处理、SIG_DFL默认处理、SIG_IGN忽略处理)。

 

注:linux内核无线程概念,线程的功能是由轻量级进程实现,以下线程均代表轻量级进程;线程组代表进程,包括只有主控线程的进程

 

I.signal发送函数
信号可以发送到线程、线程组、进程组
内核主要通过以下函数发送信号:
线程
sys_tkill/sys_tgkill:tkill/tgkill系统调用对应的内核服务
send_sig:发送信号到线程
force_sig:强制发送信号到线程;当目标进程忽略该信号时,将信号处理重置为SIG_DFL;当目标进程阻塞该信号时,将信号处理重置为SIG_DFL并清空阻塞mask中对应的信号位

 

线程组(进程)
sys_kill:kill系统调用对应的内核服务;当参数pid大于0时,会发送信号给线程组
group_send_sig_info:发送信号给某线程组

 

进程组
__kill_pgrp_info:发送信号给进程组内的所有线程组

以上函数的调用关系图如下:


信号发送到线程和线程组的区别主要是,将信号pending到私有信号pending队列还是共享信号pending队列;发送信号到进程组其实就是发送信号到进程组内的所有线程组

 


II.发送函数实现
由上图可知,所有的函数都会最终调用send_signal实现信号的发送

i.send_signal

/* kernel/signal.c */
 916 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
 917                         int group)
 918 {
 919         int from_ancestor_ns = 0;
 920 
 921 #ifdef CONFIG_PID_NS
 922         if (!is_si_special(info) && SI_FROMUSER(info) &&
 923                         task_pid_nr_ns(current, task_active_pid_ns(t)) <= 0)
 924                 from_ancestor_ns = 1;
 925 #endif
 926 
 927         return __send_signal(sig, info, t, group, from_ancestor_ns);
 928 }

from_ancestor_ns置位必须满足以下所有条件:
1.siginfo不是特殊的信号信息,SEND_SIG_NOINFO,SEND_SIG_PRIV,SEND_SIG_FORCED
2.信号是从用户进程通过kill发出的
3.发送信号的进程current是上级pid命名空间的进程(即current不在下级pid命名空间中),接收方为下级pid命名空间的进程;由alloc_pid可以看出,下级pid命名空间分配进程id时,也会在所有上级分配一个id;比如有两级pid命名空间,上级的id有1、2...1023,下级id有1、2,当下级创建进程则会在下级分配3上级分配1024,即上级的1024与下级的3是同一进程,此时上级空间的2进程向下级空间2发送信号就叫from_ancestor_ns
注:由struct pid中numbers数组大小为1及alloc_pid处理可知目前内核版本(2.6.32.60)只支持一级pid命名空间,所以from_ancestor_ns恒等于0
send_signal会以from_ancestor_ns=0调用__send_signal

 832 static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
 833                         int group, int from_ancestor_ns)
 834 {
 835         struct sigpending *pending;
 836         struct sigqueue *q;
 837         int override_rlimit;
 838 
 839         trace_sched_signal_send(sig, t);
 840 
 841         assert_spin_locked(&t->sighand->siglock);
 842 
 843         if (!prepare_signal(sig, t, from_ancestor_ns))
 844                 return 0;
 845 
 846         pending = group ? &t->signal->shared_pending : &t->pending;
 847         /*
 848          * Short-circuit ignored signals and support queuing
 849          * exactly one non-rt signal, so that we can get more
 850          * detailed information about the cause of the signal.
 851          */
 852         if (legacy_queue(pending, sig))
 853                 return 0;
 854         /*
 855          * fast-pathed signals for kernel-internal things like SIGSTOP
 856          * or SIGKILL.
 857          */
 858         if (info == SEND_SIG_FORCED)
 859                 goto out_set;
 860 
 861         /* Real-time signals must be queued if sent by sigqueue, or
 862            some other real-time mechanism.  It is implementation
 863            defined whether kill() does so.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值