Sigaction将SIGINT传递给系统调用,但不传递信号 [英] sigaction passes SIGINT to system call, but not signal

查看:23
本文介绍了Sigaction将SIGINT传递给系统调用,但不传递信号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个处理accept(2)调用的循环。我希望在向程序发送SIGINT时能够执行一些清理。我的第一个想法是使用signal函数。

void signal_handler(int signal) {
    printf("Caught signal
");
}

int main() {
    signal(SIGINT, &signal_handler);
    // ...
    int accept_fd = accept(sock, NULL, NULL);
    if (accept_fd == -1) {
        close(sock);
        perror("accept");
        return 1;
    }
    // ...
}

但是,这只是打印";捕获信号&,然后程序继续运行。

如果我将main修改为使用sigaction,程序将按预期运行。

int main() {
    struct sigaction sa;
    sa.sa_handler = &signal_handler;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGINT, &sa, NULL);
    // ...
    int accept_fd = accept(sock, NULL, NULL);
    if (accept_fd == -1) {
        close(sock);
        perror("accept");
        return 1;
    }
    // ...
}

发送SIGINT后,我得到Caught Signal,然后是accept: Interrupted system call。从accept(2)

的手册页

错误

.

EINTR在有效连接到达之前捕获的信号中断了系统调用;请参见信号(7)。

我知道sigaction更现代,我应该比signal使用它,但我很好奇为什么它在功能上有这样的区别。

下面我为每种情况都包括了一个完整的可用的示例程序。

带信号(2)的示例

#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define BUFFER_SIZE 32

void signal_handler(int signal) {
    printf("Caught signal
");
}

int main() {
    signal(SIGINT, &signal_handler);
    struct addrinfo hints;
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    struct addrinfo *addr_info;
    int info_result = getaddrinfo("localhost", "8080", &hints, &addr_info);
    if (info_result != 0) {
        printf("Getting address failed
");
        return 1;
    }
    int sock = socket(addr_info->ai_family, addr_info->ai_socktype, addr_info->ai_protocol);
    if (sock == -1) {
        printf("Socket Failed
");
        return 1;
    }
    int bind_result = bind(sock, addr_info->ai_addr, addr_info->ai_addrlen);
    if (bind_result == -1) {
        close(sock);
        printf("Bind Failed
");
        return 1;
    }
    int listen_result = listen(sock, 8);
    if (listen_result == -1) {
        close(sock);
        printf("Listen Failed
");
        return 1;
    }
    printf("Waiting...
");
    int accept_fd = accept(sock, NULL, NULL);
    if (accept_fd == -1) {
        close(sock);
        perror("accept");
        return 1;
    }
    printf("Got fd %d
", accept_fd);
    char *buffer = malloc(BUFFER_SIZE * sizeof(char));
    int n;
    while ((n = read(accept_fd, buffer, BUFFER_SIZE)) > 0) {
        printf("%.*s
", n, buffer);
    }
    close(sock);
}

带sigaction(2)的示例

#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define BUFFER_SIZE 32

void signal_handler(int signal) {
    printf("Caught signal
");
}

int main() {
    struct sigaction sa;
    sa.sa_handler = &signal_handler;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGINT, &sa, NULL);
    struct addrinfo hints;
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    struct addrinfo *addr_info;
    int info_result = getaddrinfo("localhost", "8080", &hints, &addr_info);
    if (info_result != 0) {
        printf("Getting address failed
");
        return 1;
    }
    int sock = socket(addr_info->ai_family, addr_info->ai_socktype, addr_info->ai_protocol);
    if (sock == -1) {
        printf("Socket Failed
");
        return 1;
    }
    int bind_result = bind(sock, addr_info->ai_addr, addr_info->ai_addrlen);
    if (bind_result == -1) {
        close(sock);
        printf("Bind Failed
");
        return 1;
    }
    int listen_result = listen(sock, 8);
    if (listen_result == -1) {
        close(sock);
        printf("Listen Failed
");
        return 1;
    }
    printf("Waiting...
");
    int accept_fd = accept(sock, NULL, NULL);
    if (accept_fd == -1) {
        close(sock);
        perror("accept");
        return 1;
    }
    printf("Got fd %d
", accept_fd);
    char *buffer = malloc(BUFFER_SIZE * sizeof(char));
    int n;
    while ((n = read(accept_fd, buffer, BUFFER_SIZE)) > 0) {
        printf("%.*s
", n, buffer);
    }
    close(sock);
}

推荐答案

在bsd和linux上,signal()相当于sigaction()sa_flags设置为SA_RESTART。如果您在sigaction()代码中设置了该标志,它的行为将与您的代码相同。如果这不是您想要的,则只能使用sigaction()

Linux man page(也适用于BSD和OS X)的说明:

在BSD上, 当调用信号处理程序时,信号处置不是 重置,则阻止该信号的进一步实例被 在处理程序执行时交付。再者,肯定的是, 如果被中断,阻塞的系统调用将自动重新启动 信号处理程序(参见信号(7))。BSD语义等同于 使用以下标志调用sigaction(2):

       sa.sa_flags = SA_RESTART;

这篇关于Sigaction将SIGINT传递给系统调用,但不传递信号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆