为什么在 sysfs 设备属性文件上对 `poll` 的调用没有正确阻塞? [英] Why doesn't this call to `poll` block correctly on a sysfs device attribute file?
问题描述
我有一个简单的 sysfs 设备属性,它显示在我的 sysfs 目录下,并在调用 read
时返回一个内核空间变量.我想在这个属性上调用 poll
以允许我的用户空间线程阻塞,直到属性显示的值发生变化.
我的问题是 poll
似乎没有阻止我的属性——它一直返回 POLLPRI
,即使属性显示的值没有改变.事实上,我在内核模块中根本没有调用 sysfs_notify
,但用户空间调用 poll
仍然没有阻塞.
也许我应该检查 POLLPRI
以外的返回值——但是 根据Linux 内核中的文档,sysfs_poll
应该返回POLLERR|POLLPRI代码>:
/* ... 当内容改变时(假设* kobject 的管理器支持通知),poll 将* 返回 POLLERR|POLLPRI ...*/
有什么我忘记用 poll
做的事了吗?
设备属性位于:/sys/class/vilhelm/foo/blah.
我加载了一个名为 foo 的内核模块,它注册了一个设备,并创建了一个类和这个设备属性.
名为 bar 的用户空间应用程序生成一个线程,该线程在设备属性上调用
poll
,检查POLLPRI
.- 如果
poll
返回一个正数,POLLPRI
已经返回. - 使用
fopen
和fscan
从设备属性文件中读取值. - 如果值为
42
,则打印FROM THREAD!!!.
- 如果
问题是当我期望对 poll
的调用无限期地阻塞时,消息会不间断地打印.问题一定出在poll
(其他调用成功地从设备属性中获取了42
的正确值).
用户空间应用 - bar.c:
#include #include #include #include #include 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);返回0;}static void handle_val(unsigned val, FILE *fp){开关(值){案例42:{printf("从线程!!!
");休息;}默认:休息;}}void * start_val_service(void *arg){结构pollfd fds;fds.fd = open("/sys/class/vilhelm/foo/blah", O_RDONLY);fds.events = POLLPRI;做{int ret = poll(&fds, 1, -1);如果(ret > 0){文件 *fp = fopen("/sys/class/vilhelm/foo/blah", "r");无符号值;fscanf(fp, %u", &val);handle_val(val, fp);fclose(fp);}}同时(1);关闭(fds.fd);pthread_exit(NULL);}
内核模块 - foo.c:
#include #include #include #include 静态 dev_t foo_dev;静态结构类 *vilhelm;静态无符号 myvar = 42;静态 ssize_t unsigned_dev_attr_show(struct device *dev, struct device_attribute *attr, char *buf);struct unsigned_device_attribute{struct device_attribute dev_attr;无符号 *ptr;};静态结构 unsigned_device_attribute unsigned_dev_attr_blah = {.dev_attr = __ATTR(blah, S_IRUGO, unsigned_dev_attr_show, NULL)};静态 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: 无法注册设备");retval = -1;转到 out_alloc_chrdev_region;}vilhelm = class_create(THIS_MODULE, vilhelm");如果(IS_ERR(vilhelm)){printk(KERN_ERR "foo: 无法创建设备类");retval = PTR_ERR(vilhelm);转到 out_class_create;}struct device *foo_device = device_create(vilhelm, NULL, foo_dev, NULL, foo");如果(IS_ERR(foo_device)){printk(KERN_ERR "foo: 无法创建设备文件");retval = PTR_ERR(foo_device);转到 out_device_create;}unsigned_dev_attr_blah.ptr = &myvar;retval = device_create_file(foo_device, &unsigned_dev_attr_blah.dev_attr);如果(返回){printk(KERN_ERR "foo: 无法创建设备属性文件");转到 out_create_foo_dev_attr_files;}返回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:返回 retval;}静态无效 __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);}静态 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);无符号值 = *(tmp->ptr);返回 scnprintf(buf, PAGE_SIZE, "%u
", value);}模块初始化(foo_init);模块退出(foo_exit);MODULE_LICENSE(GPL");
另见
<块引用>从您引用的评论中引用更多内容:
<块引用>一旦 poll/select 指示值已更改,您需要关闭并重新打开文件,或寻求0并重新阅读.
但是你对 fds.fd
什么也没做.
另外,在调用poll()
之前做一个虚拟的read()
;任何新打开的文件都被视为已更改.
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.
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.
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 ...
*/
Is there something I'm forgetting to do with poll
?
The device attribute is located at: /sys/class/vilhelm/foo/blah.
I load a kernel module called foo which registers a device, and creates a class and this device attribute.
The userspace application called bar spawns a thread that calls
poll
on the device attribute, checking forPOLLPRI
.- If
poll
returns a positive number,POLLPRI
has been returned. - Use
fopen
andfscan
to read the value from the device attribute file. - If the value is
42
, print FROM THREAD!!!.
- If
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).
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!!!
");
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 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
", value);
}
module_init(foo_init);
module_exit(foo_exit);
MODULE_LICENSE("GPL");
See also
To quote some more from the comment you quoted:
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.
But you do nothing with fds.fd
.
Also, do a dummy read()
before calling poll()
;
any newly opened file is considered changed.
这篇关于为什么在 sysfs 设备属性文件上对 `poll` 的调用没有正确阻塞?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!