0

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 (mit init_waitqueue_head) die .poll zu signalisieren Handler in struct 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 von struct 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 Flag poll_evt_waiting auf 1 und ruft wake_up_interruptible in der Warteschlange auf, die mit der .poll-Methode von struct 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?

Antwort

0

wake_up_interruptible() Anruf auf der abgefragten Warteschlange zwingt nur die .poll Methode wieder aufgerufen werden. Benutzerbereich Prozess erhalten Benachrichtigung nur wenn.poll Methode zurückgibt Maske die abgefragten Bits gesetzt haben.

Überprüfen Sie, ob Ihre Methode .poll tatsächlich eine Maske ungleich null zurückgibt.

+0

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. –

Verwandte Themen