当前位置:   article > 正文

【探索Linux】P.18(进程信号 —— 信号捕捉 | 信号处理 | sigaction() )_sigaction 任务

sigaction 任务

在这里插入图片描述

引言

Linux系统中,信号是进程之间通信的重要方式之一。前面的两篇文章已经介绍了信号的产生和保存,本篇文章将进一步探讨信号的捕捉、处理以及使用sigaction()函数的方法。信号捕捉是指进程在接收到信号时采取的行动,而信号处理则是指对接收到的信号进行适当的处理逻辑。通过使用sigaction()函数,我们可以在程序中设置对特定信号的处理方式,从而实现更加灵活和精确的信号处理机制。本文将详细介绍信号捕捉的原理和使用方法,以及sigaction()函数的具体用法,帮助读者更好地理解和应用信号处理的相关知识。无论是开发基于Linux的应用程序,还是进行系统级编程,信号处理都是一个至关重要的主题,相信通过学习本文,您将对信号处理有更深入的了解。

一、信号捕捉

1. 内核实现信号捕捉过程

当信号的处理动作是用户自定义函数,并且在信号到达时调用该函数,这被称为捕捉信号。由于信号处理函数的代码运行在用户空间,处理过程可能会比较复杂,下面举一个例子来说明:

  1. 用户程序注册了处理函数sighandler来捕捉SIGINT信号。
  2. 当前正在执行main函数时,若发生中断或异常导致切换到内核态。
  3. 在中断处理完成后,在返回用户态执行main函数之前,检测到有SIGINT信号递达。
  4. 内核决定在返回用户态后,不恢复main函数的上下文继续执行,而是调用sighandler函数。sighandler函数和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程。
  5. sighandler函数执行完毕后,会自动执行特殊的系统调用sigreturn,再次进入内核态。
  6. 如果没有新的信号递达,此次返回用户态将会恢复main函数的上下文,并继续执行。
    在这里插入图片描述

2. sigaction() 函数

sigaction()函数是一个用于设置信号处理函数的系统调用。它允许用户程序指定对特定信号的处理方式,包括捕捉信号、忽略信号或使用默认处理方式。
在这里插入图片描述

(1)函数原型

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
  • 1

(2)参数说明

  • signum:指定要设置处理方式的信号编号。
  • act指向一个struct sigaction结构体,用于设置新的信号处理方式
  • oldact可选参数,指向一个struct sigaction结构体,用于保存之前的信号处理方式。

struct sigaction结构体定义如下:

struct sigaction {
    void (*sa_handler)(int);
    void (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer)(void);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

该结构体的主要成员包括

  • sa_handler:指定信号处理函数的地址,可以是一个函数指针,或者是SIG_IGN(表示忽略信号)或SIG_DFL(表示使用默认处理方式)。
  • sa_sigaction:用于指定信号处理函数的扩展形式,可以获取更多关于信号的信息,如发送信号的进程ID等。
  • sa_mask:指定一个信号屏蔽集,当进入信号处理函数时,会将这个屏蔽集与当前进程的信号屏蔽字进行按位或操作,从而阻塞其他指定的信号。
  • sa_flags:用于设置一些标志位,如SA_RESTART表示在信号处理函数返回后自动重启被中断的系统调用。
  • sa_restorer:已废弃的字段,现在不再使用。

(3)返回值

sigaction()函数返回值为0表示操作成功,-1表示出现了错误。如果发生错误,可以通过errno变量获取错误码。常见的错误码包括:

  • EINVAL:指定的信号编号无效或者提供的struct sigaction结构体无效。
  • ENOENT:指定的信号编号不存在。

(4)函数使用

使用sigaction()函数进行信号处理的一般步骤如下:

  1. 创建一个struct sigaction结构体对象,并根据需要设置其中的成员,特别是sa_handlersa_sigaction成员来指定信号处理函数。
  2. 调用sigaction()函数,传入要设置处理方式的信号编号、指向上述结构体对象的指针以及可选的保存之前处理方式的结构体指针。
  3. 根据sigaction()函数的返回值判断操作是否成功。

下面是一个简单的C语言示例,演示如何使用sigaction()函数来捕获和处理SIGINT信号(即Ctrl + C):

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void sigint_handler(int signo) {
    printf("Caught SIGINT, exiting...\n");
    exit(1);
}

int main() {
    struct sigaction sa;

    // 设置信号处理函数为sigint_handler
    sa.sa_handler = sigint_handler;
    // 清空sa_mask,即不阻塞任何其他信号
    sigemptyset(&sa.sa_mask);
    // 设置一些标志位,这里使用默认值0
    sa.sa_flags = 0;

    // 注册对SIGINT信号的处理方式
    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction");
        return 1;
    }

    printf("Press Ctrl+C to send a SIGINT...\n");

    // 进入一个无限循环,等待信号
    while (1) {
        sleep(1);
    }

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

在这个示例中,首先定义了一个名为sigint_handler的函数,用于处理SIGINT信号。然后在main函数中,创建了一个struct sigaction对象sa,并设置了其中的成员,包括sa_handler指向sigint_handler函数地址,sa_mask为空,sa_flags为0。接着调用sigaction()函数注册对SIGINT信号的处理方式。最后进入一个无限循环,等待信号的到来。

当用户按下Ctrl+C时,会发送SIGINT信号,程序会捕获该信号并调用sigint_handler函数进行处理,打印一条消息并退出程序。这样就实现了对SIGINT信号的自定义处理。

二、可重入函数与不可重入函数

在这里插入图片描述
main函数调用insert函数向一个链表head中插入节点node1,插入操作分为两步,刚做完第一步的时候因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到sighandler函数。sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作的两步都做完之后从sighandler返回内核态,再次回到用户态就从main函数调用的insert函数中继续 往下执行,先前做第一步之后被打断,现在继续做完第二步。结果是 main函数和sighandler先后向链表中插入两个节点,而最后只有一个节点真正插入链表中了

像上例这样,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入insert函数访问一个全局链表有可能因为重入而造成错乱。像这样的函数称为不可重入函数,反之如果一个函数只访问自己的局部变量或参数,则称为可重入(Reentrant) 函数。想一下,为什么两个不同的控制流程调用同一个函数,访问它的同一个局部变量或参数就不会造成错乱?

1. 可重入函数条件

可重入函数必须满足以下条件

  1. 不使用全局变量或静态变量,或者只读取这些变量的值。

  2. 不修改非本地的内存区域,或者仅修改线程本地的内存区域。

  3. 不调用可能导致线程挂起或阻塞的函数,如sleep()wait()等。

一些示例可重入函数包括:memcpy()strlen()sprintf()strtok_r()等。

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/959510

推荐阅读
相关标签