Почему этот вызов `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?


  1. Атрибут устройства находится по адресу: / sys / class / vilhelm / foo / blah.

  2. Я загружаю модуль ядра с именем foo, который регистрирует устройство и создает класс и этот атрибут устройства.

  3. Приложение 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");

Смотрите также

Использование вызова Linux sysfs_notify

1 ответ

Решение

Чтобы процитировать еще один комментарий, который вы цитировали:

Как только опрос / выборка указывает на то, что значение изменилось, вам нужно закрыть и заново открыть файл или выполнить поиск 0 и снова прочитать.

Но вы ничего не делаете с fds.fd,

Кроме того, сделать манекен read() перед звонком poll(); любой вновь открытый файл считается измененным.

Другие вопросы по тегам