Problem mit poll oder select



  • Hallo

    Ich habe ein Problem mit der Treiberfunktion poll, vielleich kann mir jemand helfen. Die Funktion im Teiber sieht folgendermassen aus:

    wait_queue_head_t Wait;
    
    void init()
    {
      init_waitqueue_head(&Wait);
    }
    
    void interrupt()
    {
      wake_up_interruptible(&Wait);
    }
    
    static unsigned poll(struct file *file, poll_table *wait)
    {
      poll_wait(file, &Wait, wait);
      return POLLIN | POLLRDNORM;
    }
    

    Das dazugehörende select() rufe ich so auf:

    int Device = open(aDeviceName, O_RDONLY); //öffen funktioniert
    
      fd_set FdSet;
      FD_ZERO(&FdSet);
      FD_SET(Device, &FdSet);
    
      select(Device + 1, &FdSet, 0, 0, 0); // select gibt 1 zurück
    

    Nach dem Aufruf von select wird die Funktion poll aufgerufen, aber poll_wait() blockiert nicht. Woran kann das liegen? Mein Kernel hat die Version 2.4.19.

    Gruss sam



  • Hi,

    also wo gibt es denn Informationen zur 'poll_wait'-Funktion? Bei google hab ich
    nichts gescheites gefunden, ausser irgendwelche Aufrufe, die aber nicht die
    Funktion ansich erklaeren.

    Ich habe manpages in google zu 'poll_wait' gefunden, die jedoch eine 'poll_wait'-
    Funktion beschreiben, die erstens ab Kernel 2.1+ (also schon lange her) und
    zweitens nur 2 Parameter haben.

    Im Buch 'Linux/Unix Systemprogrammierung' sowie im Buch 'Programmieren von Unix-
    Netzwerken steht nichts zu dieser Funktion.

    Auf meinem System (FreeBSD) gibt es keine 'poll_wait'-Funktion.

    Wo stehen Informationen zu dieser Funktion?

    mfg
    v R



  • Danke erstmals für dein Intresse.
    Die Erklährung zu dieser Funktion steht im Buch "Linux Kernelprogrammierung Algorithmen und Strukturen der Version 2.2" oder hier http://www.oreilly.de/german/freebooks/linuxdrive2ger/exselect.html . Das ganze ist so einfach, dass es eigentlich funktionieren müsste - ich verstehe das nicht. Kann auch sein, dass das Problem bei select() selbst liegt. Die Informationen zu select() habe ich aus den manpages.



  • Hi,

    also an select sollte es, denke ich nicht liegen, da select ja mit dem Aufruf
    von poll nichts mehr zu tun hat. Wenn ich deine select-Anweisung richtig deute,
    dann bedeutet sie folgendes (sehr einfach ausgedrueckt)

    Blockiere, solange von der Descriptorenmenge 'Device + 1' _nicht_ gelesen werden
    kann (timeout ist 0).

    Da aber von deinem Device gelesen werden kann, kehr 'select' sofort mit dem
    Rueckgabewert '1' zurueck.

    Hmmm...ansonsten muss ich leider passen, denke ich. Aber vielleicht hilft ja
    folgendes, was ich aus der URL, die du gepostet hast, gelesen hab:

    Wenn keiner der gepollten Treiber anzeigt, daß I/O ohne Blockieren möglich ist,
    schläft der poll-Aufruf einfach, bis eine der (möglicherweise vielen)
    Warteschlangen aufwacht.

    und dieser Abschnitt:

    Das Interessante an der Implementation von poll ist, daß die Dateioperation mit
    einem NULL-Zeiger als poll_table-Argument aufgerufen werden kann. Diese Situation
    kann aus einer Reihe von Gründen entstehen. Wenn die Applikation, die poll
    aufruft, einen Timeout-Wert von 0 angegeben hat (und damit angezeigt hat, daß
    nicht gewartet werden soll), dann gibt es keinen Grund, die Warteschlangen
    anzusammeln, und das System tut das entsprechend auch nicht. Der
    poll_table-Zeiger wird auch unmittelbar, nachdem einer der gepollten Treiber
    anzeigt, daß I/O möglich ist, auf NULL gesetzt. Weil der Kernel an dieser Stelle
    weiß, daß nicht mehr gewartet werden muß, baut er keine Liste von Warteschlangen
    mehr auf.

    Sorry, wenn ich keine grosse hilfe bin. Ich werd mir aber 'poll_wait' nochmal
    anschauen (bin grad auf der Arbeit ;), wenn ich zu Hause bin.

    mfg
    v R



  • Original erstellt von <sam>:
    **Hallo

    Ich habe ein Problem mit der Treiberfunktion poll, vielleich kann mir jemand helfen. Die Funktion im Teiber sieht folgendermassen aus:

    wait_queue_head_t Wait;
    
    void init()
    {
      init_waitqueue_head(&Wait);
    }
    
    void interrupt()
    {
      wake_up_interruptible(&Wait);
    }
    
    static unsigned poll(struct file *file, poll_table *wait)
    {
      poll_wait(file, &Wait, wait);
      return POLLIN | POLLRDNORM;
    }
    

    Das dazugehörende select() rufe ich so auf:

    int Device = open(aDeviceName, O_RDONLY); //öffen funktioniert
      
      fd_set FdSet;
      FD_ZERO(&FdSet);
      FD_SET(Device, &FdSet);
      
      select(Device + 1, &FdSet, 0, 0, 0); // select gibt 1 zurück
    

    Nach dem Aufruf von select wird die Funktion poll aufgerufen, aber poll_wait() blockiert nicht. Woran kann das liegen? Mein Kernel hat die Version 2.4.19.

    Gruss sam**

    Soweit wie ich das Verstanden habe blockierst du ja auch gerade nicht oder habe ich da was übersehen ? Siehe POLLIN | POLLRDNORM heisst doch du kannst ohne zu blockieren vom devce lesen.

    poll_wait(file, &Wait, wait); fügt dein Programm meines wissens nur in die waitqueue ein hält den Prozess aber nicht an.

    Ach ja wenn du blockierend lesen willst solltest du vielleicht ein normales open versuchen das blockiert immer 😉

    Joe



  • Hallo virtuell Realisticer

    also an select sollte es, denke ich nicht liegen, da select ja mit dem Aufruf
    von poll nichts mehr zu tun hat. Wenn ich deine select-Anweisung richtig deute,
    dann bedeutet sie folgendes (sehr einfach ausgedrueckt)
    *

    Doch select() hat in meinem Beispiel schon was mit poll zu tuhen, poll ist das Gegenstück im Treiber.

    Blockiere, solange von der Descriptorenmenge 'Device + 1' _nicht_ gelesen werden
    kann (timeout ist 0).
    *

    Genau das probiere ich zu erreichen. Achtung timeout ist nicht 0, es wird ein null Zeiger übergeben.

    Da aber von deinem Device gelesen werden kann, kehr 'select' sofort mit dem
    Rueckgabewert '1' zurueck.

    Hmmm...ansonsten muss ich leider passen, denke ich. Aber vielleicht hilft ja
    folgendes, was ich aus der URL, die du gepostet hast, gelesen hab:

    Wenn keiner der gepollten Treiber anzeigt, daß I/O ohne Blockieren möglich ist,
    schläft der poll-Aufruf einfach, bis eine der (möglicherweise vielen)
    Warteschlangen aufwacht.
    *

    Wenn ich das richtig verstanden habe blockiere ich mit dem Aufruf poll_wait() und fahre nach dem Aufruf wake_up_interruptible() weiter (poll_wait wird verlassen). 😕

    und dieser Abschnitt:

    Das Interessante an der Implementation von poll ist, daß die Dateioperation mit
    einem NULL-Zeiger als poll_table-Argument aufgerufen werden kann. Diese Situation
    kann aus einer Reihe von Gründen entstehen. Wenn die Applikation, die poll
    aufruft, einen Timeout-Wert von 0 angegeben hat (und damit angezeigt hat, daß
    nicht gewartet werden soll), dann gibt es keinen Grund, die Warteschlangen
    anzusammeln, und das System tut das entsprechend auch nicht. Der
    poll_table-Zeiger wird auch unmittelbar, nachdem einer der gepollten Treiber
    anzeigt, daß I/O möglich ist, auf NULL gesetzt. Weil der Kernel an dieser Stelle
    weiß, daß nicht mehr gewartet werden muß, baut er keine Liste von Warteschlangen
    mehr auf.
    *

    Der zeiger ist nicht null.

    Sorry, wenn ich keine grosse hilfe bin. Ich werd mir aber 'poll_wait' nochmal
    anschauen (bin grad auf der Arbeit , wenn ich zu Hause bin.
    *

    Danke für deine Hilfe.

    Gruss sam



  • Hallo JoeIntel

    Soweit wie ich das Verstanden habe blockierst du ja auch gerade nicht oder habe ich da was übersehen ? Siehe POLLIN | POLLRDNORM heisst doch du kannst ohne zu blockieren vom devce lesen.

    poll_wait(file, &Wait, wait); fügt dein Programm meines wissens nur in die waitqueue ein hält den Prozess aber nicht an.
    *

    Was muss ich denn anders machen, dass select() blockiert?

    Ach ja wenn du blockierend lesen willst solltest du vielleicht ein normales open versuchen das blockiert immer
    *

    Habe es auch schon mit for(;"Ever";); probiert. 😃

    gruss sam



  • Ach ja wenn du blockierend lesen willst solltest du vielleicht ein normales open
    versuchen das blockiert immer

    Hat er ja gemacht, er hat weder ein O_NONBLOCK noch ein O_NDELAY Flag beim oeffnen
    gesetzt.

    Achtung timeout ist nicht 0, es wird ein null Zeiger übergeben.

    select(Device + 1, &FdSet, 0, 0, 0);
    

    Hier hast du aber als 'timeout' 0 uebergeben.

    Genau das probiere ich zu erreichen

    Aber du hast das ja gemacht. 'select' blockiert nur nicht, weil du vom
    entsprechenden Device lesen kannst.

    Aber ich denke eher ich versteh hier was nicht richtig 😉

    mfg
    v R



    Hier hast du aber als 'timeout' 0 uebergeben.
    *

    Nein, hier wird null (kein Timeout) übergeben. Siehe Dekleration von select()
    select(int, fd_set*, fd_set*, fd_set*, struct timeval*);

    Aber du hast das ja gemacht. 'select' blockiert nur nicht, weil du vom
    entsprechenden Device lesen kannst.
    *

    Das sollte aber nicht so sein, denn wake_up_interruptible() wird nie aufgerufen und der Zeiger auf poll_table ist auch nicht null.

    Aber ich denke eher ich versteh hier was nicht richtig
    *

    Wie du meinen?



  • Original erstellt von <sam>:

    Was muss ich denn anders machen, dass select() blockiert?

    gruss sam[/QB]

    sleep_on(...) bzw. bei dir interruptible_sleep_on(...) sollte aber auch aufgerufen werden.

    Siehe Linux Device Drivers
    void poll_wait(...)

    This function puts the current process into a wait queue without shedulunig immediately. It is designed to be used by poll method od the device drivers.

    Das heist für mich aber immer noch. Wenn die wait queue nicht blockiert ist und in deinem Beispiel wird sie nicht blockiert dann geht auch das select einfach durch und sagt Daten sind da.

    Ich kenne natürlich deinen Code nicht genau, soweit wie ich es verstehe ist aber genau das dein Problem. Wenn du die Queue blockieren würdes (selbst ohne select) würdst du auch keine Endlosschleifen brauchen sondern der Prozess würde schlafen bis Daten da sind. Das ist ja da Ziel der Wait Queues.

    Joe



  • Du hast recht. Ich ging immer davon aus, dass poll_wait() wie interruptible_sleep_on() blockieren sollte. Ich rufe jetzt nach poll_wait() noch interruptible_sleep_on() auf und es funktioniert, select() blockiert jetzt endlich wie es soll. Es ist sogar möglich, währent der eine Thread über select() blockiert, mit einem anderen auf den Treiber zugreiffen zu können.
    Danke für deine Hilfe.



  • Ja, die Namen von so manchen Kernelfunktionen sind schon irreführend, so was ist mir auch schon oft passiert. Aber wenn man es sich genau überlegt kann es gar nicht sein. Denn die Funktion kann ja gar nicht wissen wie du die Queue schlafen legen willst, denn es gibt ja kein interruptible_poll_wait(...).

    Na ja, wenn es jetzt funktioniert ist es ja gut.

    Joe


Anmelden zum Antworten