为什么对sysfs设备属性文件上的`poll`的调用不能正确阻止? [英] Why doesn't this call to `poll` block correctly on a sysfs device attribute file?
问题描述
我有一个简单的 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.
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
?
-
设备属性位于:/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
. - 使用
fopen
和fscan
从设备属性文件中读取值. - 如果值为
42
,则打印 FROM THREAD !!! .
- 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!!!.
问题是当我期望对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");
另请参见
推荐答案
要在您引用的评论中引用更多内容:
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屋!