我有一个简单的sysfs 设备属性,它显示在我的sysfs目录下,并在调用时read
返回内核空间变量的值。我想调用poll
此属性以允许我的用户空间线程阻塞,直到属性显示的值发生更改。
我的问题是它poll
似乎并没有阻止我的属性——POLLPRI
即使属性显示的值没有改变,它也会不断返回。事实上,我sysfs_notify
在内核模块中根本没有调用,但用户空间调用poll
仍然没有阻塞。
也许我应该检查其他东西的返回值POLLPRI
——但根据Linux内核中的文档,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
,则从线程打印!!!.
- 如果
问题是当我期望调用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");