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

系统调用sigaction的工作流程

系统调用 sigaction() 的工作流程本质是用户态程序通过内核接口,将信号处理规则(封装在 struct sigaction 中)注册到内核,内核根据规则管理信号的递送与处理。以下是其详细工作流程:

1. 前置条件:用户态准备信号处理配置

在调用 sigaction() 前,用户态程序需要完成:

  • 定义并初始化 struct sigaction 结构体,指定信号处理的核心参数:
    • 选择处理函数(_sa_handler 简单函数 或 _sa_sigaction 扩展函数);
    • 设置信号屏蔽集 sa_mask(处理期间需要屏蔽的信号);
    • 配置标志位 sa_flags(如 SA_SIGINFOSA_RESTART 等)。
  • 确定目标信号(如 SIGINTSIGTERM 等)。

2. 触发系统调用:从用户态进入内核态

用户态程序调用 sigaction() 函数( glibc 提供的封装函数),触发以下操作:

  • 参数校验:检查信号编号是否合法(如是否为 SIGKILLSIGSTOP,这两个信号无法自定义处理)、struct sigaction 指针是否有效。
  • 陷入内核:通过系统调用指令(如 x86 的 syscall)从用户态切换到内核态,内核会保存用户态上下文(如寄存器、栈指针)。

3. 内核处理:注册或查询信号处理规则

内核接收到 sigaction() 系统调用请求后,进入内核函数 sys_sigaction()(不同架构实现可能有差异),执行核心逻辑:

(1)查找信号对应的内核数据结构

内核为每个进程维护一个 struct task_struct 结构体(进程描述符),其中包含信号处理的关键信息:

  • struct k_sigaction sigaction[NSIG]:数组,每个元素对应一个信号的处理规则(内核态的信号配置,与用户态 struct sigaction 对应)。
  • 内核根据传入的 signum(信号编号),找到该进程 sigaction 数组中对应的条目。
(2)处理“设置新规则”(act 参数非 NULL 时)

若用户态传入了新的 struct sigactionact 非 NULL),内核会:

  • 校验处理函数合法性
    • 若使用 _sa_sigaction 扩展函数,需检查 sa_flags 是否包含 SA_SIGINFO 标志,否则返回错误。
    • 验证处理函数指针是否指向用户空间(避免恶意程序传入内核空间地址)。
  • 转换用户态配置到内核态
    将用户态 struct sigaction 中的信息(处理函数、sa_masksa_flags)拷贝到内核态的 struct k_sigaction 中(需处理指针地址转换,因为用户态与内核态地址空间独立)。
  • 特殊标志处理
    例如,若设置 SA_RESETHAND 标志,内核会记录“信号处理后恢复默认行为”;若设置 SA_NODEFER,则取消对当前信号的自动屏蔽。
(3)处理“保存旧规则”(oldact 参数非 NULL 时)

若用户态传入了 oldact 指针(用于保存旧配置),内核会:

  • 将该信号当前的内核态配置(struct k_sigaction)转换为用户态的 struct sigaction 格式。
  • 拷贝到用户态的 oldact 指针指向的内存中(需确保用户态内存可写)。

4. 内核返回:从内核态回到用户态

  • 清理与恢复:内核完成信号配置后,恢复用户态上下文(寄存器、栈等),从系统调用返回。
  • 返回值处理:若成功,返回 0;若失败(如信号不合法、参数错误),返回 -1 并设置 errno(如 EINVAL 表示信号无效)。

5. 后续:信号触发时的处理流程

sigaction() 调用完成后,内核已记录该信号的处理规则。当信号触发时(如用户按 Ctrl+C 产生 SIGINT),内核会:

  1. 检查该信号是否被屏蔽(通过进程的信号屏蔽集 blocked),若未屏蔽则准备递送。
  2. 根据 sigaction 数组中记录的规则:
    • 若处理函数是用户自定义函数,内核会创建临时栈帧,切换到用户态执行该函数。
    • 执行期间,自动屏蔽 sa_mask 中指定的信号,避免干扰。
    • 若设置了 SA_RESTART,函数执行后会重启被信号中断的系统调用(如 readsleep)。

总结

sigaction() 系统调用的核心流程是:
用户态准备配置 → 陷入内核 → 内核校验并更新信号处理规则 → 返回用户态
其本质是用户程序向内核“注册”信号处理逻辑,后续信号的触发与处理则完全由内核根据注册的规则执行,体现了 Linux 中“用户态定义规则,内核负责执行”的信号处理模型。

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

相关文章:

  • 算法训练之队列和优先级队列
  • Ubuntu 24.04 适配联发科 mt7902 pcie wifi 网卡驱动实践
  • MySQL的存储引擎:
  • C/C++内存管理函数模板
  • Flutter开发 页面间的值传递示例
  • 基于C语言(兼容C++17编译器)的记账系统实现
  • 虚拟机安装 爱快ikuai 软路由 浏览器无法访问/拒绝连接
  • 数据库面试题集
  • Effective C++ 条款34:区分接口继承和实现继承
  • 数据结构(17)排序(下)
  • 深度剖析 P vs NP 问题:计算领域的世纪谜题
  • Graham 算法求二维凸包
  • PG靶机 - Resourced
  • 【51单片机按键闪烁流水灯方向】2022-10-26
  • 【LeetCode】102 - 二叉树的层序遍历
  • MVC结构变种——第三章核心视图及控制器的整体逻辑
  • idea中使用maven造成每次都打印日志
  • matlab实现随机森林算法
  • [SUCTF 2019]Pythonginx
  • JS中typeof与instanceof的区别
  • 【精彩回顾·成都】成都 User Group×柴火创客空间:开源硬件驱动 AI 与云的创新实践!
  • JS 注释类型
  • ADK[3]历史对话信息保存机制与构建多轮对话机器人
  • scanpy单细胞转录组python教程(四):单样本数据分析之降维聚类及细胞注释
  • 【Canvas与戳记】黑底金Z字
  • 正确使用SQL Server中的Hint(10)— 常用Hint(2)
  • Spring WebSocket安全认证与权限控制解析
  • 研究揭示 Apple Intelligence 数据处理中可能存在隐私漏洞
  • 【redis初阶】------List 列表类型
  • 通过脚本修改MATLAB的数据字典