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
?
the device attribute located at: /sys/class/vilhelm/foo/blah.
i load kernel module called foo registers device, , creates class , device attribute.
the userspace application called bar spawns thread calls
poll
on device attribute, checkingpollpri
.- if
poll
returns positive number,pollpri
has been returned. - use
fopen
,fscan
read value device attribute file. - if value
42
, print from thread!!!.
- if
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
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
Post a Comment