2013-05-03 4 views
6

Я пытаюсь общаться асинхронно между драйвером ядра и программой для пространства пользователя (я знаю, что здесь есть много вопросов, которые запрашивают подобную информацию, но я не мог найти ничего, что связано с sysfs_notify).Использование вызова sysfs_notify Linux

Я оставляю здесь редактирование Vilhelm, но добавляя источник как к простому драйверу, использующему sysfs, так и к программе пользовательского пространства для опроса. Драйвер отлично работает (я получил большую часть из сети, он не получил кредитов, но я не мог найти их, когда возвращался, чтобы добавить их). К сожалению, программа опроса не работает. Он всегда возвращает успех немедленно. Интересно, что, если я не буду выполнять два чтения перед опросом, члены-регенерации будут установлены в POLLERR | POLLIN вместо просто POLLIN, как видно на выходе программы.

выход программы:

корень @ Ubuntu:/Главная/wmulcahy/демо # ./readhello
вызвало
значение атрибута файла: 74 (т) [0]
revents [0]: 00000001
revents [1]: 00000001

Здесь вы водитель: hello.c (вы можете увидеть, где я начал ...)

#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/fs.h> 
#include <linux/slab.h> 

struct my_attr { 
    struct attribute attr; 
    int value; 
}; 

static struct my_attr notify = { 
    .attr.name="notify", 
    .attr.mode = 0644, 
    .value = 0, 
}; 

static struct my_attr trigger = { 
    .attr.name="trigger", 
    .attr.mode = 0644, 
    .value = 0, 
}; 

static struct attribute * myattr[] = { 
    &notify.attr, 
    &trigger.attr, 
    NULL 
}; 

static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) 
{ 
    struct my_attr *a = container_of(attr, struct my_attr, attr); 
    printk("hello: show called (%s)\n", a->attr.name); 
    return scnprintf(buf, PAGE_SIZE, "%s: %d\n", a->attr.name, a->value); 
} 
static struct kobject *mykobj; 

static ssize_t store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len) 
{ 
    struct my_attr *a = container_of(attr, struct my_attr, attr); 

    sscanf(buf, "%d", &a->value); 
    notify.value = a->value; 
    printk("sysfs_notify store %s = %d\n", a->attr.name, a->value); 
    sysfs_notify(mykobj, NULL, "notify"); 
    return sizeof(int); 
} 

static struct sysfs_ops myops = { 
    .show = show, 
    .store = store, 
}; 

static struct kobj_type mytype = { 
    .sysfs_ops = &myops, 
    .default_attrs = myattr, 
}; 

static struct kobject *mykobj; 
static int __init hello_module_init(void) 
{ 
    int err = -1; 
    printk("Hello: init\n"); 
    mykobj = kzalloc(sizeof(*mykobj), GFP_KERNEL); 
    if (mykobj) { 
     kobject_init(mykobj, &mytype); 
     if (kobject_add(mykobj, NULL, "%s", "hello")) { 
      err = -1; 
      printk("Hello: kobject_add() failed\n"); 
      kobject_put(mykobj); 
      mykobj = NULL; 
     } 
     err = 0; 
    } 
    return err; 
} 

static void __exit hello_module_exit(void) 
{ 
    if (mykobj) { 
     kobject_put(mykobj); 
     kfree(mykobj); 
    } 
    printk("Hello: exit\n"); 
} 

module_init(hello_module_init); 
module_exit(hello_module_exit); 
MODULE_LICENSE("GPL"); 

А вот программа опрос: readhello.c

#include <stdint.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <poll.h> 

#define TEST_SYSFS_TRIGGER "/sys/hello/trigger" 
#define TEST_SYSFS_NOTIFY "/sys/hello/notify" 

int main(int argc, char **argv) 
{ 
    int cnt, notifyFd, triggerFd, rv; 
    char attrData[100]; 
    struct pollfd ufds[2]; 

    // Open a connection to the attribute file. 
    if ((notifyFd = open(TEST_SYSFS_NOTIFY, O_RDWR)) < 0) 
    { 
     perror("Unable to open notify"); 
     exit(1); 
    } 
    // Open a connection to the attribute file. 
    if ((triggerFd = open(TEST_SYSFS_TRIGGER, O_RDWR)) < 0) 
    { 
     perror("Unable to open trigger"); 
     exit(1); 
    } 

    ufds[0].fd = notifyFd; 
    ufds[0].events = POLLIN; 
    ufds[1].fd = triggerFd; 
    ufds[1].events = POLLIN; 

    // Someone suggested dummy reads before the poll() call 
    cnt = read(notifyFd, attrData, 100); 
    cnt = read(triggerFd, attrData, 100); 
    ufds[0].revents = 0; 
    ufds[1].revents = 0; 
    if ((rv = poll(ufds, 2, 10000)) < 0) 
    { 
     perror("poll error"); 
    } 
    else if (rv == 0) 
    { 
     printf("Timeout occurred!\n"); 
    } 
    else if (ufds[0].revents & POLLIN) 
    { 
     printf("triggered\n"); 
     cnt = read(notifyFd, attrData, 1); 
     printf("Attribute file value: %02X (%c) [%d]\n", attrData[0], attrData[0], cnt); 
    } 
    printf("revents[0]: %08X\n", ufds[0].revents); 
    printf("revents[1]: %08X\n", ufds[1].revents); 

    close(triggerFd); 
    close(notifyFd); 
} 

Some upcoming sysfs enhancements.

Внутренний патч добавляет очередь очереди ожидания к каждому объекту в системе ; эта очередь вставляется в таблицу опроса в ответ на вызов poll(). Код sysfs не имеет никакого способа знать, однако, когда значение любого заданного sysfs атрибут изменился, поэтому подсистема реализации Pollable атрибут должен сделать явные вызовы:

void sysfs_notify(struct kobject *kobj, char *dir, char *attr); 

Спасибо, Lee

ответ

7

Опрос блокировки выполнен с стороны пользователя. Пользовательский код может просто указать ядру, какие атрибуты ему интересны, а затем заблокировать в poll(), пока один из них не изменился.

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

Подумайте, что poll() «подписывается» на уведомления об изменении интересующего объекта и sysfs_notify() как «публикацию» изменения для любых подписчиков.

+0

Не 'sysfs_poll' автоматически вызывается для атрибутов sysfs? –

+0

Да, опрос пользователя() подключается через VFS и в конечном итоге к sysfs_poll(). Это сторона, которая ждет изменений. Сторона, которая производит изменения, вызывает sysfs_notify(), чтобы активировать активную sysfs_poll(). – Peter

+0

Спасибо вам за ваше редактирование и ответ.Я уже видел эту ссылку, Вильхельм, и понял, о чем вы говорите, Питер. Я собираюсь изменить вопрос, чтобы сфокусироваться. У меня есть примеры кода, которые были вычеркнуты из Интернета и написаны самим собой, что не работают. Может быть, вы можете взглянуть. – Digilee