【Linux】详解用户态和内核态&&内核中信号被处理的时机&&sigaction信号自定义处理方法

简介: 【Linux】详解用户态和内核态&&内核中信号被处理的时机&&sigaction信号自定义处理方法

一、用户态和内核态的理解

       在操作系统中,用户态和内核态是两种主要的执行模式,它们代表了不同的访问级别和权限,用于确保系统的安全和稳定性。

1.1、用户态

       用户态是操作系统中用户进程的运行状态。在这种状态下,进程只能访问受限的系统资源,并且不能执行某些特权操作。用户态下的进程没有权限直接访问硬件或执行某些敏感的系统调用。它们必须通过系统调用接口来请求内核态的服务。

1.2、内核态

      内核态是操作系统的核心部分(即内核)的运行状态。在这种状态下,代码可以访问系统内的所有内存空间,并且可以执行特权指令。内核态下的代码具有最高级别的权限,可以访问硬件、执行敏感操作,并管理系统资源。

1.3、用户态和内核态的切换时机

       当用户态下的进程需要执行特权操作时,它会通过系统调用接口向内核发出请求。这时,操作系统会保存用户态的上下文,然后切换到内核态来执行相应的服务。除了系统调用外,如硬件中断、软件异常也会导致系统从用户态切换到内核态。在这三种情况下,操作系统都会保存用户态的上下文,并在内核态下处理这些事件。

二、信号被处理的时机

      如下图所示,进程从内核态切换回用户态的时候,信号会被检测并处理。如果该信号的处理方法为默认处理方法,就不需要从内核态切换回用户态来处理我们写的方法,但如果该信号的处理方法为我们自己的自定义处理方法,就要从内核态切换回用户态来执行,执行完毕程序再进入内核。下面是进程处理信号并执行我们写的自定义处理方法的过程:

       执行信号自定义的处理方法时,可以由操作系统直接帮我们做了,但是为了避免我们写的处理方法存在非法操作,就必须切换回用户态, 由用户态的权限来约束我们是否能执行这个处理方法

三、用户态和内核态切换的内核级理解

在我们的进程地址空间中存在1G的内核空间,这部分会用来映射加载到内存中的操作系统。

        在内核中,所有的系统调用函数其实是被用一个函数指针数组所管理起来的,该函数指针数组会通过页表的映射与1G的内核空间的某些虚拟地址建立起映射关系,这样当正文代码部分要调用某个系统调用函数时,只需要拿着虚拟地址在内核空间中寻找再通过页表的映射就可以在内存中找到该系统调用函数。

       在系统中会存在多个进程,每个进程的地址空间的[0,3G]的地址空间映射的内容都不相同,但是,每个进程都要进行系统调用 ,也就意味着地址空间中的1G内核级空间所映射的内容可以完全相同。进一步说,我们的进程无论如何总能找到操作系统,我们的进程访问操作系统,都是通过进程地址空间中[3GB,4GB]这一部分空间来访问的。

       既然操作系统已经被映射到我们进程的地址空间上,那是否意味着我们可以随便访问操作系统中的内容了呢?答案肯定不是的。在CPU中有寄存器可以标识当前进程的状态(比如说00就表示处于用户态,11就表示处于内核态),如果进程处于用户态就阻止进程访问操作系统

四、设置自定义信号处理的函数

设置自定义信号处理的函数除了signal函数外,还有一个sigaction函数。

      第一个参数为几号信号,第二个参数为一个描述新方法的结构体, 第三个参数为一个描述旧方法的结构体。

       该结构体中第一个成员变量为新设置的信号处理方法,第二个参数为类似于sa_handler,但它提供了更强大的功能,因为该函数还可以接收有关信号发送者的信息,可以设置为nullptr,第三个参数为一个信号集,可以用来设置在处理signum信号的同时所屏蔽的信号,第四个参数用于修改信号处理的某些默认行为,第五个参数通常不用于现代操作系统,不设置。 下面是一个sigaction函数使用的例子。

自定义2号信号的处理方法,让进程不断打印pending位图:

#include <iostream>
#include <signal.h>
#include <unistd.h>
using namespace std;
 
void print(sigset_t& pending)
{
    for(int i = 31; i>= 1; i--)
    {
        if(sigismember(&pending, i))
            cout << "1";
        else
            cout << "0";
    }
    cout << endl;
}
 
//自定义2号信号的处理方法,让进程不断打印pending位图
void handler(int sig)
{
    sigset_t pending;
    sigemptyset(&pending);
 
    while(true)
    {
        sigpending(&pending);
        print(pending);
        sleep(1);
    }
}

再让进程收到2号信号的同时阻塞3,4,5号信号:

int main()
{
    struct sigaction act,oact;
    act.sa_handler = handler;
    act.sa_flags = 0;
 
    cout << getpid() << endl;
 
    //清空要添加的信号集
    sigemptyset(&act.sa_mask);
    //让进程收到2号信号的同时阻塞3,4,5号信号
    sigaddset(&act.sa_mask, 3);
    sigaddset(&act.sa_mask, 4);
    sigaddset(&act.sa_mask, 5);
 
    sigaction(2, &act, &oact);
 
    while(true)
    {}
    return 0;
}

最终运行结果:

       第一次给进程发送2号信号,信号被执行了所以pending位图中没有2号信号,再次发送2号信号发现pending位图中有2号信号,证明2号信号被屏蔽了,因为进程在处理某个信号时如果再次给它发送同一个信号该信号会被自动屏蔽,依次再向进程发送3,4,5号信号,发现信号都被屏蔽了。

相关文章
|
21天前
|
算法 Linux
深入探索Linux内核的内存管理机制
本文旨在为读者提供对Linux操作系统内核中内存管理机制的深入理解。通过探讨Linux内核如何高效地分配、回收和优化内存资源,我们揭示了这一复杂系统背后的原理及其对系统性能的影响。不同于常规的摘要,本文将直接进入主题,不包含背景信息或研究目的等标准部分,而是专注于技术细节和实际操作。
|
21天前
|
存储 缓存 网络协议
Linux操作系统的内核优化与性能调优####
本文深入探讨了Linux操作系统内核的优化策略与性能调优方法,旨在为系统管理员和高级用户提供一套实用的指南。通过分析内核参数调整、文件系统选择、内存管理及网络配置等关键方面,本文揭示了如何有效提升Linux系统的稳定性和运行效率。不同于常规摘要仅概述内容的做法,本摘要直接指出文章的核心价值——提供具体可行的优化措施,助力读者实现系统性能的飞跃。 ####
|
22天前
|
监控 算法 Linux
Linux内核锁机制深度剖析与实践优化####
本文作为一篇技术性文章,深入探讨了Linux操作系统内核中锁机制的工作原理、类型及其在并发控制中的应用,旨在为开发者提供关于如何有效利用这些工具来提升系统性能和稳定性的见解。不同于常规摘要的概述性质,本文将直接通过具体案例分析,展示在不同场景下选择合适的锁策略对于解决竞争条件、死锁问题的重要性,以及如何根据实际需求调整锁的粒度以达到最佳效果,为读者呈现一份实用性强的实践指南。 ####
|
22天前
|
缓存 监控 网络协议
Linux操作系统的内核优化与实践####
本文旨在探讨Linux操作系统内核的优化策略与实际应用案例,深入分析内核参数调优、编译选项配置及实时性能监控的方法。通过具体实例讲解如何根据不同应用场景调整内核设置,以提升系统性能和稳定性,为系统管理员和技术爱好者提供实用的优化指南。 ####
|
24天前
|
负载均衡 算法 Linux
深入探索Linux内核调度机制:公平与效率的平衡####
本文旨在剖析Linux操作系统内核中的进程调度机制,特别是其如何通过CFS(完全公平调度器)算法实现多任务环境下资源分配的公平性与系统响应速度之间的微妙平衡。不同于传统摘要的概览性质,本文摘要将直接聚焦于CFS的核心原理、设计目标及面临的挑战,为读者揭开Linux高效调度的秘密。 ####
34 3
|
27天前
|
负载均衡 算法 Linux
深入探索Linux内核调度器:公平与效率的平衡####
本文通过剖析Linux内核调度器的工作机制,揭示了其在多任务处理环境中如何实现时间片轮转、优先级调整及完全公平调度算法(CFS),以达到既公平又高效地分配CPU资源的目标。通过对比FIFO和RR等传统调度策略,本文展示了Linux调度器如何在复杂的计算场景下优化性能,为系统设计师和开发者提供了宝贵的设计思路。 ####
40 6
|
26天前
|
消息中间件 安全 Linux
深入探索Linux操作系统的内核机制
本文旨在为读者提供一个关于Linux操作系统内核机制的全面解析。通过探讨Linux内核的设计哲学、核心组件、以及其如何高效地管理硬件资源和系统操作,本文揭示了Linux之所以成为众多开发者和组织首选操作系统的原因。不同于常规摘要,此处我们不涉及具体代码或技术细节,而是从宏观的角度审视Linux内核的架构和功能,为对Linux感兴趣的读者提供一个高层次的理解框架。
|
28天前
|
缓存 并行计算 Linux
深入解析Linux操作系统的内核优化策略
本文旨在探讨Linux操作系统内核的优化策略,包括内核参数调整、内存管理、CPU调度以及文件系统性能提升等方面。通过对这些关键领域的分析,我们可以理解如何有效地提高Linux系统的性能和稳定性,从而为用户提供更加流畅和高效的计算体验。
30 2
|
28天前
|
缓存 网络协议 Linux
深入探索Linux操作系统的内核优化策略####
本文旨在探讨Linux操作系统内核的优化方法,通过分析当前主流的几种内核优化技术,结合具体案例,阐述如何有效提升系统性能与稳定性。文章首先概述了Linux内核的基本结构,随后详细解析了内核优化的必要性及常用手段,包括编译优化、内核参数调整、内存管理优化等,最后通过实例展示了这些优化技巧在实际场景中的应用效果,为读者提供了一套实用的Linux内核优化指南。 ####
45 1
|
28天前
|
算法 前端开发 Linux
深入理解Linux内核调度器:CFS与实时性的平衡####
本文旨在探讨Linux操作系统的核心组件之一——完全公平调度器(CFS)的工作原理,分析其在多任务处理环境中如何实现进程间的公平调度,并进一步讨论Linux对于实时性需求的支持策略。不同于传统摘要仅概述内容要点,本部分将简要预览CFS的设计哲学、核心算法以及它是如何通过红黑树数据结构来维护进程执行顺序,同时触及Linux内核为满足不同应用场景下的实时性要求而做出的权衡与优化。 ####