Linux task_struct信号处理与sigpending组织
Linux task_struct信号处理与sigpending组织struct task_struct中信号相关字段分布在多个cache line上直接决定信号投递路径的缓存行为。task_struct-pending是进程级挂起信号集合类型为struct sigpending内部包含一个sigset_t signal64位系统上为两个unsigned long和一个struct list_head list链式队列。thread group共享的signal_struct-shared_pending则存放需要广播到整个线程组的挂起信号。cstruct sigpending {struct list_head list;sigset_t signal;};struct task_struct {/* ... */struct sigpending pending; /* 进程私有挂起信号 *//* ... */struct signal_struct *signal; /* 指向共享的thread group信号描述符 *//* ... */unsigned int siginfo_try_wait:1;unsigned int siginfo_try_wait_seen:1;/* ... */};信号投递入口为__send_signal_locked()。该函数首先判断目标tgid是否等于当前pid——即进程自身发信号——若是则直接写入current-pending否则调用__sigqueue_alloc()分配一个struct sigqueue节点插入目标task-pending.list同时设置pending.signal中对应的bit。这里存在一个关键竞态如果目标进程正在执行do_exit()释放signal_struct__sigqueue_alloc()可能看到的是已置SIGNAL_GROUP_EXIT标志的signal_struct此时必须放弃投递。cstatic int __send_signal_locked(int sig, struct kernel_siginfo *info,struct task_struct *t, bool group, bool force){struct sigpending *pending;struct sigqueue *q;int override_rlimit;int ret 0;pending group ? t-signal-shared_pending : t-pending;if (unlikely(!t-signal)) /* 目标进程正在exit */return -ESRCH;/** 快速路径实时信号或非实时信号忽略rlimit检查* 对于sigqueue溢出场景重试一次后丢信号*/override_rlimit (sig SIGRTMIN) || sig SIGKILL || sig SIGSYS;if (!override_rlimit !sigismember(t-signal-rlim[RLIMIT_SIGPENDING].rlim_cur)) {if (t-signal-nr_queued t-signal-rlim[RLIMIT_SIGPENDING].rlim_cur) {ret -EAGAIN;goto out;}}q __sigqueue_alloc(sig, t, GFP_ATOMIC, override_rlimit, 0);if (q) {list_add_tail(q-list, pending-list);sigaddset(pending-signal, sig);} else if (!is_si_special(info)) {/* 分配失败且不是特殊info丢弃信号 */ret -ENOMEM;goto out;}/* 非实时信号相同sig只保留一个sigqueue丢弃后续重复 */if (sig SIGRTMIN) {struct sigqueue *first list_first_entry_or_null(pending-list, typeof(*first), list);while (first first-info.si_signo sig first ! q) {list_del(first-list);__sigqueue_free(first);first list_first_entry_or_null(pending-list, typeof(*first), list);}}complete_signal(sig, t, group);out:return ret;}信号递送路径complete_signal()的关键决策是选择投递目标线程。对于SIGKILL或SIGSTOP这类终止类信号直接标记整个thread group后唤醒所有TASK_INTERRUPTIBLE状态的成员对于其他信号优先选择当前正在运行的线程通过sigismember(t-signal-curr_target-pending.signal若不可用则遍历thread group找第一个不阻塞该信号的线程。选中的线程通过signal_wake_up()置TIF_SIGPENDING标志然后视当前cpu是否为目标cpu决定是否需要reschedule IPI。cstatic void complete_signal(int sig, struct task_struct *p, enum pid_type type){struct signal_struct *signal p-signal;struct task_struct *t;if (unlikely(sig SIGKILL || sig SIGSTOP)) {/* 终止类信号直接广播 */__for_each_thread(signal, t)signal_wake_up(t, sig SIGKILL);return;}/* 找不阻塞该信号的目标线程 */t signal-curr_target;while (!sigismember(t-blocked, sig)) {t next_thread(t);if (t signal-curr_target)break; /* 所有线程都阻塞 */}if (t-flags PF_EXITING)t p; /* 目标在exit退回发信号者 */signal_wake_up(t, 0);}另一个关键路径是从user mode返回内核时调用do_signal()。entry_SYSCALL_64后检查thread_info-flags的_TIF_SIGPENDING位若置位则跳转至do_notify_resume()再进入do_signal()。这里使用get_signal()从pending链表中逐一取出struct ksignal判断sa_handler是否为SIG_IGN或SIG_DFL对于SIG_IGN直接丢弃信号不计入signal_struct-nr_queues对于SIG_DFL则执行默认动作如do_group_exit()。标准信号1-31在pending.signal中只保留一个bit但list上仍可能有多个sigqueue节点——list遍历时必须通过info.si_signo匹配真实的信号编号。cvoid get_signal(struct ksignal *ksig){struct task_struct *tsk current;struct signal_struct *signal tsk-signal;int sig;for (;;) {sig dequeue_signal(tsk, tsk-blocked, ksig-info);if (!sig)break; /* 所有信号处理完毕 */if (sigismember(tsk-real_blocked, sig))continue; /* 被real_blocked二次屏蔽 */ksig-sig sig;/* ka缓存了handler和flags */if (ksig-ka-sa.sa_handler SIG_IGN) {continue; /* 直接吞掉 */}if (ksig-ka-sa.sa_handler SIG_DFL) {switch (sig) {case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:continue; /* 默认忽略 */case SIGTSTP: case SIGTTIN: case SIGTTOU:do_signal_stop(sig);goto relock;case SIGSTOP:do_signal_stop(sig);goto relock;case SIGKILL:do_group_exit(SIGKILL);default:break;}}return; /* 返回用户信号处理函数 */}/* 所有信号已耗尽清理TIF_SIGPENDING */clear_tsk_thread_flag(tsk, TIF_SIGPENDING);}dequeue_signal()的实现需要同时扫描task-pending和signal-shared_pending两个队列并且必须保持一致性——先取shared_pending再取私有pending中间不能存在抢锁窗口。内部的collect_signal()负责从list头摘取匹配sig的sigqueue节点如果list为空则清除对应的pending.signal bit。实时信号SIGRTMIN保证sigqueue的数量不压缩32个实时信号每个都可以独立排队非实时信号在投递时就做了重复合并所以dequeue时一个信号至多对应一个sigqueue。结构布局上的一个陷阱struct task_struct的pending字段和blocked字段分散在不同的cache line上signal_wake_up()写task-pending时不会invalid目标cpu上blocked字段的cache line。但get_signal()读blocked时若与complete_signal()并发由于二者均持有siglock写者通过siglock的release语义保证了读者能看到完整的pending.signal集合。然而在siglock未持有的检查路径如signal_pending()中只读取TIF_SIGPENDING位而不访问sigpending本体这是安全的——因为TIF_SIGPENDING的set/clear永远在siglock保护下进行。

相关新闻

Linux tc filter_classify分类器链匹配与action执行

Linux tc filter_classify分类器链匹配与action执行

Linux tc filter_classify分类器链匹配与action执行TC(Traffic Control)分类器链的核心入口是filter_classify函数,它遍历挂在qdisc或clas上的filter链,逐一调用每个filter的classify回调进行匹配判决。filter_classify定义在net/…

2026/9/13 13:37:22 阅读更多 →
5个实用技巧:轻松掌握iCloud照片批量下载神器

5个实用技巧:轻松掌握iCloud照片批量下载神器

5个实用技巧:轻松掌握iCloud照片批量下载神器 【免费下载链接】icloud_photos_downloader A command-line tool to download photos from iCloud 项目地址: https://gitcode.com/GitHub_Trending/ic/icloud_photos_downloader 你是否曾经担心iCloud中的珍贵照…

2026/9/15 6:19:20 阅读更多 →
高效API测试与调试神器:Restfox深度解析与实战指南

高效API测试与调试神器:Restfox深度解析与实战指南

高效API测试与调试神器:Restfox深度解析与实战指南 【免费下载链接】Restfox Offline-First Minimalistic HTTP & Socket Testing Client for the Web & Desktop 项目地址: https://gitcode.com/gh_mirrors/re/Restfox Restfox是一款专为现代开发者设…

2026/9/20 5:03:21 阅读更多 →

最新新闻

GpuMall 的 cog-face-to-many 部署教程,这次让 Codex 走 TaoToken 核对 8188 端口与 Queue Prompt

GpuMall 的 cog-face-to-many 部署教程,这次让 Codex 走 TaoToken 核对 8188 端口与 Queue Prompt

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 23:55:59 阅读更多 →
Draft.js AtomicBlockUtils 完全指南:在编辑器中插入与移动原子块(Atomic Block)

Draft.js AtomicBlockUtils 完全指南:在编辑器中插入与移动原子块(Atomic Block)

Draft.js AtomicBlockUtils 完全指南:在编辑器中插入与移动原子块(Atomic Block) 【免费下载链接】draft-js A React framework for building text editors. 项目地址: https://gitcode.com/gh_mirrors/dr/draft-js AtomicBlockUtils …

2026/9/20 23:55:58 阅读更多 →
Ray 分布式 multiprocessing.Pool:用一行 import 将 Python 多进程程序扩展到集群

Ray 分布式 multiprocessing.Pool:用一行 import 将 Python 多进程程序扩展到集群

Ray 分布式 multiprocessing.Pool:用一行 import 将 Python 多进程程序扩展到集群 【免费下载链接】ray Ray is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads. 项目地址: https:/…

2026/9/20 23:55:58 阅读更多 →
Hero 开源库 CHANGELOG 深度解读:从 1.3.0 到 1.6.3 的版本演进与核心源码实现

Hero 开源库 CHANGELOG 深度解读:从 1.3.0 到 1.6.3 的版本演进与核心源码实现

Hero 开源库 CHANGELOG 深度解读:从 1.3.0 到 1.6.3 的版本演进与核心源码实现 【免费下载链接】Hero Elegant transition library for iOS & tvOS 项目地址: https://gitcode.com/gh_mirrors/he/Hero Hero 是面向 iOS 与 tvOS 的优雅转场动画库&#xf…

2026/9/20 23:55:58 阅读更多 →
grok-build v0.2.87 版本解读:自动订阅升级、/docs 导航与按模型推理强度配置

grok-build v0.2.87 版本解读:自动订阅升级、/docs 导航与按模型推理强度配置

grok-build v0.2.87 版本解读:自动订阅升级、/docs 导航与按模型推理强度配置 【免费下载链接】grok-build SpaceXAIs coding agent harness and TUI. Fullscreen, mouse interactive, extensible. 项目地址: https://gitcode.com/gh_mirrors/gr/grok-build …

2026/9/20 23:55:58 阅读更多 →
Atlas 300V 24G部署YOLOv5全流程:昇腾推理加速卡实战指南

Atlas 300V 24G部署YOLOv5全流程:昇腾推理加速卡实战指南

Atlas这个词,做AI模型部署的人这两年应该不陌生。它不是一个单一的硬件,而是华为昇腾整个AI计算平台的代号,从边缘小盒子到服务器推理卡都有覆盖。我手头这块Atlas 300V 24G,就是一张非常典型的PCIe形态AI推理加速卡,常…

2026/9/20 23:54:58 阅读更多 →

日新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →