简体   繁体   English

sigaction将SIGINT传递给系统调用,但不传递信号

[英]sigaction passes SIGINT to system call, but not signal

I have a loop handling an accept(2) call. 我有一个处理accept(2)调用的循环。 I want to be able to perform some cleanup when a SIGINT is sent to the program. 我希望能够在将SIGINT发送到程序时执行一些清理。 My first thought was to use the signal function. 我的第一个想法是使用signal功能。

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

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

However, this simply prints "Caught signal" and then the program continues on. 然而,这只是打印“捕获信号”然后程序继续。

If I modify main to use sigaction , the program works as expected. 如果我修改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;
    }
    // ...
}

Upon sending SIGINT, I get Caught Signal , followed by accept: Interrupted system call . 发送SIGINT后,我收到Caught Signal ,然后accept: Interrupted system call From the man page for accept(2) 从接收的手册页accept(2)

ERRORS 错误

... ...

EINTR The system call was interrupted by a signal that was caught before a valid connection arrived; EINTR系统调用被有效连接到达之前捕获的信号中断; see signal(7). 见信号(7)。

I understand that sigaction is more modern and that I should be using it over signal , but I'm quite curious why it provides this difference in functionality. 我知道sigaction更现代,我应该在signal上使用它,但我很好奇为什么它提供了这种功能上的差异。

Below I've included a full usable example program for each case. 下面我列出了每个案例的完整可用示例程序。

Example with signal(2) 信号示例(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\n");
}

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\n");
        return 1;
    }
    int sock = socket(addr_info->ai_family, addr_info->ai_socktype, addr_info->ai_protocol);
    if (sock == -1) {
        printf("Socket Failed\n");
        return 1;
    }
    int bind_result = bind(sock, addr_info->ai_addr, addr_info->ai_addrlen);
    if (bind_result == -1) {
        close(sock);
        printf("Bind Failed\n");
        return 1;
    }
    int listen_result = listen(sock, 8);
    if (listen_result == -1) {
        close(sock);
        printf("Listen Failed\n");
        return 1;
    }
    printf("Waiting...\n");
    int accept_fd = accept(sock, NULL, NULL);
    if (accept_fd == -1) {
        close(sock);
        perror("accept");
        return 1;
    }
    printf("Got fd %d\n", accept_fd);
    char *buffer = malloc(BUFFER_SIZE * sizeof(char));
    int n;
    while ((n = read(accept_fd, buffer, BUFFER_SIZE)) > 0) {
        printf("%.*s\n", n, buffer);
    }
    close(sock);
}

Example with sigaction(2) 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\n");
}

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\n");
        return 1;
    }
    int sock = socket(addr_info->ai_family, addr_info->ai_socktype, addr_info->ai_protocol);
    if (sock == -1) {
        printf("Socket Failed\n");
        return 1;
    }
    int bind_result = bind(sock, addr_info->ai_addr, addr_info->ai_addrlen);
    if (bind_result == -1) {
        close(sock);
        printf("Bind Failed\n");
        return 1;
    }
    int listen_result = listen(sock, 8);
    if (listen_result == -1) {
        close(sock);
        printf("Listen Failed\n");
        return 1;
    }
    printf("Waiting...\n");
    int accept_fd = accept(sock, NULL, NULL);
    if (accept_fd == -1) {
        close(sock);
        perror("accept");
        return 1;
    }
    printf("Got fd %d\n", accept_fd);
    char *buffer = malloc(BUFFER_SIZE * sizeof(char));
    int n;
    while ((n = read(accept_fd, buffer, BUFFER_SIZE)) > 0) {
        printf("%.*s\n", n, buffer);
    }
    close(sock);
}

On BSD and Linux, signal() is equivalent to sigaction() with sa_flags set to SA_RESTART . 在BSD和Linux上, signal()等效于sigaction()sa_flags设置为SA_RESTART If you set that flag in your sigaction() code, it will behave the same as your signal() code. 如果在sigaction()代码中设置该标志,则其行为与signal()代码相同。 If that's not what you want, then you must only use sigaction() . 如果那不是你想要的,那么你必须只使用sigaction()

Notes from the Linux man page (which also apply to BSD and OS X): Linux手册页中的注释(也适用于BSD和OS X):

On BSD, when a signal handler is invoked, the signal disposition is not reset, and further instances of the signal are blocked from being delivered while the handler is executing. 在BSD上,当调用信号处理程序时,信号处理不会被重置,并且在处理程序执行时阻止信号的其他实例被传递。 Furthermore, certain blocking system calls are automatically restarted if interrupted by a signal handler (see signal(7)). 此外,如果信号处理程序中断,某些阻塞系统调用会自动重启(参见signal(7))。 The BSD semantics are equivalent to calling sigaction(2) with the following flags: BSD语义等同于使用以下标志调用sigaction(2):

       sa.sa_flags = SA_RESTART;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM