poll()在macOS上返回超过256个描述符的EINVAL

时间:2017-04-22 06:11:35

标签: c macos-sierra

以下是崩溃的示例代码:

#include <stdio.h>
#include <poll.h>
#include <stdlib.h>
#include <limits.h>

#define POLL_SIZE 1024

int main(int argc, const char * argv[]) {
    printf("%d\n", OPEN_MAX);
    struct pollfd *poll_ = calloc(POLL_SIZE, sizeof(struct pollfd));
    if (poll(poll_, POLL_SIZE, -1) < 0)
        if (errno == EINVAL)
            perror("poll error");
    return 0;
}

如果将POLL_SIZE设置为256或更低,代码就可以正常工作。有趣的是,如果你在Xcode中运行这个代码,它会正常执行,但如果你自己运行二进制文件就会崩溃。

输出如下:

10240
poll error: Invalid argument

根据poll(2)

[EINVAL] The nfds argument is greater than OPEN_MAX or the
         timeout argument is less than -1.

正如您所看到的,POLL_SIZE比限制小很多,超时正好是-1,但它崩溃了。

我用于手动构建的clang版本:

Configured with: prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.41)
Target: x86_64-apple-darwin16.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

1 个答案:

答案 0 :(得分:1)

在Unix系统上,processes对资源有限制。参见例如getrlimit。您可以更改它们(使用setrlimit),您的系统管理员也可以更改它们(例如,在启动或登录时配置这些限制)。与文件描述符有关的限制RLIMIT_NOFILE。另请阅读ulimit bash builtin。另请sysconf_SC_OPEN_MAX

poll系统调用给出了一个不太大的数组,并且在其中重复一些file descriptor是不好的(可能但效率低下)。因此,在实践中,您经常使用一个非常小的数组来提及不同的(但有效)文件描述符。 poll的第二个参数是有用条目的数量(实际上,所有不同的条目),而不是数组的分配大小。

您可以处理许多文件描述符。阅读C10K problem

顺便说一句,你的代码没有崩溃。 poll记录失败(但没有崩溃)。

你应该阅读一些POSIX编程书。 Advanced Linux Programming是免费提供的,其中大部分是在POSIX(而不是Linux特定的)上。