linux signal产生(发送)

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

不论是内核发送信号(硬件异常-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  
Linux中的信号处理是通过信号机制实现的。当一个进程接收到一个信号时,它会根据事先定义好的处理方式来处理这个信号。信号的处理方式包括终止进程、忽略信号、终止进程并生成core文件、停止进程和继续运行进程等不同的动作。 在Linux中,信号的处理是通过设置信号的处理函数来完成的。当一个信号到达时,内核会调用相应的处理函数来处理这个信号。可以通过系统提供的函数来设置自定义的信号处理函数。 信号的发送可以通过多种方式,包括按键产生、终端按键产生、系统调用产生、软件条件产生和硬件异常产生等。不同的事件会触发不同的信号发送。例如,按下Ctrl+C会发送SIGINT信号,而按下Ctrl+Z会发送SIGTSTP信号。 对于进程来说,接收到信号后,不管正在执行什么代码,都会暂停运行,去处理信号。这种处理方式类似于硬件中断,被称为“软中断”。对于用户来说,由于信号的实现方式,信号的延迟时间非常短,几乎不可察觉。 总而言之,Linux中的信号处理是通过信号机制实现的,程序在接收到信号后会根据事先定义好的处理方式来处理这个信号。这种处理方式可以通过设置信号的处理函数来自定义。信号的发送可以通过多种方式,不同的事件会触发不同的信号发送。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Linux信号(signal)](https://blog.csdn.net/weixin_43408582/article/details/115523424)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值