Linux内核进程管理子系统有什么第二十七回 —— 进程主结构详解(23)

接前一篇文章:Linux内核进程管理子系统有什么第二十六回 —— 进程主结构详解(22)

本文内容参考:

Linux内核进程管理专题报告_linux rseq-CSDN博客

《趣谈Linux操作系统 核心原理篇:第三部分 进程管理》—— 刘超

《图解Linux内核 基于6.x》 —— 姜亚华 机械工业出版社

特此致谢!

进程管理核心结构 —— task_struct

3. 信号处理相关成员

上一回继续讲解task_struct结构中信号处理相关的成员,包括:

	/* Signal handlers: */
	struct signal_struct		*signal;
	struct sighand_struct __rcu		*sighand;
	sigset_t			blocked;
	sigset_t			real_blocked;
	/* Restored if set_restore_sigmask() was used: */
	sigset_t			saved_sigmask;
	struct sigpending		pending;
	unsigned long			sas_ss_sp;
	size_t				sas_ss_size;
	unsigned int			sas_ss_flags;

上一回沿以下路径深入跟进:

do_send_sig_info函数   --->

    send_signal_locked函数   --->

        __send_signal_locked函数   --->

            complete_signal函数

讲到了__send_signal_locked函数的最后一步 —— complete_signal函数。

(6)调用complete_signal函数查找一个处理信号的进程(线程)

上一回解析到了complete_signal函数的第3步即最后一步,本回详细解析此步骤具体内容。为了便于理解和回顾,再次贴出complete_signal函数源码,在同文件(kernal/signal.c)中,如下:

static void complete_signal(int sig, struct task_struct *p, enum pid_type type)
{
	struct signal_struct *signal = p->signal;
	struct task_struct *t;
 
	/*
	 * Now find a thread we can wake up to take the signal off the queue.
	 *
	 * If the main thread wants the signal, it gets first crack.
	 * Probably the least surprising to the average bear.
	 */
	if (wants_signal(sig, p))
		t = p;
	else if ((type == PIDTYPE_PID) || thread_group_empty(p))
		/*
		 * There is just one thread and it does not need to be woken.
		 * It will dequeue unblocked signals before it runs again.
		 */
		return;
	else {
		/*
		 * Otherwise try to find a suitable thread.
		 */
		t = signal->curr_target;
		while (!wants_signal(sig, t)) {
			t = next_thread(t);
			if (t == signal->curr_target)
				/*
				 * No thread needs to be woken.
				 * Any eligible threads will see
				 * the signal in the queue soon.
				 */
				return;
		}
		signal->curr_target = t;
	}
 
	/*
	 * Found a killable thread.  If the signal will be fatal,
	 * then start taking the whole group down immediately.
	 */
	if (sig_fatal(p, sig) &&
	    (signal->core_state || !(signal->flags & SIGNAL_GROUP_EXIT)) &&
	    !sigismember(&t->real_blocked, sig) &&
	    (sig == SIGKILL || !p->ptrace)) {
		/*
		 * This signal will be fatal to the whole group.
		 */
		if (!sig_kernel_coredump(sig)) {
			/*
			 * Start a group exit and wake everybody up.
			 * This way we don't have other threads
			 * running and doing things after a slower
			 * thread has the fatal signal pending.
			 */
			signal->flags = SIGNAL_GROUP_EXIT;
			signal->group_exit_code = sig;
			signal->group_stop_count = 0;
			t = p;
			do {
				task_clear_jobctl_pending(t, JOBCTL_PENDING_MASK);
				sigaddset(&t->pending.signal, SIGKILL);
				signal_wake_up(t, 1);
			} while_each_thread(p, t);
			return;
		}
	}
 
	/*
	 * The signal is already in the shared-pending queue.
	 * Tell the chosen thread to wake up and dequeue it.
	 */
	signal_wake_up(t, sig == SIGKILL);
	return;
}

signal_wake_up函数在include/linux/sched/signal.h中,代码如下:

static inline void signal_wake_up(struct task_struct *t, bool fatal)
{
	unsigned int state = 0;
	if (fatal && !(t->jobctl & JOBCTL_PTRACE_FROZEN)) {
		t->jobctl &= ~(JOBCTL_STOPPED | JOBCTL_TRACED);
		state = TASK_WAKEKILL | __TASK_TRACED;
	}
	signal_wake_up_state(t, state);
}

signal_wake_up函数在得到了t->jobctl和state的值之后,将实际工作交给了signal_wake_up_state函数。其在kernel/signal.c中,代码如下:

/*
 * Tell a process that it has a new active signal..
 *
 * NOTE! we rely on the previous spin_lock to
 * lock interrupts for us! We can only be called with
 * "siglock" held, and the local interrupt must
 * have been disabled when that got acquired!
 *
 * No need to set need_resched since signal event passing
 * goes through ->blocked
 */
void signal_wake_up_state(struct task_struct *t, unsigned int state)
{
	lockdep_assert_held(&t->sighand->siglock);

	set_tsk_thread_flag(t, TIF_SIGPENDING);

	/*
	 * TASK_WAKEKILL also means wake it up in the stopped/traced/killable
	 * case. We don't check t->state here because there is a race with it
	 * executing another processor and just now entering stopped state.
	 * By using wake_up_state, we ensure the process will wake up and
	 * handle its death signal.
	 */
	if (!wake_up_state(t, state | TASK_INTERRUPTIBLE))
		kick_process(t);
}

signal_wake_up_state函数中主要做了两件事情:

1)给这个线程设置TIF_SIGPENDING标志(位)

代码片段如下:

	set_tsk_thread_flag(t, TIF_SIGPENDING);

从这一点就可以看出,其实信号的处理采取的是和进程的调度是类似的机制(进程调度的机制后文书会详细讲解),即:当信号到来的时候,并不直接处理这个信号,而是设置一个标志位TIF_PENDING,以标识(记录)已经有信号等待处理。与进程调度类似,在系统调用结束、或者中断处理结束,从内核态返回用户态的时候,再进行信号的处理。

2)试图唤醒这个进程或者线程

代码片段如下:

	/*
	 * TASK_WAKEKILL also means wake it up in the stopped/traced/killable
	 * case. We don't check t->state here because there is a race with it
	 * executing another processor and just now entering stopped state.
	 * By using wake_up_state, we ensure the process will wake up and
	 * handle its death signal.
	 */
	if (!wake_up_state(t, state | TASK_INTERRUPTIBLE))
		kick_process(t);

wake_up_state函数在kernel/sched/core.c中,代码如下:

int wake_up_state(struct task_struct *p, unsigned int state)
{
	return try_to_wake_up(p, state, 0);
}

try_to_wakeup函数在后文书会详细讲解,这里先大概知道其功能即可。try_to_wakeup函数将进程或线程设置为TASK_RUNNING,然后放在运行队列中。后续随着时钟不断地滴答(tick),迟早会被调用。

回到signal_wake_up_state函数中。如果wake_up_state函数即try_to_wake_up函数返回0,则说明进程或线程已经处于TASK_RUNNING状态了。如果它在另外一个CPU上运行,则调用kill_process函数发送一个处理器间中断,强制该进程或线程重新调度。重新调度完毕后,会返回用户态执行(此时是一个检查TIF_SIGPENDING标志的时机)。

至此,complete_signal函数就讲解完了。以下路径也就解析完了:

do_send_sig_info函数   --->

    send_signal_locked函数   --->

        __send_signal_locked函数   --->

            complete_signal函数

信号处理流程的第2步 —— 发送信号以及整体信号处理流程也就总体上讲完了。

下一回结合此整体流程,对于task_struct结构中的相关成员进行讲解。

标题基于SpringBoot的在线网络学习平台研究AI更换标题第1章引言介绍基于SpringBoot的在线网络学习平台的研究背景、意义、国内外现状、论文研究方法及创新点。1.1研究背景与意义阐述在线网络学习平台的重要性及其在教育领域的应用价值。1.2国内外研究现状分析当前国内外在线网络学习平台的发展状况及趋势。1.3研究方法与创新点说明本研究采用的方法论和在研究过程中的创新之处。第2章相关理论技术概述SpringBoot框架、在线教育理论及相关技术基础。2.1SpringBoot框架概述介绍SpringBoot框架的特点、优势及其在Web应用中的作用。2.2在线教育理论阐述在线教育的基本理念、教学模式及其与传统教育的区别。2.3相关技术基础介绍开发在线网络学习平台所需的关键技术,如前端技术、数据库技术等。第3章在线网络学习平台设计详细描述基于SpringBoot的在线网络学习平台的整体设计方案。3.1平台架构设计给出平台的整体架构图,并解释各个模块的功能及相互关系。3.2功能模块设计详细介绍平台的要功能模块,如课程管理、用户管理、在线考试等。3.3数据库设计说明平台的数据库设计方案,包括数据表结构、数据关系等。第4章平台实现与测试阐述平台的实现过程及测试方法。4.1平台实现详细介绍平台的开发环境、开发工具及实现步骤。4.2功能测试对平台的要功能进行测试,确保功能正常且符合预期要求。4.3性能测试对平台的性能进行测试,包括响应时间、并发用户数等指标。第5章平台应用与分析分析平台在实际应用中的效果及存在的问题,并提出改进建议。5.1平台应用效果介绍平台在实际教学中的应用情况,包括用户反馈、使用情况等。5.2存在问题及原因分析分析平台在运行过程中出现的问题及其原因,如技术瓶颈、用户体验等。5.3改进建议与措施针对存在的问题提出具体的改进建议和措施,以提高平台的性能和用户满意度
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝天居士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值