为什么对sysfs设备属性文件上的`poll`的调用不能正确阻止? [英] Why doesn't this call to `poll` block correctly on a sysfs device attribute file?

查看:89
本文介绍了为什么对sysfs设备属性文件上的`poll`的调用不能正确阻止?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的 sysfs设备属性,该属性显示在我的 sysfs 目录下,并在调用read时返回内核空间变量的值.我想在此属性上调用poll,以允许我的用户空间线程阻塞,直到该属性显示的值更改为止.

I have a simple sysfs device attribute which shows up under my sysfs directory, and on a call to read returns the value of a kernelspace variable. I want to call poll on this attribute to allow my userspace thread to block until the value shown by the attribute changes.

我的问题是poll似乎并没有阻塞我的属性-即使该属性显示的值没有变化,它也会不断返回POLLPRI.实际上,我在内核模块中根本没有对sysfs_notify的调用,但是用户空间调用poll仍然没有阻塞.

My problem is that poll doesn't seem to block on my attribute -- it keeps returning POLLPRI even though the value shown by the attribute does not change. In fact, I have no calls at all to sysfs_notify in the kernel module, yet the userspace call poll still does not block.

也许我应该检查除POLLPRI之外的其他东西的返回值-但是

Perhaps I should be checking for a return value of something other than POLLPRI -- but according to the documentation in the Linux kernel, sysfs_poll should return POLLERR|POLLPRI:

/* ... When the content changes (assuming the
 * manager for the kobject supports notification), poll will
 * return POLLERR|POLLPRI ...
 */

我是否忘记了与poll有关的内容?

Is there something I'm forgetting to do with poll?

  1. 设备属性位于:/sys/class/vilhelm/foo/blah .

我加载了一个名为 foo 的内核模块,该模块注册了一个设备,并创建了一个类和该设备属性.

I load a kernel module called foo which registers a device, and creates a class and this device attribute.

名为 bar 的用户空间应用程序会生成一个在device属性上调用poll的线程,并检查POLLPRI.

The userspace application called bar spawns a thread that calls poll on the device attribute, checking for POLLPRI.

  • 如果poll返回正数,则返回POLLPRI.
  • 使用fopenfscan从设备属性文件中读取值.
  • 如果值为42,则打印 FROM THREAD !!! .
  • If poll returns a positive number, POLLPRI has been returned.
  • Use fopen and fscan to read the value from the device attribute file.
  • If the value is 42, print FROM THREAD!!!.

问题是当我期望对poll的调用无限期地阻塞时,消息会不停地打印.问题必须出在poll上(其他调用从device属性成功获取了42的正确值).

The problem is that the message is printed nonstop when I'm expecting the call to poll to block indefinitely. The problem must lie with poll (the other calls successfully acquire the correct value of 42 from the device attribute).

用户空间应用- bar.c :

#include <stdio.h>

#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <unistd.h>

static void handle_val(unsigned val, FILE *fp);
void * start_val_service(void *arg);

int main(void){
        pthread_t val_serv;
        pthread_create(&val_serv, NULL, &start_val_service, NULL);

        pthread_exit(NULL);
        return 0;

}

static void handle_val(unsigned val, FILE *fp){
        switch(val){
                case 42:
                {
                        printf("FROM THREAD!!!\n");
                        break;
                }

                default:
                        break;
        }
}


void * start_val_service(void *arg){
        struct pollfd fds;
        fds.fd = open("/sys/class/vilhelm/foo/blah", O_RDONLY);
        fds.events = POLLPRI;

        do{
                int ret = poll(&fds, 1, -1);
                if(ret > 0){
                        FILE *fp = fopen("/sys/class/vilhelm/foo/blah", "r");

                        unsigned val;
                        fscanf(fp, "%u", &val);

                        handle_val(val, fp);

                        fclose(fp);
                }
        }while(1);

        close(fds.fd);

        pthread_exit(NULL);
}

内核模块- foo.c :

#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/kernel.h>

static dev_t foo_dev;
static struct class *vilhelm;

static unsigned myvar = 42;

static ssize_t unsigned_dev_attr_show(struct device *dev, struct device_attribute *attr, char *buf);

struct unsigned_device_attribute{
        struct device_attribute dev_attr;
        unsigned *ptr;
};

static struct unsigned_device_attribute unsigned_dev_attr_blah = {
        .dev_attr = __ATTR(blah, S_IRUGO, unsigned_dev_attr_show, NULL)
};

static int __init foo_init(void){
        int retval = 0;

        printk(KERN_INFO "HELLO FROM MODULE 1");

        if(alloc_chrdev_region(&foo_dev, 0, 1, "vilhelm") < 0){
                printk(KERN_ERR "foo: unable to register device");
                retval = -1;
                goto out_alloc_chrdev_region;
        }

        vilhelm = class_create(THIS_MODULE, "vilhelm");
        if(IS_ERR(vilhelm)){
                printk(KERN_ERR "foo: unable to create device class");
                retval = PTR_ERR(vilhelm);
                goto out_class_create;
        }

        struct device *foo_device = device_create(vilhelm, NULL, foo_dev, NULL, "foo");
        if(IS_ERR(foo_device)){
                printk(KERN_ERR "foo: unable to create device file");
                retval = PTR_ERR(foo_device);
                goto out_device_create;
        }

        unsigned_dev_attr_blah.ptr = &myvar;
        retval = device_create_file(foo_device, &unsigned_dev_attr_blah.dev_attr);
        if(retval){
                printk(KERN_ERR "foo: unable to create device attribute files");
                goto out_create_foo_dev_attr_files;
        }

        return 0;

        out_create_foo_dev_attr_files:
                device_destroy(vilhelm, foo_dev);
        out_device_create:
                class_destroy(vilhelm);
        out_class_create:
                unregister_chrdev_region(foo_dev, 1);
        out_alloc_chrdev_region:
                return retval;
}

static void __exit foo_exit(void){
        printk(KERN_INFO "BYE FROM MODULE 1");

        device_destroy(vilhelm, foo_dev);
        class_destroy(vilhelm);
        unregister_chrdev_region(foo_dev, 1);
}

static ssize_t unsigned_dev_attr_show(struct device *dev, struct device_attribute *attr, char *buf){
        struct unsigned_device_attribute *tmp = container_of(attr, struct unsigned_device_attribute, dev_attr);

        unsigned value = *(tmp->ptr);

        return scnprintf(buf, PAGE_SIZE, "%u\n", value);
}

module_init(foo_init);
module_exit(foo_exit);

MODULE_LICENSE("GPL");


另请参见

使用Linux sysfs_notify调用

推荐答案

要在您引用的评论中引用更多内容:

To quote some more from the comment you quoted:

一旦轮询/选择指示值已更改,则您 需要关闭然后重新打开文件,或者搜索为0并重新读取.

Once poll/select indicates that the value has changed, you need to close and re-open the file, or seek to 0 and read again.

但是您对fds.fd不执行任何操作.

But you do nothing with fds.fd.

另外,在调用poll()之前先做一个虚拟read(); 任何新打开的文件都被视为已更改.

Also, do a dummy read() before calling poll(); any newly opened file is considered changed.

这篇关于为什么对sysfs设备属性文件上的`poll`的调用不能正确阻止?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆