[Linux][进程信号][一][信号基础][如何产生信号]详细解读

发布于:2024-04-23 ⋅ 阅读:(24) ⋅ 点赞:(0)


0.前言预备

1.系统定义的信号列表

  • **[1, 31]:**普通信号

  • **[34, 64]:**实时信号
    请添加图片描述

  • 这些信号在什么条件下产生,默认的处理动作是什么,可以通过 man 7 signal 查看
    请添加图片描述

2.核心转储 – Core Dump

  • 当一个进程要异常终止时,可以选择把当前进程在内存中的相关核心数据转存到磁盘上,文件名通常是core,这叫做Core Dump
  • 进程异常终止通常是因为有Bug,事后可以用调试器检查core文件以查清错误原因,这叫做Post-mortem Debug(事后调试)
    • 使用:core -file core.pid
  • 默认是不允许产生core文件的,因为core文件中可能包含用户密码等敏感信息,不安全
    • 一个进程允许产生多大的core文件取决于进程的Resource Limit(这个信息保存在PCB中)
    • 在开发调试阶段可以用ulimit命令改变这个限制,允许产生core文件
      • ulimit -a
      • ulimit -c
      • 当前bash会话有效
        请添加图片描述

1.信号基础

1.信号概念

  • 信号是进程之间事件异步通知的一种方式,属于软中断
    • 本质是一种通知机制
  • 理解信号思路
    • 进程要处理信号,必须具备信号"识别"能力(看到 + 处理动作)
    • 进程为什么能够"识别"信号?
      • 程序员通过代码提前设置好的
    • 信号产生是随机的,进程可能正在忙自己的事情
      • 信号可能后续被处理,不一定是立即处理
    • 信号会临时的记录下对应的信号,方便后续进行处理
      • 何时处理?
        • 合适的时候
    • 一般而言,信号的产生相对于进程而言是异步的

2.信号处理方式概览

  • 执行该信号的默认处理动作
  • 忽略此信号
  • 自定义动作(捕捉信号)
    • 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数
  • 信号捕捉初识
    • **功能:**捕获特定的信号,执行自定的方法
    • 原型:sighandler_t signal(int signum, sighandler_t handler);
    • 参数:
      • **signum:**要捕获的信号
      • **handler:**函数指针,要执行的自定方法
    • 返回值:
      • 不在乎
    • 注意:
      • signal函数,仅仅是修改进程对特性信号的后续处理动作,不是直接调用对应的处理动作
      • 如果后续没有任何SIGNAL信号产生,handler永远不会被调用

3.理解信号如何被保存

  • 需要解决两个问题 --> 什么信号?是否产生?
  • 进程PCB内部保存了**信号位图**字段
    • 第几个比特位表示什么信号
    • 01表示是否产生信号

4.信号发送的本质

  • 信号位图在task_struct --> task_struct内核数据结构 --> OS掌控
  • 信号发送的本质:OS向目标进程写信号,OS直接修改PCB中的指定的位图结构,完成"发送"信号的过程

2.如何产生信号?

1.终端按键产生信号

  • 键盘的工作方式是通过中断方式进行的
    • 便可以**识别组合键,**如Ctrl + c
  • OS解释组合键 --> 查找进程列表 --> 找到前台运行的进程 --> OS写入对应的信号到进程内部的位图结构中

2.系统调用接口

1.kill()

  • **功能:**给指定的进程发送指定的信号
  • 原型:int kill(pid_t pid, int sig);

2.raise()

  • **功能:**给当前进程发送指定的信号 --> 自己给自己发信号
  • 原型:int raise(int sig);

3.abort()

  • **功能:通常用来终止进程,发送SIGABRT(6)**信号
  • 原型:void abort(void);

4.如何理解?

  • 用户调用系统接口 --> 执行OS对应的系统调用代码 --> OS提取参数,或者设置特定的数值 --> OS****向目标进程写信号 --> 修改对应进程的信号标记位 --> 进程后续会处理信号 --> 执行对应的处理动作

3.由软件条件产生信号

  • 如:管道读端不光不读,而且还关闭了,写端一直在写,会发生什么问题?
    • 写没有意义,OS会自动终止对应的写端进程,通过发送信号(SIGPIPE)的方式
  • 如:alarm() && SIGALRM
    • 功能:
      • 设定一个闹钟,告诉内核在seconds秒之后给当前进程发SIGALRM信号,该信号的默认处理动作是终止当前进程
      • 闹钟一旦触发,就自动移除了
  • 原型:unsigned int alarm(unsigned int seconds);
  • 返回值:
    • 0
    • 以前设定的闹钟时间还余下的秒数
  • 如何理解?
    • OS先识别到某种软件条件触发或不满足某条件 --> OS构建信号,发送给指定的进程

4.硬件异常产生信号

  • 硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号
    • 例如:当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程
    • 例如:当前进程访问了非法内存地址,,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程
  • 由此看出,在C/C++中,除零,内存越界等异常,在系统层面上,是被当成信号处理的

5.总结

  • 所有的信号,有他的来源,但最终全部都是被OS识别,解释,并发送的