Ich schreibe einen Linux-Zeichentreiber für eine benutzerdefinierte Laborhardware, die an ein Entwicklungsboard mit einem langsamen ARM-SoC angehängt ist und versuchte, ein geeignetes Benachrichtigungssystem zu implementieren von Kernel-Space zu Benutzer-Space.Senden einer Umfrage/Auswählen eines Ereignisses von einem Timer-Handler über eine Warteschlange
Grundsätzlich lese ich Daten von der HW regelmäßig (alle 10 ms), verarbeite diese Daten über einige Filter im Kernelraum (dieser Teil ist in Ordnung), und benachrichtige den Benutzerraum, wenn einige Bedingungen erfüllt sind. Mein Ansatz ist, dass der User Space Daemon eine Benachrichtigung vom Treiber mit einem poll()
Systemaufruf wartet (natürlich, da ich dort auch einen Netzwerk-Socket überwache).
auf Treiberinitialisierung, I den Timer (mit
setup_timer
) erstellen, die die Funktion, die für das Lesen der Hardware nennen werden, stellen die GPIO dafür verwendet, und eine Warteschlange erstellen (mitinit_waitqueue_head
) die.poll
zu signalisieren Handler instruct file_operations
aus dem Timer-Handler. Dieser Teil scheint in Ordnung zu sein.Es gibt einen
.unlocked_ioctl
Handler zu setzen und die Bedingungen zu bekommen, aber dieser Teil funktioniert.meine
.read
Methode vonstruct file_operations
setzt nur ein einzelnes Byte mit dem Status auf Benutzerraum; Es blockiert nie, da es immer ein gültiges gibt (einschließlich des 'W' für "mehr Daten von den Sensoren warten").Sobald das Gerät geöffnet ist, aktiviere ich den Timer. Seine Handler-Funktion wird nach 10 ms aufgerufen, liest Daten von der HW, läuft durch den Filter und setzt den Timer erneut (mit
mod_timer
); Wenn die gefilterten Daten meinen Bedingungen entsprechen, ändert sie den Status, setzt ein Flagpoll_evt_waiting
auf 1 und ruftwake_up_interruptible
in der Warteschlange auf, die mit der.poll
-Methode vonstruct file_operations
geteilt wird. Diese Methode ist einfach:static unsigned int firflt_file_poll(struct file *filp, poll_table *wait) { unsigned int mask = 0; poll_wait(filp, &firflt_queue, wait); if (poll_evt_waiting != 0) { mask = POLLIN | POLLRDNORM; poll_evt_waiting = 0; } return mask; }
Problem ist: die poll()
in meinem Userspace-Daemon nie eine Benachrichtigung von dem Fahrer empfängt! Gibt es einen offensichtlichen Fehler in meinem Ansatz? Speziell in Bezug auf die Warteschlange? Ich habe nie zuvor die "andere Seite" einer Umfrage() implementiert und alle Informationen dazu von "Linux Device Drivers", 2005 ed. Erhalten.
Wenn ich den Gerätedateideskriptor kontinuierlich lese, kann ich die Statusänderungen aus dem Benutzerbereich sehen, aber das versetzt meinen Daemon in eine Busy-Schleife, was für die langsame CPU zu viel ist. Ich muss es wirklich in der Umfrage warten lassen, bis es etwas Neues gibt.
Auch die einzigen Operationen, die ich mit der Warteschlange tun, ist es mit init_waitqueue_head
initialisiert, es mit poll_evt_waiting
wenn Statusänderungen Aufwachen, und es poll_wait
in meinem .poll
Handler übergeben. Klingt dieser Ansatz?
Interessanterweise funktionierte es, nachdem ich die Art geändert habe, wie ich Flag 'poll_evt_waiting' gesetzt habe. Es sollte irgendwo eine unerwartete Konkurrenz geben. –