将 poll() 与 POLLIN 一起使用以等待文件中的更改

Use poll() with POLLIN for waiting changes in file

提问人:Anton Kalistratov 提问时间:11/6/2023 更新时间:11/9/2023 访问量:55

问:

我必须与内核驱动程序合作,并在 C 应用程序中等待 sysfs_notify(3) 调用特定属性。我想通过文件描述符使用 poll() 方法。

我的实现如下所示:

...
    struct pollfd *fds = malloc(sizeof(struct pollfd) * 1);

    fds[0].fd = open("/path/to/file", O_RDONLY);
    fds[0].events = POLLIN;
    fds[0].revents = 0;
    if (fds[0].fd < 0) return -EXIT_FAILURE;

    //! Poll and Process Descriptors
    while (poll(fds, 1, -1) > 0) {
        if (fds[0].events & fds[0].revents) {
            fds[0].revents = 0;
            ret = read(fds[0].fd, buf, sizeof(buf));
        }
    }
...

结果,即使没有对目标文件执行任何操作,我也会在 POLLIN 的 fds.revents 中激活无限不可阻挡的 poll() 激活。

我已经尝试了我的简单文本文件而不是内核 sysfs 属性,并且还为 POLLIN 获得了无限的 unsoppable poll() 激活,而没有对文件执行任何操作。

有人可以帮我解决问题吗? 提前致谢,安东!

C Linux 内核 sysfs

评论

1赞 Shawn 11/7/2023
文件始终是可读的。这些东西可能会堵塞,比如插座和管道,但不会堵塞。
1赞 Shawn 11/7/2023
如果要监视文件的更改,请使用 。inotify
0赞 Anton Kalistratov 11/7/2023
感谢您的回复!您能给我分享一些关于如何在应用程序上正确捕获sysfs_notify的想法吗?
1赞 John Bollinger 11/7/2023
根据对 stackoverflow.com/a/16404357/2402272 的评论,等待是错误的事件。您应该等待 .这对我来说似乎并不奇怪,因为 sysfs 文件应该始终准备好阅读。POLLINPOLLPRI|POLLERR
1赞 John Bollinger 11/7/2023
@AntonKalistratov,我希望这是暴露您正在ing的sysfs接口的驱动程序的功能。poll

答:

0赞 Anton Kalistratov 11/9/2023 #1

UPD:嗯,我已经解决了我的问题。我有自己的内核驱动程序,sysfs_notify问题就在这里。I2C 内核驱动程序具有自己的结构,sysfs 组注册从内部驱动程序探测运行。因此,与其在探测期间使用,不如由您的组初始化内部字段,并在内部探测期间自动在 sysfs 中注册,并且我之前已经粘贴过,例如在我的驱动程序上:struct i2c_driversysfs_create_group(2)sysfs_create_group(2)struct i2c_driverstruct device_driver driverdev_groupskobject_uevent_env(&chip->client->dev.kobj, KOBJ_CHANGE, envp);sysfs_notify()

ATTRIBUTE_GROUPS(sfh7771_attribute);
...
static struct i2c_driver sfh7771_driver = {
.driver  = {
    .name   = SFH7771_NAME,
    .of_match_table = sfh7771_of_match,
    .dev_groups = sfh7771_attribute_groups,
},
.probe    = sfh7771_probe,
.remove   = sfh7771_remove,
.id_table = sfh7771_id,
};
...
kobject_uevent_env(&chip->client->dev.kobj, KOBJ_CHANGE, envp);
sysfs_notify(&chip->client->dev.kobj, NULL, "your_attribute");

在我的用户空间代码上,我使用了,但作为事件,有 POLLPRI |POLLERR 标记,不要忘记使用 lseek() 来查找文件的开头。下面的简短示例:poll(3)

struct pollfd *fds = malloc(sizeof(struct pollfd) * 1);

fds[0].fd = open("/path/to/file", O_RDONLY);
fds[0].events = POLLPRI | POLLERR;
fds[0].revents = 0;
if (fds[0].fd < 0) return -EXIT_FAILURE;

//! Poll and Process Descriptors
while (poll(fds, 1, -1) > 0) {
    if (fds[0].events & fds[0].revents) {
        fds[0].revents = 0;
        lseek(fds[0].fd, 0, SEEK_SET);
        ret = read(fds[0].fd, buf, sizeof(buf));
    }
}