【发布时间】:2013-05-02 19:36:16
【问题描述】:
我有一个简单的 sysfs 设备属性,它显示在我的 sysfs 目录下,并且在调用 read 时返回内核空间变量的值。我想在这个属性上调用poll,以允许我的用户空间线程阻塞,直到属性显示的值发生变化。
我的问题是poll 似乎并没有阻止我的属性——即使属性显示的值没有改变,它也会不断返回POLLPRI。事实上,我在内核模块中根本没有调用sysfs_notify,但是用户空间调用poll仍然没有阻塞。
也许我应该检查POLLPRI以外的返回值——但是在Linux内核中according to the documentation,sysfs_poll应该返回POLLERR|POLLPRI:
/* ... When the content changes (assuming the
* manager for the kobject supports notification), poll will
* return 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 <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 linux-kernel linux-device-driver blocking polling