LIUNX系统编程:信号(3)

目录

3.信号的处理

3.1信号是什么时候被处理的

read系统调用

3.2信号是怎样被处理的

内核态和用户态

 3.3操作系统是如何运行处理信号的呢?

中断技术

什么让操作系统运行起来的

3.4捕捉信号的其他方式

​编辑

demo代码


3.信号的处理

3.1信号是什么时候被处理的

信号在发送给进程之后不是立即处理的,而是等到合适的机会,在去处理信号的。

什么是合适的机会呢?

进程从内核态要切换回用户态时,会检测处理信号。

为什要内核态才能处理信号呢?

因为处理信号的时候一定会对内核数据结构做修改,就像在处理信号之前,要把pending表中信号对应的bit位置为0,然后去调用handler函数,处于用户态的时候是不允许让问内核数据的。

这里可能会有个问题,直接使用系统调用不就能对内核数据进行修改吗?还用上面说的来回切换多麻烦啊?

这是因为在执行系统调用的时候,也会切换到内核态的,举个例子。

read系统调用

1.将参数拷贝到内核

2.切换为内核态

3.在task_struct中找到文件描述符表。

4.访问0号fd的文件,将该文件的缓冲区拷贝到buffer中

5.将结果返回给用户。

6.返回用户态

信号的大致处理流程就是这样的。

但是自定义和默认处理方式流程是有区别的。

自定义处理:执行sighandler需要切换回用户态,去执行自定义的函数,然后返回内核态,内核态在返回运行结果给用户态。

默认处理:直接在内核态执行默认的sighandler函数,然后返回用户态即可。

 

3.2信号是怎样被处理的

内核态和用户态

进程的虚拟地址空间,分为用户区0-3g,和内核区3-4g,一共是4g。

这也就是为什么,进程总能找到操作系统,让操作系统替进程执行一些动作。

操作系统被映射到了,进程的地址空间内,经过mmu+页表将虚拟的地址转化为物理地址,就找到操作系统了。

内核级的页表只有一份,因为操作系统只有一个,操作系统的内核数据也只有一份,只需要一个内核级的页表,建立不同进程的虚拟地址到操作系统所处物理内存的映射,就可以让多个进程看到一个操作系统。

但是进程是有多个的,每个进程的数据也是不同的,这就需要不同的页表,来映射不同的进程。

 3.3操作系统是如何运行处理信号的呢?

首先呢操作系统是一个功能强大的傀儡,它没有自己的思想,得有人告诉操作系统要做什,它才会去做,不然操作系统什么都不会做。

中断技术

信号技术本质就是软件中断,软件中断就是对硬件中断的模拟。

 硬件中断:键盘直接连接到cpu的针脚上,当键盘输入的时候,会给对应的针脚一个高电频,cpu会拿着这个针脚的编号,去操作系统的中断向量表(函数指针数组),执行对应的函数。

软件中断:由软件产生一个中断信号,然后去操作系统的终端向量表,执行对应的函数。

重谈read方法

cs的寄存器的后两位是权限标识位。00代表是内核态,11代表用户态。

首先判断当前是不是用户态,是就把系统调用表中对应系统调用的编号放入eax寄存器中。

执行int 0x80指令陷入内核态,执行系统调用。

什么让操作系统运行起来的

操作系统是一个死循环,不断的接受其他外部的中断。

由一个硬件,向操作系统发送一个频率非常高,时间非常短的周期时钟中断,操作系统会拿着中断号去操作系统的中断向量表中,执行进程调度,内存管理,更新系统时间。。。任务。

3.4捕捉信号的其他方式

在处理信号的时候,会讲处理的信号屏蔽,防止一直接受同一个信号陷入循环。

参数:

signum是想要捕捉的信号,或者一些选项(不介绍)。

act:act是个结构体,含有一下内容。

        sa_handler是想要自定处理的函数

        sa_sigaction处理实时信号

        sa_mask除了屏蔽当前信号,还要屏蔽哪些信号。

        sa_flag是一些选项。

oldact:输出型参数,将原来信号的处理保存到oldact中。

demo代码

使用一下这个接口,屏蔽2号信号的同时屏蔽3,4,5号信号。

看下现象,运行起来的pending位图2,3,4,5的位置应该都是1。

验证

#include<signal.h>
#include<iostream>
#include<unistd.h>

void print(sigset_t &pending)
{
    for(int i = 31; i >= 1; i--)
    {
        if(sigismember(&pending,i))
        {
            std::cout<<"1";
        }
        else
        {
            std::cout<<"0";
        } 
    }
    std::cout<<std::endl;
}


void handler(int signo)
{
    //获取pending并打印
    sigset_t pending;
    sigemptyset(&pending);
    while(true)
    {
        sigpending(&pending);//获取pending位图
        print(pending);//打印pending
        sleep(1);
    }

}


int main()
{
    struct sigaction act,oact;
    act.sa_handler = handler;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);//初始化信号集
    sigaddset(&act.sa_mask,3);//在信号集中添加3号信号
    sigaddset(&act.sa_mask,4);
    sigaddset(&act.sa_mask,5);

    sigaction(2,&act,&oact);//捕捉信号
    while(true)
    sleep(1);
    return 0;
}

第一次kill-2让信号被捕捉,第二次就直接被阻塞在pending位图中。

kill -3 -4 -5每次pending位图对应的位置都会变为1.

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-06-07 22:58:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-07 22:58:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-07 22:58:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-07 22:58:03       20 阅读

热门阅读

  1. 2024全国高考作文题解读(Chat GPT 4.0版本)

    2024-06-07 22:58:03       11 阅读
  2. 使用Python的xml.etree.ElementTree模块解析XML文件

    2024-06-07 22:58:03       6 阅读
  3. 【C语言】动态内存管理技术文档

    2024-06-07 22:58:03       7 阅读
  4. AT_abc014_3 题解

    2024-06-07 22:58:03       9 阅读
  5. 如何在Python中处理时间和日期

    2024-06-07 22:58:03       6 阅读
  6. 深度解读 ChatGPT基本原理

    2024-06-07 22:58:03       9 阅读
  7. 驱动开发的分离与分层

    2024-06-07 22:58:03       7 阅读
  8. git使用

    git使用

    2024-06-07 22:58:03      9 阅读
  9. 「前端+鸿蒙」鸿蒙应用开发简介

    2024-06-07 22:58:03       9 阅读
  10. PyTorch使用tensorboard的SummaryWriter报错

    2024-06-07 22:58:03       11 阅读
  11. DeepSort整体流程梳理及匈牙利算法解析

    2024-06-07 22:58:03       12 阅读