为什么不调用“轮询”在sysfs设备属性文件上正确的阻塞?

我有一个简单的sysfs设备属性 ,它显示在我的sysfs目录下,并且在read调用时返回一个kernelspacevariables的值。 我想调用这个属性的poll ,以允许我的用户空间线程阻塞,直到属性显示的值改变。

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

也许我应该检查POLLPRI之外的返回值 – 但是根据 Linux内核的文档 , sysfs_poll应该返回POLLERR|POLLPRI

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

有什么我忘记做poll吗?


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

  2. 我加载一个名为foo的内核模块,它注册一个设备,并创build一个类和这个设备属性。

  3. 名为bar的用户空间应用程序产生一个调用设备属性poll的线程,检查POLLPRI

    • 如果poll返回正数, POLLPRI已经返回。
    • 使用fopenfscan读取设备属性文件中的值。
    • 如果值是42 ,则打印FROM THREAD!

问题是,当我期望调用poll无限期阻止时,邮件不停打印。 问题必须与poll (其他调用成功从设备属性获取正确的值42 )。


用户空间的应用程序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调用

Solutions Collecting From Web of "为什么不调用“轮询”在sysfs设备属性文件上正确的阻塞?"

引用一些你引用的评论:

一旦轮询/选择表明该值已经改变,你需要关闭并重新打开文件,或寻求0和再次阅读。

但是你对fds.fd不做任何fds.fd

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