【发布时间】:2014-05-15 18:17:33
【问题描述】:
环境:类似 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);
}
strace 输出:
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 ...>
【问题讨论】: