选择fds高于255然后不检查fd是否打开。这是我的示例代码:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/select.h>
int main()
{
fd_set set;
for(int i = 5;i<FD_SETSIZE;i++)
{
printf("--> i is %d\n", i);
FD_ZERO(&set);
FD_SET(i, &set);
close(i);
int retval = select(FD_SETSIZE, &set, NULL, NULL, NULL);
if(-1 == retval)
{
perror("select");
}
}
}
这导致:
--> i is 5
select: Bad file descriptor
...
--> i is 255
select: Bad file descriptor
--> i is 256
然后应用程序阻止。
为什么这不会在256上创建EBADF
直到FD_SETSIZE?
来自评论的请求信息:
prlimit
的结果是:
NOFILE max number of open files 1024 1048576
这是strace ./test_select
:
select(1024, [127], NULL, NULL, NULL) = -1 EBADF (Bad file descriptor)
dup(2) = 3
fcntl(3, F_GETFL) = 0x8402 (flags O_RDWR|O_APPEND|O_LARGEFILE)
fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
write(3, "select: Bad file descriptor\n", 28select: Bad file descriptor
) = 28
close(3) = 0
write(1, "--> i is 128\n", 13--> i is 128
) = 13
close(128) = -1 EBADF (Bad file descriptor)
select(1024, [128], NULL, NULL, NULL
从评论中揭穿思路:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/select.h>
#include <fcntl.h>
int main()
{
char filename[80];
int fd;
for(int i = 5;i<500;i++)
{
snprintf(filename, 80, "/tmp/file%d", i);
fd = open(filename, O_RDWR | O_APPEND | O_CREAT);
}
printf("--> fd is %d, FD_SETSIZE is %d\n", fd, FD_SETSIZE);
fd_set set;
FD_ZERO(&set);
FD_SET(fd, &set);
int retval = select(FD_SETSIZE, NULL, &set, NULL, NULL);
if(-1 == retval)
{
perror("select");
}
}
结果:
$ ./test_select
--> fd is 523, FD_SETSIZE is 1024
流程正常退出,无阻塞。
答案 0 :(得分:4)
这里发生了一件非常奇怪的事。您可能在Linux内核中发现了一个错误。
我修改了你的测试程序,使其更精确,并且在遇到问题时也不会卡住:
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
int main(void)
{
fd_set set;
struct timeval tv;
int i;
for(i = 5; i < FD_SETSIZE; i++)
{
FD_ZERO(&set);
FD_SET(i, &set);
tv.tv_sec = 0;
tv.tv_usec = 1000;
close(i);
int retval = select(FD_SETSIZE, &set, 0, 0, &tv);
if (retval == -1 && errno == EBADF)
;
else
{
if (retval > 0)
printf("fd %d: select returned success (%d)\n", i, retval);
else if (retval == 0)
printf("fd %d: select timed out\n", i);
else
printf("fd %d: select failed (%d; %s)\n", i, retval, strerror(errno));
return 1;
}
}
return 0;
}
我对POSIX的理解表明,无论FD_SETSIZE
是什么,该程序都不会产生输出并成功退出。这就是它在FreeBSD 11.1和NetBSD 7.1上的作用(两者都在某些描述的x86处理器上运行)。但是在Linux(x86-64,内核4.13)上,它打印
fd 256: select timed out
并退出失败。更奇怪的是,如果我在strace
,下运行相同的二进制文件来更改输出:
$ strace -o /dev/null ./a.out
fd 64: select timed out
如果我在gdb
下运行它会发生同样的事情,即使我不会告诉gdb
做除了运行程序之外的任何事情。< / p>
Reading symbols from ./a.out...done.
(gdb) r
Starting program: /tmp/a.out
fd 64: select timed out
[Inferior 1 (process 8209) exited with code 01]
因此,某些事情正在发生变化,因为该过程受ptrace
监控。这只能由内核引起。
我已经提交了bug report on the Linux kernel并会报告他们对此的评价。