select(2) System Calls Manual select(2) BEZEICHNUNG select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO, fd_set - synchrones E/A-Zeitmultiplexverfahren BIBLIOTHEK Standard-C-Bibliothek (libc, -lc) UBERSICHT #include typedef /* */ fd_set; int select(int azdd, fd_set *_Nullable restrict lesedd, fd_set *_Nullable restrict schreibedd, fd_set *_Nullable restrict ausnahmedd, struct timeval *_Nullable restrict wartezeit); void FD_CLR(int fd, fd_set *gruppe); int FD_ISSET(int fd, fd_set *gruppe); void FD_SET(int fd, fd_set *gruppe); void FD_ZERO(fd_set *gruppe); int pselect(int azdd, fd_set *_Nullable restrict lesedd, fd_set *_Nullable restrict schreibedd, fd_set *_Nullable restrict ausnahmedd, const struct timespec *_Nullable restrict wartezeit, const sigset_t *_Nullable restrict sigmask); Mit Glibc erforderliche Feature-Test-Makros (siehe feature_test_macros(7)): pselect(): _POSIX_C_SOURCE >= 200112L BESCHREIBUNG WARNUNG: select() kann nur Datei-Deskriptoren-Nummern uberwachen, die kleiner als FD_SETSIZE (1024) sind. Fur viele modernen Anwendungen ist dies eine unangemessen kleine Begrenzung, aber diese Einschrankung wird sich nicht andern. Alle modernen Anwendungen sollten stattdessen poll(2) oder epoll(7) verwenden, die dieser Beschrankung nicht unterliegen. Mit der Funktion select() kann ein Programm mehrere Dateideskriptoren uberwachen und warten, bis ein oder mehrere der Dateideskriptoren >>bereit<< fur eine Klasse von E/A-Aktionen sind (z. B. Eingabe moglich). Ein Dateideskriptor gilt als bereit, wenn es moglich ist, eine entsprechende E/A-Aktionen (z.B. read (2) oder ein hinreichend kleines write(2) ohne zu blockieren) durchzufuhren. fd_set Ein Strukturtyp, der eine Reihe von Dateideskriptoren darstellen kann. Gemass POSIX ist die maximale Anzahl an Dateideskriptoren in einer Struktur fd_set der Wert des Makros FD_SETSIZE. Dateideskriptor-Gruppen Die hauptsachlichen Argumente von select() sind drei >>Gruppen<< von Dateideskriptoren (mit dem Typ fd_set deklariert), die es dem Aufrufenden erlauben, auf drei Ereignisklassen von der festgelegten Menge an Dateideskriptoren zu warten. Jedes der fd_set-Argumente kann als NULL angegeben werden, falls keine Dateideskriptoren fur die entsprechende Ereignisklasse beobachtet werden soll. Beachten Sie gut: Bei der Ruckkehr wird jede der Dateideskriptor-Gruppen so verandert, dass sie anzeigen, welche Datei-Deskriptoren derzeit >>bereit<< sind. Falls Sie daher select() innerhalb einer Schleife verwenden, mussen die Gruppen vor jedem Aufruf neu initialisiert werden. Der Inhalt einer Dateideskriptor-Gruppe kann mit den folgenden Makros bearbeitet werden: FD_ZERO() Dieses Makro loscht (entfernt alle Dateideskriptoren aus) gruppe. Es sollte als erster Schritt beim Initialisieren einer Dateideskriptor-Gruppe eingebunden werden. FD_SET() Dieses Makro fugt den Dateideskriptor fd zu gruppe hinzu. Das Hinzufugen eines bereits in gruppe vorhandenen Dateideskriptors ist ein Leerbefehl und lost keinen Fehler aus. FD_CLR() Dieses Makro entfernt den Dateideskriptor fd aus gruppe. Das Hinzufugen eines nicht in gruppe vorhandenen Dateideskriptors ist ein Leerbefehl und lost keinen Fehler aus. FD_ISSET() select() modifiziert den Inhalt der Gruppen entsprechend der nachfolgend bschriebenen Regeln. Nach dem Aufruf von select() kann mit dem Makro FD_ISSET() uberpruft werden, ob ein Dateideskriptor noch in einer Gruppe vorhanden ist. FD_ISSET() gibt einen von 0 verschiedenen Wert zuruck, falls der Dateideskriptor fd in gruppe vorhanden ist; falls nicht, wird 0 zuruckgegeben. Argumente Die Argumente von select() im Einzelnen: lesedd Die Dateideskriptoren in dieser Gruppe werden uberwacht, um festzustellen, ob sie bereit zum Lesen sind. Ein Dateideskriptor ist bereit zum Lesen, wenn ein Lesevorgang nicht blockiert; insbesondere ist ein Dateideskriptor auch bereit, wenn das Dateiende erreicht ist. Nachdem select() zuruckgekehrt ist, werden alle Dateideskriptoren aus lesedd entfernt, ausser jene, die bereit zum Lesen sind. schreibedd Die Dateideskriptoren in dieser Gruppe werden uberwacht, um festzustellen, ob sie bereit zum Schreiben sind. Ein Dateideskriptor ist bereit zum Schreiben, wenn ein Schreibvorgang nicht blockiert. Dennoch konnte ein grosser Schreibvorgang noch immer blockieren, selbst wenn ein Dateideskriptor als schreibbar angezeigt wird. Nachdem select() zuruckgekehrt ist, werden alle Dateideskriptoren aus schreibedd entfernt, ausser jene, die bereit zum Schreiben sind. ausnahmedd Die Dateideskriptoren in dieser Gruppe werden auf >>Ausnahmebedingungen<< uberwacht. Einige Beispiele fur Ausnahmebedingungen finden Sie in den Erlauterungen zu POLLPRI in poll(2). Nachdem select() zuruckgekehrt ist, werden alle Dateideskriptoren aus ausnahmedd entfernt, ausser jene, bei denen Ausnahmebedingungen aufgetreten sind. azdd Dieses Argument sollte auf die Nummer des am hochsten nummerierten Dateideskriptors in allen drei Gruppen plus 1 gesetzt werden. Der gekennzeichnete Dateideskriptor in jeder der drei Gruppen wird bis zu dieser Begrenzung gepruft (siehe aber FEHLER). wartezeit Das Argument wartezeit ist eine timeval-Struktur (nachfolgend beschrieben), welche das Intervall angibt, das select() warten sollte, bis ein Dateideskriptor bereit wird. Der Aufruf wird blockieren, bis entweder: o ein Dateideskriptor bereit wird, o der Aufruf durch einen Signal-Handler unterbrochen wird, oder o die Wartezeit ablauft. Beachten Sie, das das Intervall wartezeit auf die Auflosung der Systemuhr aufgerundet wird. Durch Verzogerungen beim Kernel-Scheduling kann dieser Wert nochmals etwas grosser werden. Falls beide Felder der Struktur timeval gleich 0 sind, kehrt select() sofort zuruck. (Das ist praktisch fur Polling). Falls wartezeit als NULL angegeben wurde, wird select() unendlich warten, bis ein Dateideskriptor bereit wird. pselect() Der Systemaufruf pselect() ermoglicht einer Anwendung, sicher zu warten, bis entweder ein Dateideskriptor bereit wird oder bis ein Signal empfangen wird. Das Verhalten von select() und pselect() ist bis die folgenden drei Unterschiede identisch: o select() verwendet fur Wartezeiten ein struct timeval (mit Sekunden und Mikrosekunden), wahrend pselect() stattdessen ein struct timespec (mit Sekunden und Nanosekunden) verwendet. o Wahrend select() das Argument wartezeit andern darf, um die verbleibende Zeit anzugeben, verandert pselect() dieses Argument nicht. o Die Funktion select() hat keinen Parameter sigmask und verhalt sich wie pselect, wenn ihr fur sigmask ein NULL ubergeben wird. sigmask ist ein Zeiger auf eine Signalmaske (siehe sigprocmask(2)); falls er ungleich NULL ist, ersetzt pselect() zuerst die aktuelle Signalmaske durch diejenige, auf die sigmask weist, erledigt danach die >>select<<-Funktion und stellt als Letztes die ursprungliche Signalmaske wieder her. (Falls sigmask nicht NULL ist, wird die Signalmaske wahrend des pselect()-Aufrufs nicht verandert.) Abgesehen von der unterschiedlichen Genauigkeit des wartezeit-Arguments ist der pselect()-Aufruf ready = pselect(azdd, &lesedd, &schreibedd, &ausnahmedd, wartezeit, &sigmask); ist aquivalent zur atomaren Ausfuhrung der folgenden Aufrufe: sigset_t origmask; pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); ready = select(azdd, &lesedd, &schreibedd, &ausnahmedd, wartezeit); pthread_sigmask(SIG_SETMASK, &origmask, NULL); Falls man auf die Verfugbarkeit eines Signals oder eines Dateideskriptors warten mochte, ist zur Vermeidung von Wettlaufsituationen (race conditions) eine atomare Prufung erforderlich, die von pselect() erledigt wird. (Angenommen, der Signal Handler setzt einen globalen Schalter und kehrt zuruck. Dann konnte eine Prufung dieses globalen Schalters gefolgt von einem Aufruf von select() auf unbestimmte Zeit hangen, wenn das Signal zwischen der Prufung und vor dem Aufruf von select() eintrifft. Im Gegensatz dazu ermoglicht es pselect() zuerst Signale zu blockieren, die eingetroffenen Signale abzuarbeiten und anschliessend pselect() mit der gewunschten sigmask aufzurufen, um Race Conditions zu vermeiden.) Die Wartezeit (timeout) Das Argument wartezeit fur select() ist eine Struktur des folgenden Typs: struct timeval { time_t tv_sec; /* Sekunden */ suseconds_t tv_usec; /* Mikrosekunden */ }; Das korrespondierende Argument fur pselect() ist eine timespec(3)-Struktur. Unter Linux modifiziert select() wartezeit, um die nicht schlafend verbrachte Zeit anzuzeigen; die meisten anderen Implementierungen tun das nicht. (POSIX.1 lasst beiderlei Verhalten zu.) Dies fuhrt zu Problemen sowohl bei der Portierung von Linux-Code, der wartezeit liest, auf andere Betriebssysteme als auch bei der Portierung von Code nach Linux, der eine struct timeval in einer Schleife fur mehrfache Aufrufe von select() nutzt, ohne sie erneut zu initialisieren. Gehen Sie davon aus, dass wartezeit nach der Ruckkehr aus select() nicht definiert ist. RUCKGABEWERT Bei Erfolg geben select() und pselect() die Anzahl der Datei-Deskriptoren in den drei zuruckgegebenen Deskriptor-Gruppen zuruck. (Das entspricht der Gesamtzahl von Bits, die in lesedd, schreibedd und ausnahmedd gesetzt sind.) Der Ruckgabewert kann 0 sein, falls die Wartezeit ablief, bevor der Dateideskriptor bereitstand. Bei einem Fehler wird -1 zuruckgegeben und errno wird gesetzt, um den Fehler anzuzeigen; die Dateideskriptor-Gruppen werden nicht verandert und wartezeit wird undefiniert. FEHLER EBADF In einer der Gruppen wurde ein ungultiger Dateideskriptor angegeben. (Vielleicht war es ein schon geschlossener Dateideskriptor oder einer, bei dem ein Fehler aufgetreten ist.) Lesen Sie aber auch FEHLER. EINTR Ein Signal wurde abgefangen; siehe signal(7). EINVAL azdd ist negativ oder ubersteigt die Ressourcenbegrenzung RLIMIT_NOFILE (siehe getrlimit(2)). EINVAL Der Wert von wartezeit ist ungultig. ENOMEM Speicher fur interne Tabellen konnte nicht bereitgestellt werden. VERSIONEN Unter einigen UNIX-Systemen kann select() mit dem Fehler EAGAIN fehlschlagen, falls es dem System nicht gelingt, kernelinterne Ressourcen zuzuweisen. Linux verwendet hierbei ENOMEM. POSIX legt diesen Fehler fur poll(2) aber nicht fur select() fest. Portable Anwendungen konnten in einer Schleife auf EAGAIN (wie auch auf EINTR) prufen. STANDARDS POSIX.1-2008. GESCHICHTE select() POSIX.1-2001, 4.4BSD (erschien zuerst in 4.2BSD). Im Allgemeinen von/nach nicht BSD-Systeme portabel, unterstutzt Klone der BSD-Socket-Schicht (einschliesslich System-V-Varianten). Beachten Sie allerdings, dass System-V-Varianten typischerweise die Variable >>wartezeit<< vor dem Zuruckkehren setzen, die BSD-Variante aber nicht. pselect() Linux 2.6.16. POSIX.1g, POSIX.1-2001. Vorher wurde es in der Glibc emuliert (siehe aber FEHLER). fd_set POSIX.1-2001. ANMERKUNGEN Der folgende Header stellt auch den Typ fd_set bereit: . Ein fd_set ist ein Puffer fester Grosse. Wird FD_CLR() oder FD_SET() mit einem Wert fur fd, der negativ, gleich gross oder grosser als FD_SETSIZE ist, ausgefuhrt, fuhrt dies zu nicht definiertem Verhalten. Desweiteren verlangt POSIX, dass fd ein gultiger Dateideskriptor ist. Das Verhalten von select() und pselect() ist von dem Schalter O_NONBLOCK nicht betroffen. Der Selbst-Pipe-Trick Auf Systemen, auf denen pselect() fehlt, kann ein zuverlassiges (und portableres) Abfangen von Signalen mit dem Selbst-Pipe-Trick erreicht werden. Bei dieser Technik schreibt ein Signal-Handler ein Byte in eine Pipe, dessen anderes Ende von select() im Hauptprogramm uberwacht wird. (Um mogliches Blockieren beim Schreiben in eine Pipe, die voll sein konnte, oder Lesen aus einer Pipe, die leer sein konnte, zu vermeiden, wird nicht blockierende E/A beim Auslesen und Schreiben in die Pipe verwandt.) Emulieren von usleep(3) Vor dem Aufkommen von usleep(3) gab es Code, der select wie folgt aufrief: alle drei Deskriptor-Gruppen leer, azdd gleich 0 und ein von NULL verschiedenes wartezeit als recht portabler Weg, um mit Auflosungen unterhalb einer Sekunde zu schlafen. Korrespondenz zwischen den Benachrichtigungen select() und poll() Innerhalb der Linux-Kernelquellen finden wir die folgenden Definitionen, die die Korrespondenz zwischen den lesbaren, schreibbaren und ausserordentlichen Zustandsbenachrichtigungen von select() und den durch poll(2) (und epoll(7)) bereitgestellten Ereignisbenachrichtigungen zeigt: #define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR) /* Bereit zum Lesen */ #define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR) /* Bereit zum Schreiben */ #define POLLEX_SET (EPOLLPRI) /* Aussergewohnliche Bedingung */ Multithreaded Anwendungen Falls ein Dateideskriptor, der durch select() uberwacht wird, in einem anderen Thread geschlossen wird, ist das Ergebnis nicht spezifiziert. Auf einigen UNIX-Systemen entblockt select() und kehrt mit einer Information zuruck, dass der Dateideskriptor bereit ist (eine nachfolgende E/A-Aktion wird wahrscheinlich mit einem Fehler fehlschlagen, ausser ein anderer Prozess hat den Dateideskriptor zwischen dem Zeitpunkt, zu dem select() zuruckkehrte, und dem Zeitpunkt, zu der die E/A-Aktion stattfindet, wieder geoffnet). Unter Linux (und einigen anderen Systemen) hat das Schliessen des Dateideskriptors in einem anderen Thread keinen Effekt auf select(). Zusammenfassend sollte jede Anwendung, die sich auf ein bestimmtes Verhalten in diesem Szenario abstutzt, als fehlerhaft betrachtet werden. Unterschiede C-Bibliothek/Kernel Der Linux-Kernel erlaubt Dateideskriptor-Gruppen beliebiger Grosse und bestimmt die Grosse der zu prufenden Gruppen durch den Wert von azdd. In der Glibc-Implementierung ist der Typ fd_set allerdings von fester Grosse. Siehe auch FEHLER. Die in dieser Seite beschriebene Schnittstelle von pselect() wird durch Glibc implementiert. Der darunterliegende Systemaufruf heisst pselect6(). Dieser Systemaufruf hat ein etwas anderes Verhalten als die Glibc-Wrapper-Funktion. Der Systemaufruf pselect6() von Linux verandert das Argument wartezeit. Die Glibc-Wrapper-Funktion versteckt dieses Verhalten durch Verwendung einer lokalen Variablen fur das Argument >>wartezeit<<, die an den Systemaufruf ubergeben wird. Daher verandert die Glibc-Funktion pselect() nicht ihr Argument wartezeit; dies ist das von POSIX.1-2001 verlangte Verhalten. Das finale Argument des Systemaufrufs pselect6() ist kein sigset_t *-Zeiger, sondern eine Struktur der folgenden Form: struct { const kernel_sigset_t *ss; /* Zeiger auf Signalgruppe */ size_t ss_len; /* Grosse (in Bytes) des Objekts, auf das durch >>ss<< gezeigt wird */ }; Dies erlaubt es dem Systemaufruf, sowohl einen Zeiger auf die Signalgruppe als auch seine Grosse zu ermitteln und dabei zu berucksichtigen, dass die meisten Architekturen eine maximale Anzahl von 6 Argumenten fur einen Systemaufruf erlauben. Siehe sigprocmask(2) fur eine Diskussion der Unterschiede zwischen der Ansicht des Kernels und der Ansicht der Libc bezuglich der Singalmenge. Geschichtliche Glibc-Details Glibc 2.0 stellte eine inkorrekte Version von pselect() bereit, die das Argument sigmask nicht akzeptierte. In den Glibc-Versionen von 2.1 bis 2.2.1 musste _GNU_SOURCE definiert werden, um die Deklaration von pselect() aus zu erhalten. FEHLER POSIX erlaubt einer Implementierung, eine oberer Begrenzung fur den Bereich von Dateideskriptoren, die in einer Dateideskriptor-Gruppe festgelegt werden konnen, zu definieren. Diese Begrenzung soll mittels der Konstanten FD_SETSIZE bekannt gemacht werden. Der Linux-Kernel erzwingt keine feste Begrenzung, aber die Glibc-Implementierung macht fd_set zu einem Typ fester Grosse, wobei FD_SETSIZE als 1024 definiert ist und die Makros FD_*() arbeiten entsprechend dieser Begrenzung. Um Dateideskriptoren grosser als 1024 zu uberwachen, verwenden Sie stattdessen poll(2) oder epoll(7). Die Implementierung der Argumente fd_set als Wert-Ergebnis-Argumente ist ein Design-Fehler, der in poll(2) und epoll(7) vermieden wurde. Laut POSIX sollte select() alle festgelegten Dateideskriptoren in den drei Dateideskriptor-Gruppen bis zur Grenze azdd-1 prufen. Allerdings ignoriert die aktuelle Implementierung jeden Dateideskriptor in diesen Gruppen, der grosser als die maximale Dateideskriptorennummer ist, die der Prozess derzeit offen hat. Laut POSIX sollte jeder solcher Dateideskriptoren, der in einer der drei Gruppen festgelegt ist, zu einem Fehler EBADF fuhren. Beginnend mit Version 2.1 stellt Glibc eine Emulation von pselect() bereit, die mittels sigprocmask(2) und select() implementiert wurde. Diese Implementierung blieb fur den starken Ressourcenwettlauf verwundbar, der durch das Design von pselect() vermieden werden sollte. Moderne Versionen der Glibc verwenden den (ressourcenwettlauffreien) pselect()-Systemaufruf auf Kerneln, die ihn bereitstellen. Unter Linux konnte select() einen Socket-Dateideskriptor als >>bereit zum Lesen<< melden, obwohl trotzdem ein folgendes Lesen blockiert. Dies konnte beispielsweise passieren, wenn Daten angekommen sind, aber bei genauerer Prufung die falsche Prufsumme haben und daher verworfen werden. Es mag andere Umstande geben, in denen ein Dateideskriptor falschlicherweise als bereit berichtet werden konnte. Daher mag es sicherer sein, O_NONBLOCK bei Sockets zu benutzen, die nicht blockieren sollen. Unter Linux verandert select() auch wartezeit falls der Aufruf durch ein Signal-Handler unterbrochen wird (d.h. den Fehler EINTR zuruckliefert). Dies wird von POSIX.1 nicht erlaubt. Der Linux-Systemaufruf pselect() zeigt das gleiche Verhalten, aber der Glibc-Wrapper versteckt das Verhalten, indem er intern wartezeit in eine lokale Variable kopiert und diese Variable an den Systemaufruf ubergibt. BEISPIELE #include #include #include #include int main(void) { int retval; fd_set rfds; struct timeval tv; /* stdin (fd 0) auf Eingaben uberwachen. */ FD_ZERO(&rfds); FD_SET(0, &rfds); /* Bis zu funf Sekunden warten. */ tv.tv_sec = 5; tv.tv_usec = 0; retval = select(1, &rfds, NULL, NULL, &tv); /* Nicht auf den Wert von tv beziehen! */ if (retval == -1) perror("select()"); else if (retval) printf("Daten sind jetzt verfugbar.\n"); /* FD_ISSET(0, &rfds) will be true. */ else printf("Keine Daten innerhalb von funf Sekunden.\n"); exit(EXIT_SUCCESS); } SIEHE AUCH accept(2), connect(2), poll(2), read(2), recv(2), restart_syscall(2), send(2), sigprocmask(2), write(2), timespec(3), epoll(7), time(7) Fur eine Anleitung mit Diskussionen und Beispielen lesen Sie select_tut(2). UBERSETZUNG Die deutsche Ubersetzung dieser Handbuchseite wurde von Martin Schulze , Daniel Kobras , Martin Eberhard Schauer , Mario Blattermann und Helge Kreutzmann erstellt. Diese Ubersetzung ist Freie Dokumentation; lesen Sie die GNU General Public License Version 3 oder neuer bezuglich der Copyright-Bedingungen. Es wird KEINE HAFTUNG ubernommen. Wenn Sie Fehler in der Ubersetzung dieser Handbuchseite finden, schicken Sie bitte eine E-Mail an die Mailingliste der Ubersetzer . Linux man-pages 6.12 3. November 2024 select(2)