linux - Why doesn't this call to `poll` block correctly on a sysfs device attribute file? -


i have simple sysfs device attribute shows under sysfs directory, , on call read returns value of kernelspace variable. want call poll on attribute allow userspace thread block until value shown attribute changes.

my problem poll doesn't seem block on attribute -- keeps returning pollpri though value shown attribute not change. in fact, have no calls @ sysfs_notify in kernel module, yet userspace call poll still not block.

perhaps should checking return value of other pollpri -- according documentation in linux kernel, sysfs_poll should return pollerr|pollpri:

/* ... when content changes (assuming  * manager kobject supports notification), poll  * return pollerr|pollpri ...  */ 

is there i'm forgetting poll?


  1. the device attribute located at: /sys/class/vilhelm/foo/blah.

  2. i load kernel module called foo registers device, , creates class , device attribute.

  3. the userspace application called bar spawns thread calls poll on device attribute, checking pollpri.

    • if poll returns positive number, pollpri has been returned.
    • use fopen , fscan read value device attribute file.
    • if value 42, print from thread!!!.

the problem message printed nonstop when i'm expecting call poll block indefinitely. problem must lie poll (the other calls acquire correct value of 42 device attribute).


userspace app - 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); } 

kernel module - 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 module 1");          if(alloc_chrdev_region(&foo_dev, 0, 1, "vilhelm") < 0){                 printk(kern_err "foo: unable register device");                 retval = -1;                 goto out_alloc_chrdev_region;         }          vilhelm = class_create(this_module, "vilhelm");         if(is_err(vilhelm)){                 printk(kern_err "foo: unable 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 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 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 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"); 

see also

using linux sysfs_notify call

to quote more comment quoted:

once poll/select indicates value has changed, need close , re-open file, or seek 0 , read again.

but nothing fds.fd.

also, dummy read() before calling poll(); newly opened file considered changed.


Comments

Popular posts from this blog

java - Jmockit String final length method mocking Issue -

asp.net - Razor Page Hosted on IIS 6 Fails Every Morning -

c++ - wxwidget compiling on windows command prompt -