Ich versuche, asynchron zwischen einem Kernel-Treiber und einem User-Space-Programm zu kommunizieren (ich weiß, es gibt viele Fragen hier, die nach ähnlichen Informationen fragen, aber ich konnte keine finden, die sich mit sysfs_notify befassen).Mit dem Linux-Aufruf sysfs_notify
Ich verlasse Vilhelms Bearbeitung hier, aber die Quelle zu einem einfachen Treiber mit sysfs und einem User-Space-Programm hinzufügen, um es abzufragen. Der Treiber funktioniert gut (ich habe das meiste davon aus dem Netz; es fehlen die Credits, aber ich konnte sie nicht finden, als ich sie wieder hinzufügte). Leider funktioniert das Abrufprogramm nicht. Es bringt immer Erfolg sofort zurück. Interessanterweise werden die revents-Mitglieder auf POLLERR | gesetzt, wenn ich die beiden Lesevorgänge vor der Umfrage nicht ausführe POLLIN statt nur POLLIN, wie in der Programmausgabe zu sehen ist.
Programmausgabe:
root @ ubuntu:/home/wmulcahy/demo # ./readhello
ausgelöst
Attribut Datei Wert: 74 (t) [0]
revents [0]: [1] 00000001
revents: 00000001
Hier ist der Fahrer: hello.c (man kann sehen, wo ich begann ...)
#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[] = {
¬ify.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");
Und hier ist die Umfrage Programm: 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.
Intern fügt der Patch jedem kobject auf dem System einen Warteschlangenkopf hinzu; Diese Warteschlange wird als Antwort auf einen Aufruf poll() in eine Abfragetabelle eingefügt. Der sysfs Code hat keine Möglichkeit zu wissen, wenn jedoch der Wert der angegebenen sysfs-Attribut hat sich geändert, so dass das Subsystem ein abfragbaren Attribut Implementierung muss explizit Anrufe vor:
void sysfs_notify(struct kobject *kobj, char *dir, char *attr);
Danke, Lee
Wird 'sysfs_poll' nicht automatisch für sysfs-Attribute aufgerufen? –
Ja, user-space poll() verbindet sich über das VFS und schließlich mit sysfs_poll(). Das ist die Seite, die auf Veränderungen wartet. Die Seite, die die Änderungen erzeugt, ruft sysfs_notify() auf, um eine aktive sysfs_poll() zu aktivieren. – Peter
Vielen Dank für Ihre Bearbeitung und Antwort.Ich habe diese Referenz bereits gesehen, Vilhelm, und verstanden, was Sie sagen, Peter. Ich werde die Frage bearbeiten, um ihren Fokus zu ändern. Ich habe einige Codebeispiele, die beide aus dem Internet stammen und von mir geschrieben wurden, die nicht funktionieren. Vielleicht kannst du einen Blick darauf werfen. – Digilee