Problem mit poll oder select
-
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>:
**HalloIch 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 immerHat 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