gpt4 book ai didi

linux - 为什么 Linux accept() 不返回 EINTR?

转载 作者:太空狗 更新时间:2023-10-29 11:14:13 25 4
gpt4 key购买 nike

环境:类似 RedHat 的发行版,2.6.39 内核,glibc 2.12。

我完全希望如果在 accept() 进行时传递了信号,则 accept 应该失败,留下 errno==EINTR。但是,我的不这样做,我想知道为什么。下面是示例程序和 strace 输出。

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <errno.h>
#include <arpa/inet.h>
#include <string.h>

static void sigh(int);

int main(int argc, char ** argv) {

int s;
struct sockaddr_in sin;

if ((s = socket(AF_INET, SOCK_STREAM, 0))<0) {
perror("socket");
return 1;
}
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
if (bind(s, (struct sockaddr*)&sin, sizeof(struct sockaddr_in))) {
perror("bind");
return 1;
}
if (listen(s, 5)) {
perror("listen");
}

signal(SIGQUIT, sigh);

while (1) {
socklen_t sl = sizeof(struct sockaddr_in);
int rc = accept(s, (struct sockaddr*)&sin, &sl);
if (rc<0) {
if (errno == EINTR) {
printf("accept restarted\n");
continue;
}
perror("accept");
return 1;
}
printf("accepted fd %d\n", rc);
close(rc);
}

}

void sigh(int s) {

signal(s, sigh);

unsigned char p[100];
int i = 0;
while (s) {
p[i++] = '0'+(s%10);
s/=10;
}
write(1, "sig ", 4);
for (i--; i>=0; i--) {
write(1, &p[i], 1);
}
write(1, "\n", 1);

}

跟踪输出:

execve("./accept", ["./accept"], [/* 57 vars */]) = 0
<skipped>
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 5) = 0
rt_sigaction(SIGQUIT, {0x4008c4, [QUIT], SA_RESTORER|SA_RESTART, 0x30b7e329a0}, {SIG_DFL, [], 0}, 8) = 0
accept(3, 0x7fffe3e3c500, [16]) = ? ERESTARTSYS (To be restarted)
--- SIGQUIT (Quit) @ 0 (0) ---
rt_sigaction(SIGQUIT, {0x4008c4, [QUIT], SA_RESTORER|SA_RESTART, 0x30b7e329a0}, {0x4008c4, [QUIT], SA_RESTORER|SA_RESTART, 0x30b7e329a0}, 8) = 0
write(1, "sig ", 4sig ) = 4
write(1, "3", 13) = 1
write(1, "\n", 1
) = 1
rt_sigreturn(0x1) = 43
accept(3, ^C <unfinished ...>

最佳答案

Unix Network Programming内书,有一节说:

We used the term "slow system call" to describe accept, and we use this term for any system call that can block forever. That is, the system call need never return. Most networking functions fall into this category. For example, there is no guarantee that a server's call to accept will ever return, if there are no clients that will connect to the server. Similarly, our server's call to read in Figure 5.3 will never return if the client never sends a line for the server to echo. Other examples of slow system calls are reads and writes of pipes and terminal devices. A notable exception is disk I/O, which usually returns to the caller (assuming no catastrophic hardware failure).

The basic rule that applies here is that when a process is blocked in a slow system call and the process catches a signal and the signal handler returns, the system call can return an error of EINTR. Some kernels automatically restart some interrupted system calls. For portability, when we write a program that catches signals (most concurrent servers catch SIGCHLD), we must be prepared for slow system calls to return EINTR. Portability problems are caused by the qualifiers "can" and "some," which were used earlier, and the fact that support for the POSIX SA_RESTART flag is optional. Even if an implementation supports the SA_RESTART flag, not all interrupted system calls may automatically be restarted. Most Berkeley-derived implementations, for example, never automatically restart select, and some of these implementations never restart accept or recvfrom.

关于linux - 为什么 Linux accept() 不返回 EINTR?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23685816/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com