Почему этот вызов `poll` не блокируется правильно в файле атрибутов устройства sysfs?
У меня есть простой атрибут устройства 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, который регистрирует устройство и создает класс и этот атрибут устройства.
Приложение userpace под названием 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");
Смотрите также
1 ответ
Чтобы процитировать еще один комментарий, который вы цитировали:
Как только опрос / выборка указывает на то, что значение изменилось, вам нужно закрыть и заново открыть файл или выполнить поиск 0 и снова прочитать.
Но вы ничего не делаете с fds.fd
,
Кроме того, сделать манекен read()
перед звонком poll()
; любой вновь открытый файл считается измененным.