首页 > 解决方案 > 将文件描述符读入 NULL 是否合法?

问题描述

最近,为了我正在编写的库,我一直在修复时间步长。经过一些研究,假设我最终得到了这个原型,它精确且易于与我的库的通用事件系统结合:

#include <stdio.h>
#include <unistd.h>
#include <sys/timerfd.h>
#include <poll.h>

struct pollfd fds[1];
struct itimerspec its;

int main(void) {
    fds[0] = (struct pollfd) {timerfd_create(CLOCK_MONOTONIC, 0), POLLIN, 0}; //long live clarity
    its.it_interval = (struct timespec) {0, 16666667};
    its.it_value = (struct timespec) {0, 16666667};
    timerfd_settime(fds[0].fd, 0, &its, NULL);
    while(1) {
        poll(fds, 1, -1);
        if(fds[0].revents == POLLIN) {
            long long buffer;
            read(fds[0].fd, &buffer, 8);
            printf("ROFL\n");
        } else {
            printf("BOOM\n");
            break;
        }
    }
    close(fds[0].fd);
    return 0;
}

但是,为了使计时器的文件描述符可重用,我不得不用宝贵的 8 字节数据污染我的 CPU 缓存,这严重伤害了我。因此,我尝试将read()调用替换为lseek(),如下所示:

lseek(fds[0].fd, 0, SEEK_END);

不幸的是,这甚至lseek(fds[0].fd, 8, SEEK_CUR);给了我ESPIPE错误并且不起作用。但是后来,我发现尽管给出了EFAULTs,但以下内容实际上完成了它的工作:

read(fds[0].fd, NULL, 8);

像这样偏移文件描述符是否合法,已定义的行为?如果不是(正如EFAULTs 向我建议的那样,足以避免使用那个天才),是否存在一个函数可以丢弃读取的数据,而不会将其写下来,或者以其他方式抵消我的计时器的文件描述符?

标签: clinuxfile-descriptor

解决方案


read(2)的 POSIX 规范没有指定将空指针作为缓冲区参数传递的结果。没有给出具体的错误代码,也没有说明是否会从描述符中读取任何数据。

但是,Linux 手册页有此错误:

EFAULT buf在您可访问的地址空间之外。

但是,它并没有说它会在发生这种情况时读取 8 个字节并丢弃它们。

所以我认为你不能像你想要的那样依赖这个工作。


推荐阅读