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);
	else
		override_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
#endif
	disable_irq_notrace			@ disable interrupts
	ldr	r2, [tsk, #TI_ADDR_LIMIT]
	cmp	r2, #TASK_SIZE
	blne	addr_limit_check_failed
	ldr	r1, [tsk, #TI_FLAGS]		@ re-check for syscall tracing
	tst	r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK
	beq	no_work_pending
 UNWIND(.fnend		)
ENDPROC(ret_fast_syscall)

	/* Slower path - fall through to work_pending */
#endif

	tst	r1, #_TIF_SYSCALL_WORK
	bne	__sys_trace_return_nosave
slow_work_pending:
	mov	r0, sp				@ 'regs'
	mov	r2, why				@ 'syscall'
	bl	do_work_pending
	cmp	r0, #0
	beq	no_work_pending
	movlt	scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)
	ldmia	sp, {r0 - r6}			@ have to reload r0 - r6
	b	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;
}

简化框图如下

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

kubeadmin搭建自建k8s集群

一、安装要求 在开始之前&#xff0c;部署Kubernetes集群的虚拟机需要满足以下几个条件&#xff1a; 操作系统 CentOS7.x-86_x64硬件配置&#xff1a;2GB或更多RAM&#xff0c;2个CPU或更多CPU&#xff0c;硬盘30GB或更多【注意master需要两核】可以访问外网&#xff0c;需要…

【QT进阶】Qt Web混合编程之使用ECharts显示各类折线图等

往期回顾 【QT进阶】Qt Web混合编程之QWebEngineView基本用法-CSDN博客 【QT进阶】Qt Web混合编程之CMake VS2019编译并使用QCefView&#xff08;图文并茂超详细版本&#xff09;-CSDN博客【QT进阶】Qt Web混合编程之html、 js的简单交互-CSDN博客 【QT进阶】Qt Web混合编程之使…

什么是信息熵?

什么是信息&#xff1f; ​ 我们在日常生活中吃瓜的时候总会说信息量太大了&#xff0c;那么这个信息是怎么个意思呢&#xff1f;我们在听到的时候很多原因都是因为这个消息是新鲜的&#xff0c;我们没见过的&#xff0c;没听说过&#xff0c;所以就说是信息量大。 信息熵 2…

YOLOv9训练结果分析->mAP、Precision、Recall、FPS、Confienc、混淆矩阵分析

简介 这篇博客&#xff0c;主要给大家讲解我们在训练yolov9时生成的结果文件中各个图片及其中指标的含义&#xff0c;帮助大家更深入的理解&#xff0c;以及我们在评估模型时和发表论文时主要关注的参数有那些。本文通过举例训练过程中的某一时间的结果来帮助大家理解&#xf…

【FineBI】强大处理、分析和可视化数据的工具

文章目录 前言功能丰富的数据处理深入的数据分析交互式的数据可视化协作与共享无缝的集成 总结 前言 在当今数据驱动的商业环境中&#xff0c;企业需要强大的工具来处理、分析和可视化数据&#xff0c;以便做出更明智的决策。FineBI就是这样一个工具&#xff0c;它是一个全面的…

维乐Angel Revo让你的骑行生活从此美得冒泡儿~重新定义『坐着的艺术』!

维乐「AngelRevo」美学系列坐垫荣获「2023年台北国际自行车展创新设计奖」是卓越品质和极致减碳的双重结合精品。底壳的YCut设计&#xff0c;前段的加长的透孔&#xff0c;减轻压迫&#xff0c;有效释放压力。在享受驰骋赛道的快感同时&#xff0c;提升舒适度。 这款坐垫采用了…

js获取某月往前推一年或半年的年月数组

前言 需求&#xff1a;需要显示某月份往前推一年或者半年的费用情况&#xff0c;显示到柱形图上&#xff0c;后台接口只返回有数据的年份&#xff0c;这就需要前端拿全部月份数组去比对并显示。 开始 上代码&#xff1a; // date:选择的月份,比如:2024-04,//n:半年或者1年,…

如何让复购率提升:亚马逊、Lazada、速卖通的营销技巧

跨境电商卖家必须抓住客户&#xff0c;而客户维护是提高复购率的关键。很多卖家热衷于吸引新客户&#xff0c;却忽略了旧客户的重要性。相较于投入广告和参与秒杀活动以吸引新客户&#xff0c;维护好旧客户并提高复购率的成本更低。然而&#xff0c;实现客户维护和复购率提升并…

Python获取上市公司报告,AI分析助力投资决策

折腾了几天&#xff0c;通过从巨潮信息网上获取上市公司的报告&#xff0c;然后实现调用大语言模型的API去分析报告内容&#xff0c;下面把相应的代码和过程分享给对这个感兴趣的兄弟姐妹们&#xff0c;希望能帮到大家。 1&#xff0c;首先去巨潮信息网首页&#xff0c;右上角…

vuex和pinia转态管理工具介绍

文章目录 一、介绍二、使用1、pinia使用2、Vuex使用 一、介绍 相同点&#xff1a; 都是Vue.js的状态管理工具 不同点&#xff1a; 区别PiniaVuex支持Vue2和Vue3都支持Vue3写法需要额外配置Mutation只有 state, getter 和 action&#xff0c;无Mutationaction异步、Mutation …

埋点,自己写插件,自己写的按钮埋点,掘金同款投递简历

20分钟掌握 Vite 插件开发 - 掘金 vite的生命周期啥的 1.浏览器的控制台输出有样式的字 // const randomLetterPlugin ()>{ // const letters [wwwwwww,000000000000,888888888888]; // //随机获取一个字符并打印 // const printRandomLetter ()>{ // …

如何更好的管理个人财务?使用极空间部署私有记账系统Firefly III

如何更好的管理个人财务&#xff1f;使用极空间部署私有记账系统Firefly III 哈喽小伙伴们好&#xff0c;我是Stark-C~ 不知道屏幕前的各位“富哥”日常生活中是怎么管理自己巨额财富的&#xff0c;反正对于像我这样年薪过千的摸鱼族来说&#xff0c;请一个专业的理财顾问多多…

电子签名在人力资源中的应用:让HR工作更高效

人力资源&#xff08;HR&#xff09;行业是电子签领域的重要应用之一&#xff0c;它可以在以下场景中使用电子签&#xff1a; 1. 在招聘流程中&#xff0c;HR部门可以利用电子签名工具来完成与招聘候选人之间的任何文件签署操作。例如&#xff0c;维护人才库数据库、简历、面试…

世界读书日 | 开发者必读书单重磅来袭,华为云DTSE专家天团力荐

春色恰如许&#xff0c;读书正当时。 读书&#xff0c;就像解锁一把神秘钥匙&#xff0c;为开发者洞开新世界的大门&#xff0c;赋予他们破译复杂难题的能力、挑战未知领域的勇气。书页翻动间&#xff0c;开发者得以站在巨人的肩膀上&#xff0c;汲取前人经验&#xff0c;积蓄…

RANSAC 配准算法

RANSAC 配准算法 1. 简介2. RANSAC步骤3. RANSAC原理4. RANSAC的优缺点5. 代码实现6. 参考 1. 简介 先讲一下背景吧。 点云配准&#xff08;Point Cloud Registration&#xff09;指的是输入两幅点云 (source 和 target) &#xff0c;输出一个变换使得变换后的source和target…

管理 Python 项目的艺术:在 PyCharm 中使用虚拟环境(以BPnP为例)

在 PyCharm 中使用虚拟环境对于 Python 项目开发具有多方面的重要作用&#xff0c;这些作用体现在提升项目管理的效率、保障代码的可运行性以及维护项目的长期稳定性等方面。以下是使用虚拟环境的几个关键好处&#xff1a; 1. 依赖管理和隔离 虚拟环境允许每个项目拥有…

深度相机(3D相机)

传统的RGB彩色相机称为2D相机&#xff0c; 只能得到2D的图像信息&#xff0c; 无法得到物体与相机的距离信息&#xff0c;也就是深度信息。 顾名思义&#xff0c; 深度相机除了获取2D信息&#xff0c;还能得到深度信息&#xff0c;也叫RGBD相机&#xff0c; 或3D相机。 顺便提…

CSS介绍及三种应用方式[内联,内嵌,外链]元素及实例讲解

css介绍 CSS&#xff08;Cascading Style Sheets&#xff09;是一种用于描述HTML文档外观和格式的样式表语言。CSS允许开发者和设计师将网页的呈现&#xff08;布局、颜色、字体等&#xff09;与内容&#xff08;HTML&#xff09;分离开来&#xff0c;从而使得网页的设计更加灵…

vue2+vxe-table实现表格增删改查+虚拟滚动

vue2vxe-table实现表格增删改查虚拟滚动 使用的vxe-table版本&#xff1a;v3.x (vue 2.6 长期维护版) 完整代码 <template><div><vxe-toolbar ref"xToolbar" export :refresh"{query: findList}"><template #buttons><vxe-b…

vulhub weblogic全系列靶场

目录 简介 需要使用的工具 CVE-2017-10271 0x00 漏洞产生原因 0x01 影响范围 0x02 漏洞地址 0x03 环境 0x04 漏洞复现 1. 手工 2. 漏洞利用工具 CVE-2018-2628 0x00 漏洞产生原因 0x01 影响范围 0x02 环境 0x03 漏洞复现 1.nmap扫是否是T3协议 2.漏洞检测&…