2013-05-03 5 views
6

Sto provando a comunicare in modo asincrono tra un driver del kernel e un programma di spazio utente (so che ci sono molte domande che richiedono informazioni simili, ma non trovo nessuno che si occupi di sysfs_notify).Uso della chiamata sysfs_notify Linux

Sto lasciando qui la modifica di Vilhelm, ma aggiungendo il sorgente a un semplice driver che utilizza sysfs e un programma user-space per il polling. Il driver funziona bene (ne ho preso la maggior parte dalla rete, mancano i crediti, ma non sono riuscito a trovarli quando sono tornato per aggiungerli). Sfortunatamente, il programma di polling non funziona. Restituisce sempre il successo immediatamente. È interessante notare che se non eseguo le due letture prima del sondaggio, i membri di Revents sono impostati su POLLERR | POLLIN anziché solo POLLIN come mostrato nell'output del programma.

output del programma:

root @ ubuntu:/home/wmulcahy/demo # ./readhello
innescato
valore di attributo di file: 74 (t) [0]
revents [0]: 00000001
revents [1]: 00000001

Ecco il driver: ciao.c (si può vedere dove ho iniziato ...)

#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"); 

E qui è il programma di sondaggio: 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.

Internamente, la patch aggiunge una coda di attesa a ogni kobject sul sistema ; quella coda viene inserita in una tabella di polling in risposta a una chiamata poll ( poll(). Il codice sysfs non ha alcun modo di sapere, tuttavia, quando il valore di un qualsiasi sysfs attributo è cambiato, in modo che il sottosistema attuazione di un attributo pollable deve effettuare chiamate esplicite a:

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

Grazie, Lee

risposta

7

Il polling di blocco proviene dal lato utente. Il codice utente può semplicemente dire al kernel a quali attributi è interessato, quindi bloccare in un poll() finché uno di essi non è cambiato.

Il sysfs_notify() è una chiamata sul lato kernel che rilascia lo spazio utente poll(). Dopo aver regolato il valore dell'attributo del kernel, è sufficiente chiamare lo sysfs_notify() per consentire a qualsiasi applicazione dello spazio utente di rispondere alle loro eccezionali poll().

Pensare allo poll() come "sottoscrizione" alle notifiche di una modifica in un attributo di interesse e sysfs_notify() come "pubblicazione" della modifica a qualsiasi sottoscrittore.

+0

Non viene chiamato 'sysfs_poll' per gli attributi sysfs? –

+0

Sì, sondaggio spazio utente() si connette tramite VFS ed eventualmente a sysfs_poll(). Questa è la parte che aspetta cambiamenti. Il lato che produce le modifiche chiama sysfs_notify() per riattivare un sysfs_poll() attivo. – Peter

+0

Grazie ad entrambi per la modifica e la risposta.Avevo già visto quel riferimento, Vilhelm, e ho capito cosa stai dicendo, Peter. Ho intenzione di modificare la domanda per cambiare il suo focus. Ho alcuni esempi di codice, entrambi estratti da internet e scritti da me stesso che non funzionano. Forse puoi dare un'occhiata. – Digilee