当前位置: 首页 > news >正文

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

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

本文内容参考:

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函数的第1步,本回继续解析后续内容。为了便于理解和回顾,再次贴出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;
}

complete_signal函数分为以下步骤:

1)查找一个可以处理信号的进程

2)发现了一个可杀死的线程。如果信号是致命的,那么立即开始关闭整个线程组

代码片段如下:

	/** 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;}}

如果信号属于sig_fatal,并且满足&&后边的一系列条件,则在信号不属于sig_kernel_coredump的情况下,发送SIGKILL到线程组中的每一个线程,整个组退出。

哪些信号属于sig_fatal即致命信号呢?1)信号不属于sig_kernel_ignore;2)信号不属于sig_kernel_stop;3)信号的处理方式是SIG_DFL。也就是说,默认行为是terminate,且用户未改变处理方式的信号。

这里顺带提一下:kill不能发送信号到指定线程,但pthread_kill可以。它是通过tgkill系统调用实现的,和kill不同的是,它调用do_send_sig_info时传递的type参数为PIDTYPE_PID。

3)唤醒步骤1)中找到的可以处理信号的进程或线程

代码片段如下:

	/** 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);

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函数的解析,请看下回。

http://www.dtcms.com/a/328547.html

相关文章:

  • 深度学习-卷积神经网络-NIN
  • 数据结构:后缀表达式:结合性 (Associativity) 与一元运算符 (Unary Operators)
  • Linux软件编程(三)文件操作-文件 I/O
  • 笔试——Day36
  • Linux应用软件编程---文件操作3(文件IO及其指令、文件定位函数lseek、文件IO与标准IO的比较、缓冲区)
  • archlinux中VLC无法播放视频的解决办法
  • 【Datawhale夏令营】多模态RAG学习
  • 关于Linux编程3:fread/fwrite/流的定位/文件IO
  • 存储过程作为系统逻辑核心的架构思考 —— 以 SaaS 系统为例
  • 电商双 11 美妆数据分析:从数据清洗到市场洞察
  • 生产环境中Kubernetes Pod 安全上下文与策略的实战经验分享
  • nt!MmCreatePeb函数分析之peb中OSMajorVersion的由来
  • Flutter ExpansionPanel组件(可收缩的列表)
  • 【入门系列】图像算法工程师如何入门计算机图形学?
  • 数据分析基本内容(第二十节课内容总结)
  • MCU外设初始化:为什么参数配置必须优先于使能
  • redis的过期策略和定时器
  • 支持任意 MCP 协议的客户端
  • SQL180 每类试卷得分前3名
  • Mybatis源码解读-Plugin插件源码
  • (C++)继承全解析及运用
  • Labelme从安装到标注:零基础完整指南
  • MySQL基础面试
  • Springboot整合Thrift
  • 移动端网页调试实战,键盘弹出与视口错位问题的定位与优化
  • 汉高携手SAP推出AI驱动的退换货与争议管理解决方案
  • 赛灵思ZYNQ官方文档UG585自学翻译笔记:UART Controller,通用异步收发传输器控制器
  • Vue接口平台十三——测试记录
  • Ubuntu 全盘备份
  • 九尾狐未来机械晶核技术