poll () из пространства пользователя в файле sysfs и sysfs_notify () из пространства ядра не будут работать вместе

Мой модуль ядра для raspi, написанный для создания двойного светового барьера, считывает монотонное время, если каждый из двух входных фронтов gpio поднимается и возникает прерывание. Значение времени передается через обычные файлы sysfs в пространство пользователя (не файлы dev). Это нормально работает.

Моя реализация в пользовательском пространстве должна считывать эти значения и вычислять результирующую скорость прохождения объекта через световой барьер. В настоящее время эта проблема решается периодическим чтением файлов sysfs. Если значение изменяется, новые значения подбираются и используются.

Чтобы сэкономить ресурсы, я хочу опросить () для получения POLLPRI для выпущенных файлов sysfs. Внутри модуля ядра функция sysfs_notify () должна передавать измененное состояние и значение выпущенного файла sysfs в пользовательское пространство.

Но мой poll () в пользовательском пространстве постоянно блокируется. Я пробовал также POLLIN как событие. Результатом было немедленное возвращение функции poll ().

Вот мой код ...

// [...]

static struct kobject *gpio; // dir /sys/kernel/gpio

static ssize_t gpio17s_show(struct kobject *kobj,struct kobj_attribute
            *attr,char *buf)
{
    return sprintf(buf,"%li",sec1);
}

static ssize_t gpio17s_store(struct kobject *kobj,struct kobj_attribute
            *attr,const char *buf,size_t count)
{
    sscanf(buf,"%li",&sec1);
    return count;
}

}

// [...] (two more files)

static ssize_t gpio26n_show(struct kobject *kobj,struct kobj_attribute
            *attr,char *buf)
{
    sysfs_notify(gpio,NULL,"gpio26n"); // Is this the right place, the right invocation????
    // I saw this already in isr, but i believe this is not a good idea....
    // Has it perhaps to be in module_init function???
    // First arg('gpio') is kobject of the dir containing files(attributes)..
    // This can not be right in my mind, but how do I find the right kobj??
    // The third param 'gpio26n' if the file, on which I'm polling.

    return sprintf(buf,"%li",nsec2);
}

static ssize_t gpio26n_store(struct kobject *kobj,struct kobj_attribute
            *attr,const char *buf,size_t count)
{
    sscanf(buf,"%li",&nsec2);
    return count;
}

static int cleanup(int value,int ret) {

    switch(value) {
        case 5:
            free_irq(speed_irq2,NULL);
        case 4:
            free_irq(speed_irq1,NULL);
        case 3:
            gpio_free(PIN2);
        case 2:
            gpio_free(PIN1);
        case 1:
            kobject_put(gpio);
    }

    return ret;
}

static irqreturn_t speed_isr(int irq, void *data) {

    if(irq==speed_irq1) {
        getrawmonotonic(&ts1);
        sec1=ts1.tv_sec;
        nsec1=ts1.tv_nsec;
    }

    if(irq==speed_irq2) {
        getrawmonotonic(&ts2);
        sec2=ts2.tv_sec;
        nsec2=ts2.tv_nsec;
    }

    return IRQ_HANDLED;
}

static struct kobj_attribute gpio17s_attr = __ATTR(gpio17s,0644,
        gpio17s_show,gpio17s_store);
static struct kobj_attribute gpio26n_attr = __ATTR(gpio26n,0644,
        gpio26n_show,gpio26n_store);

static int  __init d_init(void) {

    int ret=0;

    printk(KERN_INFO "Module successfully loaded...");

    gpio=kobject_create_and_add("gpio",kernel_kobj);
    if(!gpio) {
        printk(KERN_ERR "Failed to create 'gpio'");
        return -ENOMEM;
    }

    ret=sysfs_create_file(gpio,&gpio17s_attr.attr);
    if(ret) {
        printk(KERN_ERR "Failed to create file 'gpio17s'");
        return cleanup(1,2);
    }

    // [...] (two more files)

    ret=sysfs_create_file(gpio,&gpio26n_attr.attr);
    if(ret) {
        printk(KERN_ERR "Failed to create file 'gpio26n'");
        return cleanup(1,5);
    }

    ret=gpio_request(PIN1,"gpio 17");
    if(ret) {
        printk(KERN_ERR "Failed to request 'gpio17'");
        return cleanup(1,6);
    }

    ret=gpio_request(PIN2,"gpio 26");
    if(ret) {
        printk(KERN_ERR "Failed to request 'gpio26'");
        return cleanup(2,7);
    }

    ret=gpio_to_irq(PIN1);
    if(ret<0) {
        printk(KERN_ERR "Unable to get irq for pin 17");
        return cleanup(3,8);
    }

    speed_irq1=ret;

    ret=gpio_to_irq(PIN2);
    if(ret<0) {
        printk(KERN_ERR "Unable to get irq for pin 26");
        return cleanup(3,9);
    }

    speed_irq2=ret;

    ret=request_irq(speed_irq1,speed_isr,IRQF_TRIGGER_RISING,
            "Speed trigger 17",NULL);
    if(ret) {
        printk(KERN_ERR "Unable to request irq for pin 17");
        return cleanup(3,10);
    }

    ret=request_irq(speed_irq2,speed_isr,IRQF_TRIGGER_RISING,
            "Speed trigger 26",NULL);
    if(ret) {
        printk(KERN_ERR "Unable to request irq for pin 26");
        return cleanup(4,10);
    }

    return 0;
}

static void __exit d_exit(void) {
// [...]

И мое приложение в пользовательском пространстве

// [...]

int main() {

    int           f      ;
    char          buf[16];
    struct pollfd pfd    ;

    while(1) {
        memset(buf,0,sizeof(buf));

        if((f=open("/sys/kernel/gpio/gpio26n",O_RDONLY)) <0) {
            fprintf(stderr,"Failed to open sysfs file\n");
            exit(1);
        }

        if((lseek(f,0L,SEEK_SET)) <0) {
            fprintf(stderr,"Failed to set pointer\n");
            exit(2);
        }


        if((read(f,buf,1)) <0) {
            fprintf(stderr,"Failed to read from file\n");
            exit(3);
        }

        pfd.fd     = f      ;
        pfd.events = POLLPRI;

        poll(&pfd,1,-1); // This should block until value has changed....
        close(f);


        // fopen, read new value etc.
        // [...]

        // Do some stuff, calculate speed, etc
    }
}

Привет, пфау


person pfau    schedule 17.12.2017    source источник


Ответы (1)


Я ошибся, разместив функцию sysfs_notify ().

В данном случае нужное место находится внутри ISR.

Когда происходит прерывание, вызывается ISR и уведомляет пользовательское пространство через sysfs_notify () о том, что новые данные доступны для чтения. poll () разблокируется, и данные принимаются.

В моем предыдущем созвездии poll () в пользовательском пространстве блокировался до тех пор, пока не будет вызвана функция kobj_attribute show. Но эта функция вызывается только в том случае, если данные читаются из файла. Это означает, что приложение пользовательского пространства ожидало модуля ядра и версии Visa.

Теперь все работает нормально.

Вот мой отредактированный код:

// [...]

static struct kobject *gpio; // dir /sys/kernel/gpio

static ssize_t gpio17s_show(struct kobject *kobj,struct kobj_attribute
            *attr,char *buf)
{
    return sprintf(buf,"%li",sec1);
}

static ssize_t gpio17s_store(struct kobject *kobj,struct kobj_attribute
            *attr,const char *buf,size_t count)
{
    sscanf(buf,"%li",&sec1);
    return count;
}

}

// [...] (two more files)

static ssize_t gpio26n_show(struct kobject *kobj,struct kobj_attribute
            *attr,char *buf)
{
    return sprintf(buf,"%li",nsec2);
}

static ssize_t gpio26n_store(struct kobject *kobj,struct kobj_attribute
            *attr,const char *buf,size_t count)
{
    sscanf(buf,"%li",&nsec2);
    return count;
}

static int cleanup(int value,int ret) {

    switch(value) {
        case 5:
            free_irq(speed_irq2,NULL);
        case 4:
            free_irq(speed_irq1,NULL);
        case 3:
            gpio_free(PIN2);
        case 2:
            gpio_free(PIN1);
        case 1:
            kobject_put(gpio);
    }

    return ret;
}

static irqreturn_t speed_isr(int irq, void *data) {

    if(irq==speed_irq1) {
        getrawmonotonic(&ts1);
        sec1=ts1.tv_sec;
        nsec1=ts1.tv_nsec;
    }

    if(irq==speed_irq2) {
        getrawmonotonic(&ts2);
        sec2=ts2.tv_sec;
        nsec2=ts2.tv_nsec;

        sysfs_notify(gpio,NULL,"gpio26n"); // !! HERE IS THE RIGHT PLACE !!
    }

    return IRQ_HANDLED;
}

static struct kobj_attribute gpio17s_attr = __ATTR(gpio17s,0644,
        gpio17s_show,gpio17s_store);
static struct kobj_attribute gpio26n_attr = __ATTR(gpio26n,0644,
        gpio26n_show,gpio26n_store);

static int  __init d_init(void) {

    int ret=0;

    printk(KERN_INFO "Module successfully loaded...");

    gpio=kobject_create_and_add("gpio",kernel_kobj);
    if(!gpio) {
        printk(KERN_ERR "Failed to create 'gpio'");
        return -ENOMEM;
    }

    ret=sysfs_create_file(gpio,&gpio17s_attr.attr);
    if(ret) {
        printk(KERN_ERR "Failed to create file 'gpio17s'");
        return cleanup(1,2);
    }

    // [...] (two more files)

    ret=sysfs_create_file(gpio,&gpio26n_attr.attr);
    if(ret) {
        printk(KERN_ERR "Failed to create file 'gpio26n'");
        return cleanup(1,5);
    }

    ret=gpio_request(PIN1,"gpio 17");
    if(ret) {
        printk(KERN_ERR "Failed to request 'gpio17'");
        return cleanup(1,6);
    }

    ret=gpio_request(PIN2,"gpio 26");
    if(ret) {
        printk(KERN_ERR "Failed to request 'gpio26'");
        return cleanup(2,7);
    }

    ret=gpio_to_irq(PIN1);
    if(ret<0) {
        printk(KERN_ERR "Unable to get irq for pin 17");
        return cleanup(3,8);
    }

    speed_irq1=ret;

    ret=gpio_to_irq(PIN2);
    if(ret<0) {
        printk(KERN_ERR "Unable to get irq for pin 26");
        return cleanup(3,9);
    }

    speed_irq2=ret;

    ret=request_irq(speed_irq1,speed_isr,IRQF_TRIGGER_RISING,
            "Speed trigger 17",NULL);
    if(ret) {
        printk(KERN_ERR "Unable to request irq for pin 17");
        return cleanup(3,10);
    }

    ret=request_irq(speed_irq2,speed_isr,IRQF_TRIGGER_RISING,
            "Speed trigger 26",NULL);
    if(ret) {
        printk(KERN_ERR "Unable to request irq for pin 26");
        return cleanup(4,10);
    }

    return 0;
}

static void __exit d_exit(void) {
// [...]

Привет, пфау

person pfau    schedule 11.01.2018