linux信号机制分析

概念

信号递达:实际执行信号的处理动作就是信号递达

信号未决:信号从产生到递达之间的状态就是信号未决(未决就是没有解决)

收到某信号后,把未决信号集中的此信号置为1(1表示未解决的信号),然后去阻塞信号集中查看此信号有没有被阻塞,如果没有被阻塞的话,那就去信号捕捉函数数组中查看该如何处理该信号

在阻塞信号集中,阻塞和未阻塞用一个bit表示就可以,在未决信号集中也是一样,因此阻塞和未决可以用相同的数据类型sigset_t来存储

发送信号

不管内核驱动调用kill_fasync发送信号,还是用户层调用kill系统调用,最终都会调通过__send_signal_locked,调用内核函数sigaddset来将信号加入信号集

kill_fasync__send_signal_locked
sys_kill__send_signal_locked
static int __send_signal_locked(int sig, struct kernel_siginfo *info,struct task_struct *t, enum pid_type type, bool force)
{struct sigpending *pending;struct sigqueue *q;int override_rlimit;int ret = 0, result;lockdep_assert_held(&t->sighand->siglock);result = TRACE_SIGNAL_IGNORED;if (!prepare_signal(sig, t, force))goto ret;pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;/** Short-circuit ignored signals and support queuing* exactly one non-rt signal, so that we can get more* detailed information about the cause of the signal.*/result = TRACE_SIGNAL_ALREADY_PENDING;if (legacy_queue(pending, sig))goto ret;result = TRACE_SIGNAL_DELIVERED;/** Skip useless siginfo allocation for SIGKILL and kernel threads.*/if ((sig == SIGKILL) || (t->flags & PF_KTHREAD))goto out_set;/** Real-time signals must be queued if sent by sigqueue, or* some other real-time mechanism.  It is implementation* defined whether kill() does so.  We attempt to do so, on* the principle of least surprise, but since kill is not* allowed to fail with EAGAIN when low on memory we just* make sure at least one signal gets delivered and don't* pass on the info struct.*/if (sig < SIGRTMIN)override_rlimit = (is_si_special(info) || info->si_code >= 0);elseoverride_rlimit = 0;//新分配一个sigqueue,将其加入pending队列q = __sigqueue_alloc(sig, t, GFP_ATOMIC, override_rlimit, 0);if (q) {list_add_tail(&q->list, &pending->list);switch ((unsigned long) info) {case (unsigned long) SEND_SIG_NOINFO:clear_siginfo(&q->info);q->info.si_signo = sig;q->info.si_errno = 0;q->info.si_code = SI_USER;q->info.si_pid = task_tgid_nr_ns(current,task_active_pid_ns(t));rcu_read_lock();q->info.si_uid =from_kuid_munged(task_cred_xxx(t, user_ns),current_uid());rcu_read_unlock();break;case (unsigned long) SEND_SIG_PRIV:clear_siginfo(&q->info);q->info.si_signo = sig;q->info.si_errno = 0;q->info.si_code = SI_KERNEL;q->info.si_pid = 0;q->info.si_uid = 0;break;default:copy_siginfo(&q->info, info);break;}} else if (!is_si_special(info) &&sig >= SIGRTMIN && info->si_code != SI_USER) {/** Queue overflow, abort.  We may abort if the* signal was rt and sent by user using something* other than kill().*/result = TRACE_SIGNAL_OVERFLOW_FAIL;ret = -EAGAIN;goto ret;} else {/** This is a silent loss of information.  We still* send the signal, but the *info bits are lost.*/result = TRACE_SIGNAL_LOSE_INFO;}out_set:signalfd_notify(t, sig);sigaddset(&pending->signal, sig);/* Let multiprocess signals appear after on-going forks */if (type > PIDTYPE_TGID) {struct multiprocess_signals *delayed;hlist_for_each_entry(delayed, &t->signal->multiprocess, node) {sigset_t *signal = &delayed->signal;/* Can't queue both a stop and a continue signal */if (sig == SIGCONT)sigdelsetmask(signal, SIG_KERNEL_STOP_MASK);else if (sig_kernel_stop(sig))sigdelset(signal, SIGCONT);sigaddset(signal, sig);}}//唤醒进程complete_signal(sig, t, type);
ret:trace_signal_generate(sig, info, t, type != PIDTYPE_PID, result);return ret;
}

应用层接口

1.int sigemptyset(sigset_t* set);

功能:初始化信号集(把set所指向的信号集中的所有信号的对应bit清零,表示该信号集不包含任何有效信号)

2.int sigfillset(sigset_t* set);

功能:初始化信号集(把set所指向的信号集中的所有信号的对应bit置为1,表示该信号集包含所有的有效信号)

3.int sigaddset(sigset_t* set,int signo);

功能:添加有效信号signo(把编号为signo的信号在位图中的bit从0变为1)

4.int sigdelset(sigset_t* set,int signo);

功能:删除有效信号signor(把编号为signo的信号在位图中的bit从1变为0)

5.int sigismember(const sigset_t* set,int signo);

功能:用于判断信号集中的有效信号是否包含编号为signor的信号

6.int sigprocmask(int how,const sigset_t* set,sigset_t* oset);

功能:可以读取或更改进程的阻塞信号集(信号屏蔽字);SIGKILL和SIGSTOP不能被阻塞

7.int sigpending(sigset_t* set);

功能:读取当前进程的未决信号集,通过参数set传出

8.sighandler_t signal(int signum, sighandler_t handler);

功能:handler需要用户自定义处理信号的方式;也可以是SIG_IGN:忽略该信号;SIG_DFL:采用系统默认方式处理信号

SIGKILL和SIGSTOP不能阻塞原因

见sigprocmask内核代码

void set_current_blocked(sigset_t *newset)
{sigdelsetmask(newset, sigmask(SIGKILL) | sigmask(SIGSTOP));__set_current_blocked(newset);
}void __set_current_blocked(const sigset_t *newset)
{struct task_struct *tsk = current;/** In case the signal mask hasn't changed, there is nothing we need* to do. The current->blocked shouldn't be modified by other task.*/if (sigequalsets(&tsk->blocked, newset))return;spin_lock_irq(&tsk->sighand->siglock);__set_task_blocked(tsk, newset);spin_unlock_irq(&tsk->sighand->siglock);
}/** This is also useful for kernel threads that want to temporarily* (or permanently) block certain signals.** NOTE! Unlike the user-mode sys_sigprocmask(), the kernel* interface happily blocks "unblockable" signals like SIGKILL* and friends.*/
int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
{struct task_struct *tsk = current;sigset_t newset;/* Lockless, only current can change ->blocked, never from irq */if (oldset)*oldset = tsk->blocked;switch (how) {case SIG_BLOCK:sigorsets(&newset, &tsk->blocked, set);break;case SIG_UNBLOCK:sigandnsets(&newset, &tsk->blocked, set);break;case SIG_SETMASK:newset = *set;break;default:return -EINVAL;}__set_current_blocked(&newset);return 0;
}
EXPORT_SYMBOL(sigprocmask);

执行流程

目标进程在从内核态返回用户态的过程中检测是否有挂起的信号,发现有挂起的信号则从链表中每次拿出一个信号事件进行处理直到链表为空

自定义处理函数

对于有通过 signal、sigaction 注册信号处理函数的信号,设定堆栈后跳转到用户态的信号处理函数开始执行,此函数返回后触发一个 sigreturn 系统调用后再次回到内核,然后恢复旧的堆栈继续运行

默认处理

对于 SIGKILL、SIGSTOP 这两种不可被用户程序捕获的信号,以及设定了 SIG_IGN、SIG_DFL 行为的信号而言,这些信号的处理过程均在内核态完成。

对于SIG_DFL,默认行为是dump 的信号处理可能会进程工作目录下创建一个core 文件. 这个文件列出了进程的地址空间和cpu 寄存器的值.

do_signal 创建这个文件后, 就会杀死整个线程组. 剩下18 个信号的默认处理是terminate, 这仅仅是简单地杀死整个线程组. 为此,do_signal 调用了do_group_exit

处理流程

el0_svc执行系统调用后,会通过ret_fast_syscall返回用户空间,会执行do_work_pending

ret_fast_syscall:
__ret_fast_syscall:UNWIND(.fnstart	)UNWIND(.cantunwind	)str	r0, [sp, #S_R0 + S_OFF]!	@ save returned r0
#if IS_ENABLED(CONFIG_DEBUG_RSEQ)/* do_rseq_syscall needs interrupts enabled. */mov	r0, sp				@ 'regs'bl	do_rseq_syscall
#endifdisable_irq_notrace			@ disable interruptsldr	r2, [tsk, #TI_ADDR_LIMIT]cmp	r2, #TASK_SIZEblne	addr_limit_check_failedldr	r1, [tsk, #TI_FLAGS]		@ re-check for syscall tracingtst	r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASKbeq	no_work_pendingUNWIND(.fnend		)
ENDPROC(ret_fast_syscall)/* Slower path - fall through to work_pending */
#endiftst	r1, #_TIF_SYSCALL_WORKbne	__sys_trace_return_nosave
slow_work_pending:mov	r0, sp				@ 'regs'mov	r2, why				@ 'syscall'bl	do_work_pendingcmp	r0, #0beq	no_work_pendingmovlt	scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)ldmia	sp, {r0 - r6}			@ have to reload r0 - r6b	local_restart			@ ... and off we go
ENDPROC(ret_fast_syscall)

do_work_pending调用do_signal对信号做处理

asmlinkage int
do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
{/** The assembly code enters us with IRQs off, but it hasn't* informed the tracing code of that for efficiency reasons.* Update the trace code with the current status.*/trace_hardirqs_off();do {if (likely(thread_flags & _TIF_NEED_RESCHED)) {schedule();} else {if (unlikely(!user_mode(regs)))return 0;local_irq_enable();if (thread_flags & _TIF_SIGPENDING) {int restart = do_signal(regs, syscall);if (unlikely(restart)) {/** Restart without handlers.* Deal with it without leaving* the kernel space.*/return restart;}syscall = 0;} else if (thread_flags & _TIF_UPROBE) {uprobe_notify_resume(regs);} else {clear_thread_flag(TIF_NOTIFY_RESUME);tracehook_notify_resume(regs);rseq_handle_notify_resume(NULL, regs);}}local_irq_disable();thread_flags = current_thread_info()->flags;} while (thread_flags & _TIF_WORK_MASK);return 0;
}

简化框图如下

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2979096.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

2010年认证杯SPSSPRO杯数学建模B题(第一阶段)交通拥堵问题全过程文档及程序

2010年认证杯SPSSPRO杯数学建模 交通拥堵问题 B题 Braess 悖论 原题再现&#xff1a; Dietrich Braess 在 1968 年的一篇文章中提出了道路交通体系当中的Braess 悖论。它的含义是&#xff1a;有时在一个交通网络上增加一条路段&#xff0c;或者提高某个路段的局部通行能力&a…

OceanBase V4.2特性解析:用 Show Trace 快速定位数据库性能瓶颈

在数据库日常运维中&#xff0c;当遇到慢SQL问题时&#xff0c;若无法迅速查明原因&#xff0c;将极大地影响用户的使用感受&#xff0c;甚至可能引发业务或服务的中断。相较于单机数据库&#xff0c;分布式数据库系统因其涉及多个节点和多组件的协同工作&#xff0c;集群规模可…

计算IP地址总个数的方法及其应用

IP地址是计算机网络中用于唯一标识和定位设备的数字地址&#xff0c;是Internet Protocol&#xff08;IP&#xff09;的核心组成部分。计算IP地址的总个数是网络规划和管理中的重要任务之一&#xff0c;本文将介绍计算IP地址总个数的方法及其应用。 IP地址查询&#xff1a;IP数…

华为公司战略规划和落地方法之五看三定工具解析【PPT图片】(内含超级福利)

导言 华为公司最厉害之处就是战略上的高举高打&#xff0c;“吹过的牛都实现了”。支撑华为公司战略从规划到落地的主要工具很多&#xff0c;其中“五看三定”是战略规划时最核心的方法之一。本资料将介绍五看三定的核心精髓。欢迎学习&#xff01; 本材料结合谢宁老师专著《华…

【漏洞复现】锐捷 EG易网关 phpinfo.view.php 信息泄露漏洞

0x01 产品简介 锐捷EG易网关是一款综合网关产品&#xff0c;集成了先进的软硬件体系构架&#xff0c;并配备了DPI深入分析引擎、行为分析/管理引擎。这款产品能在保证网络出口高效转发的基础上&#xff0c;提供专业的流控功能、出色的URL过滤以及本地化的日志存储/审计服务。 …

# 从浅入深 学习 SpringCloud 微服务架构(二)模拟微服务环境(2)通过 RestTemplate 调用远程服务

从浅入深 学习 SpringCloud 微服务架构&#xff08;二&#xff09;模拟微服务环境&#xff08;2&#xff09;通过 RestTemplate 调用远程服务 段子手168 1、打开 idea 创建父工程 创建 artifactId 名为 spring_cloud_demo 的 maven 工程。 --> idea --> File -->…

基于SpringBoot的“幼儿园管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“幼儿园管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 个人信息界面图 缴费信息管理界…

STM32 HAL库F103系列之DAC实验(一)

DAC输出实验 原理图 DAC数据格式 DAC输出电压 DORX - 数据输出寄存器 Vref 3.3V 实验简要 1&#xff0c;功能描述 通过DAC1通道1(PA4)输出预设电压&#xff0c; 然后由ADC1通道1 (PA1) 采集&#xff0c;最后显示ADC转换的数字量及换算后的电压值 2&#xff0c;关闭通道1…

2024平替电容笔买哪个品牌好?iPad电容笔全能榜单热门款TOP5分享!

2024年&#xff0c;随着科技的不断发展和消费者对生活品质的追求&#xff0c;电容笔作为一种创新的无纸化工具&#xff0c;逐渐走进人们的生活和工作中。然而&#xff0c;在电容笔市场的繁荣背后&#xff0c;也隐藏着品质良莠不齐的现象。众多品牌为了追求利润&#xff0c;推出…

SCSS全局配置 vue项目(二)

目录 1、先要查看node版本 2、安装对应的node-sass、sass-loader版本 2.1根据项目使用的node版本安装对应的node-sass版本 2.2根据node-sass版本选择兼容的sass-loader版本&#xff0c;不然项目无法正常运行 3、在 vue.config.js 中配置&#xff1a; 4、在组件中…

QT QZipReader改进,以支持大于2G的zip文件

QZipReader对ZIP文件读取非常方便好用。即使在最新版的QT 6.6.1里&#xff0c;仍然存在一些问题&#xff1a;对于大于2G的zip文件不支持。 虽然有标准zlib可调用&#xff0c;但包装成一个易用且功能成熟的zip解压功能库&#xff0c;还是有很大的工作量&#xff0c;也需要有一定…

【理性讨论】进口主食冻干高价是不是智商税?SC主食冻干全解+测评分享

说到高端主食冻干产品&#xff0c;SC无疑是其中的明星品牌。无论是在哪个平台搜索“主食冻干”等关键词&#xff0c;SC都能轻松进入视线。在双11、618等促销活动中&#xff0c;尽管SC的价格相对较高&#xff0c;但其销量却还不错&#xff0c;这足以说明众多宠物主人对SC冻干品质…

国产技术迎来突破,光量子芯片横空出世,中文编程也有好消息

国外光刻机不再牛&#xff0c;随着这项技术问世&#xff0c;我们摆脱芯片卡脖子困境成为可能&#xff01; 欧美国家在科技领域一直遥遥领先&#xff0c;那我们该如何实现后来居上呢&#xff1f;答案就在于我国在全球处于领先地位的量子科技&#xff0c;以及新近问世、令人瞩目…

如何在React中构建动态下拉组件 - 解释React复合组件模式

下拉菜单长期以来一直是网站和应用程序中的重要组成部分。它们是用户交互的默默英雄&#xff0c;通过简单的点击或轻触默默地促进着无数的操作和决策。 今天你可能已经遇到了其中之一&#xff0c;无论是在你最喜爱的在线商店上选择类别&#xff0c;还是在注册表单上选择你的出…

骨传导耳机哪个牌子好?5款年度精品骨传导耳机推荐

在骨传导耳机最开始出现的时候&#xff0c;相信很多人都只关心骨传导耳机的外观颜值和特殊的传声方式&#xff0c;但当你真正用过一段时间后&#xff0c;对骨传导耳机有了更加深入的了解后就会关注到骨传导耳机的使用体验、音质表现、蓝牙性能等具体功能&#xff0c;而随着骨传…

上位机图像处理和嵌入式模块部署(树莓派4b的一种固件部署方法)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 如果软件开发好了之后&#xff0c;下面就是实施和部署。对于树莓派4b来说&#xff0c;部署其实就是烧录卡和拷贝文件。之前我们烧录卡&#xff0c;…

RK3568 学习笔记 : u-boot 千兆网络无法 ping 通PC问题的解决

前言 开发板型号&#xff1a; 【正点原子】 的 RK3568 开发板 使用 虚拟机 ubuntu 20.04 收到单独 编译 RK3568 u-boot 【问题】u-boot 千兆网络无法ping 通&#xff1f;Linux 下千兆网络正常&#xff0c;说明&#xff1a;开发板硬件正常 u-boot 下网络如果通了&#xff0c;…

Unity的旋转实现一些方法总结(案例:通过输入,玩家进行旋转移动)

目录 1. Transform.Rotate 方法 使用 2. Transform.rotation 或 Transform.localRotation 属性与四元数 使用方式&#xff1a; 小案例 &#xff1a;目标旋转角度计算&#xff1a;targetRotation&#xff08;Quaternion类型&#xff09; 玩家发现敌人位置&#xff0c;玩家…

【数据结构】AVL树(万字超详细 附动图)

一、前言 二、AVL树的性质 三、AVL树节点的定义 四、AVL树的插入 五、AVL树的平衡调整 六、AVL树的验证 6.1 验证有序 6.2 验证平衡 七、AVL树的删除 八、AVL树的性能和代码 一、前言 还没有学习过二叉搜索树的同学可以移步 【数据结构】二叉搜索树-CSDN博客https:/…

【C++】:构造函数和析构函数

目录 前言一&#xff0c;构造函数**1.1 什么是构造函数****1.2 构造函数的特性**1.3 总结 二&#xff0c;析构函数**2.1 什么是析构函数****2.2 析构函数的特性****2.3 总结** 前言 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并…