Provided by: manpages-pl-dev_4.23.1-1_all bug

NAZWA

       select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO, fd_set - synchronicznie zwielokrotnia wejście/wyjście

BIBLIOTEKA

       Standardowa biblioteka C (libc, -lc)

SKŁADNIA

       #include <sys/select.h>

       typedef /* ... */ fd_set;

       int select(int nfds, fd_set *_Nullable restrict readfds,
                  fd_set *_Nullable restrict writefds,
                  fd_set *_Nullable restrict exceptfds,
                  struct timeval *_Nullable restrict timeout);

       void FD_CLR(int fd, fd_set *set);
       int  FD_ISSET(int fd, fd_set *set);
       void FD_SET(int fd, fd_set *set);
       void FD_ZERO(fd_set *set);

       int pselect(int nfds, fd_set *_Nullable restrict readfds,
                  fd_set *_Nullable restrict writefds,
                  fd_set *_Nullable restrict exceptfds,
                  const struct timespec *_Nullable restrict timeout,
                  const sigset_t *_Nullable restrict sigmask);

   Wymagane ustawienia makr biblioteki glibc (patrz feature_test_macros(7)):

       pselect():
           _POSIX_C_SOURCE >= 200112L

OPIS

       OSTRZEŻENIE:  select() potrafi monitorować deskryptory plików o numerach mniejszych niż FD_SETSIZE (1024)
       — limit nierozsądnie niewielki dla wielu współczesnych aplikacji — i  ograniczenie  to  nie  zmieni  się.
       Wszystkie  współczesne  aplikacje  powinny w zamian korzystać z poll(2) lub epoll(7), które nie mają tego
       ograniczenia.

       select() umożliwia programowi monitorowanie wielu deskryptorów plików i oczekiwanie aż jeden  lub  więcej
       deskryptorów  będzie  „gotowy”  na  wykonanie pewnej klasy operacji wejścia/wyjścia (np. możliwy odczyt).
       Deskryptor  pliku  jest  uważany  za  gotowy,  jeżeli  możliwe  jest  wykonanie  odpowiadającej  operacji
       wejścia/wyjścia (np. read(2) lub odpowiednio małe write(2)) bez blokowania.

   fd_set
       Typ  struktury  mogącej  reprezentować  zbiór  deskryptorów  pliku.  Zgodnie  z  POSIX, maksymalną liczbą
       deskryptorów pliku w strukturze fd_set jest wartość makra FD_SETSIZE.

   Zbiory deskryptorów pliku
       Podstawowymi argumentami select() są trzy „zbiory” deskryptorów pliku (zadeklarowane  jako  typ  fd_set),
       pozwalające  wywołującemu  na  oczekiwanie  na  trzy klasy zdarzeń na zadanym zbiorze deskryptorów pliku.
       Każdy argument fd_set można podać jako  NULL,  jeśli  dla  odpowiadającej  klasy  zdarzeń  nie  mają  być
       monitorowane deskryptory pliku.

       Proszę  zwrócić  szczególną  uwagę:  Po powrocie, każdy ze zbiorów deskryptorów pliku jest modyfikowany w
       miejscu, aby wskazać, które z deskryptorów pliku są aktualnie „gotowe”. Z tego  względu,  jeśli  select()
       jest używany w pętli, zbiory muszą być zainicjowane ponownie przed każdym wywołaniem.

       Zawartością zbiorów deskryptorów pliku można manipulować za pomocą następujących makr:

       FD_ZERO()
              Makro czyści (usuwa z niego wszystkie deskryptory pliku) set. Powinno być użyte jako pierwszy krok
              w inicjowaniu zbiorów deskryptorów pliku.

       FD_SET()
              Makro dodaje deskryptor pliku fd do zbioru set. Dodanie deskryptora pliku, który jest już obecny w
              zbiorze, jest instrukcją pustą i nie powoduje błędu.

       FD_CLR()
              Makro usuwa deskryptor pliku fd z zbioru set. Usunięcie deskryptora pliku, który nie jest obecny w
              zbiorze jest instrukcją pustą i nie powoduje błędu.

       FD_ISSET()
              select()  modyfikuje zawartość zbiorów, zgodnie z regułami opisanymi niżej. Po wywołaniu select(),
              można skorzystać z makra FD_ISSET(), aby sprawdzić, czy  deskryptor  pliku  jest  wciąż  obecny  w
              zbiorze.  FD_ISSET() zwraca wartość niezerową, jeśli deskryptor pliku fd jest obecny w zbiorze set
              i zero, gdy nie jest.

   Argumenty
       Argumenty select() są następujące:

       readfds
              Deskryptory pliku w tym zbiorze  są  monitorowane,  aby  sprawdzić,  czy  są  gotowe  do  odczytu.
              Deskryptor  pliku  jest  gotowy  do  odczytu,  jeśli  operacja  odczytu  nie  będzie  blokowała; w
              szczególności, deskryptor pliku jest również gotowy na końcu pliku.

              Po powrocie select(),  readfds  zostanie  wyczyszczone  ze  wszystkich  deskryptorów  pliku,  poza
              gotowymi do odczytu.

       writefds
              Deskryptory  pliku  w  tym  zbiorze  są  monitorowane,  aby  sprawdzić,  czy  są gotowe do zapisu.
              Deskryptor pliku jest gotowy do zapisu, jeśli wszystkie operacje zapisu nie będą blokowały. Jednak
              nawet gdy deskryptor pliku jest wskazywany jako zapisywalny, duży zapis może wciąż blokować.

              Po powrocie select(), writefds  zostanie  wyczyszczone  ze  wszystkich  deskryptorów  pliku,  poza
              gotowymi do zapisu.

       exceptfds
              Deskryptory  pliku  w tym zbiorze są monitorowane pod kątem „szczególnych okoliczności”. Przykłady
              takich szczególnych okoliczności opisano w podręczniku poll(2) odnośnie POLLPRI.

              Po powrocie select(), exceptfds zostanie wyczyszczone ze wszystkich deskryptorów pliku, poza tymi,
              dla których zaszły szczególne okoliczności.

       nfds   Argument ten powinien być ustawiony na najwyższy numer deskryptora  z  wszystkich  trzech  zbiorów
              plus  1.  Sprawdzany  jest  wskazany  deskryptor pliku w każdym zbiorze, do tego limitu (lecz zob.
              USTERKI).

       timeout
              Argument timeout jest strukturą timeval (pokazaną niżej),  określającą  interwał,  który  powinien
              blokować select(), czekając na gotowość deskryptora plików. Wywołanie będzie skutkowało blokadą do
              momentu aż:

              •  deskryptor pliku stanie się dostępny

              •  lub wywołanie zostanie przerwane procedurą obsługi sygnału

              •  albo wywołanie przeterminuje się

              Proszę  zauważyć,  że  interwał  zostanie zaokrąglony w górę do dokładności zegara, a występowanie
              opóźnienia planisty jądra oznacza, że ten interwał może być nieznacznie przekroczony.

              Jeśli oba pola struktury timeval mają wartość zero, select() niezwłocznie zakończy pracę (jest  to
              przydatne przy odpytywaniu).

              Jeśli  timeout  jest  równe  NULL,  select()  może blokować w nieskończoność, czekając na gotowość
              deskryptora pliku.

   pselect()
       Wywołanie systemowe  pselect()  pozwala  aplikacjom  na  bezpieczne  oczekiwanie,  do  momentu  uzyskania
       gotowości przez deskryptor plików lub do momentu przechwycenia sygnału.

       Funkcjonalność funkcji select() i pselect() jest identyczna, jeśli pominąć trzy różnice:

       •  Funkcja  select()  używa  dla  parametru  timeout  typu struct timeval (z sekundami i mikrosekundami),
          podczas gdy pselect() używa typu struct timespec (z sekundami i nanosekundami).

       •  Funkcja select() może aktualizować parametr timeout, aby  wskazać,  jak  dużo  czasu  minęło.  Funkcja
          pselect() nie zmienia tego parametru.

       •  Funkcja  select()  nie  przyjmuje  parametru sigmask i zachowuje się, jak pselect() wywołane z NULL-em
          przekazanym w sigmask.

       sigmask jest wskaźnikiem do maski sygnałów  (zobacz  sigprocmask(2)).  Jeśli  nie  jest  równe  NULL,  to
       pselect()  najpierw zastępuje bieżącą maskę sygnałów maską wskazywaną przez sigmask, a następnie wywołuje
       funkcję „select”, a po jej zakończeniu odtwarza oryginalną maskę sygnałów (jeśli sigmask wynosi NULL,  to
       maska sygnałów nie jest modyfikowana podczas wywołania pselect()).

       Poza różnicą w precyzji argumentu timeout, następujące wywołanie pselect():

           ready = pselect(nfds, &readfds, &writefds, &exceptfds,
                           timeout, &sigmask);

       jest odpowiednikiem niepodzielnego wykonania następujących funkcji:

           sigset_t origmask;

           pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
           ready = select(nfds, &readfds, &writefds, &exceptfds, timeout);
           pthread_sigmask(SIG_SETMASK, &origmask, NULL);

       Idea  pselect()  polega  na  tym,  że  gdy  chce  się oczekiwać na zdarzenie będące sygnałem lub czymś na
       deskryptorze pliku,  potrzebny  jest  atomowy  test  zapobiegający  sytuacjom  wyścigu.  (Przypuśćmy,  że
       procedura  obsługi  sygnału  ustawia  globalny  znacznik i kończy działanie. Wówczas, test tego znacznika
       globalnego, po którym następuje wywołanie select() może wisieć w  nieskończoność,  gdyby  sygnał  przybył
       natychmiast  po  teście, ale przed wywołaniem. Inaczej mówiąc, pselect zezwala na, najpierw, zablokowanie
       sygnałów, następnie obsłużenie  dostarczonych  sygnałów,  aby  wreszcie  wywołać  pselect()  z  pożądanym
       sigmask, unikając wyścigu).

   Przeterminowanie
       Argument timeout do select() jest strukturą następującego typu:

           struct timeval {
               time_t      tv_sec;         /* sekundy */
               suseconds_t tv_usec;        /* mikrosekundy */
           };

       Odpowiadającym argumentem pselect() jest struktura timespec(3).

       Pod  Linuksem  funkcja  select()  modyfikuje  timeout,  aby  odzwierciedlić  ilość  nieprzespanego czasu;
       większość innych implementacji tego nie robi (POSIX.1 dopuszcza oba te zachowania). Powoduje to problemy,
       zarówno gdy kod linuksowy odczytujący timeout zostanie przeniesiony na inne systemy operacyjne, jak i gdy
       kod przeniesiony pod Linuksa z innych  systemów  używa  ponownie  struktury  timeval  dla  wielu  wywołań
       select()   w  pętli,  bez  powtórnej  inicjacji.  Prosimy  rozważyć  traktowanie  wartości  timeout  jako
       niezdefiniowanej po zakończeniu funkcji select().

WARTOŚĆ ZWRACANA

       Po pomyślnym zakończeniu, select() i pselect() zwracają liczbę deskryptorów w zbiorach  deskryptorów  (to
       jest  całkowitą  liczbę  bitów  ustawioną  w readfds, writefds, exceptfds). Wartość zwracana może wynosić
       zero, jeśli czas oczekiwania upłynął zanim jakiś deskryptor plików stał się gotowy.

       Po błędzie zwracane jest -1 i ustawiane errno, wskazując błąd; zbiory deskryptorów nie są modyfikowane, a
       timeout staje się niezdefiniowane.

BŁĘDY

       EBADF  W jednym ze zbiorów przekazano niepoprawny deskryptor pliku (być może deskryptor  ten  został  już
              zamknięty lub wystąpił na nim inny błąd). Zob. jednak BŁĘDY.

       EINTR  Przechwycono sygnał, patrz signal(7).

       EINVAL nfds jest ujemne lub przekracza limit zasobów RLIMIT_NOFILE (zob. getrlimit(2)).

       EINVAL Wartość timeout jest nieprawidłowa.

       ENOMEM Nie można było przydzielić pamięci dla wewnętrznych tablic.

WERSJE

       Na  niektórych  innych systemach Uniksowych select() może zwrócić błąd EAGAIN jeśli systemowi nie uda się
       przydzielić wewnątrzjądrowych zasobów, zamiast ENOMEM, tak jak robi to Linux. POSIX przewiduje  ten  błąd
       dla  poll(2), lecz nie dla select(). Przenośne programy mogą chcieć sprawdzać EAGAIN w pętli, tak jak dla
       EINTR.

STANDARDY

       POSIX.1-2008.

HISTORIA

       select()
              POSIX.1-2001, 4.4BSD (pojawiło się pierwotnie w 4.2BSD).

              W ogólności jest przenośne do/z systemów  nie-BSD  wspierających  sklonowaną  warstwę  gniazd  BSD
              (włączając  warianty  Systemu V).  Jednakże  należy  zauważyć,  że  warianty  Systemu V zasadniczo
              ustawiają zmienną przeterminowania przed powrotem, ale wariant BSD tego nie robi.

       pselect()
              Linux 2.6.16.  POSIX.1g, POSIX.1-2001.

              Wcześniej był on emulowany w glibc (patrz również USTERKI).

       fd_set POSIX.1-2001.

UWAGI

       Następujący nagłówek zapewnia również typ fd_set: <sys/time.h>.

       fd_set jest buforem o stałym rozmiarze. Wykonanie FD_CLR() lub FD_SET() z  ujemną  wartością  fd  albo  z
       wartością  większą lub równą FD_SETSIZE spowoduje zachowanie niezdefiniowane. Ponadto POSIX wymaga, by fd
       był prawidłowym deskryptorem pliku.

       Na działanie select() i pselect() nie wpływa znacznik O_NONBLOCK.

   Sztuczka „potoku do siebie”
       W systemach, które nie mają pselect() niezawodne (i bardziej przenośne)  przechwytywanie  sygnałów  można
       osiągnąć,  używając  sztuczki  w  postaci  „potoku  do  siebie”. W tej technice procedura obsługi sygnału
       zapisuje bajt do potoku, którego drugi koniec jest monitorowany przez select() w głównym  programie.  Aby
       uniknąć  możliwego  zablokowania  przy pisaniu do potoku który może być pełny lub czytaniu z potoku który
       może być pusty, przy czytaniu z i pisaniu do potoku używane jest nieblokujące wejście/wyjście.

   Emulowanie usleep(3)
       Przed powstaniem usleep(3) niektóre programy używały wywołania  select()  z  wszystkimi  trzema  zbiorami
       pustymi,  z  nfds  równym  zeru  i  niezerowym  timeout.  Jest  to  całkiem przenośny sposób pauzowania z
       dokładnością subsekundową.

   Relacja pomiędzy powiadomieniami select() i poll()
       W źródłach jądra Linux można znaleźć następujące definicje pokazujące relację pomiędzy powiadomieniami  o
       warunkach:  odczytu,  zapisu i szczególnych okoliczności select(), a powiadomieniami zdarzeń zapewnianymi
       przez poll(2) i epoll(7):

           #define POLLIN_SET  (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN |
                                EPOLLHUP | EPOLLERR)
                              /* Gotowość do odczytu */
           #define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT |
                                EPOLLERR)
                              /* Gotowość do zapisu */
           #define POLLEX_SET  (EPOLLPRI)
                              /* Szczególne okoliczności */

   Aplikacje wielowątkowe
       Jeśli deskryptor plików monitorowany przez select() zostanie zamknięty w innym wątku,  to  rezultat  jest
       nieokreślony.  Na  niektórych  systemach  uniksowych  select()  odblokuje go i powróci wskazując, że dany
       deskryptor plików jest gotowy (kolejne operacje wyjścia/wyjścia prawdopodobnie zakończą się błędem, chyba
       że inny proces otworzy ponownie deskryptor  plików  w  czasie  pomiędzy  powrotem  select()  a  wykonanie
       operacji  wejścia/wyjścia.  W systemie Linux (i części innych) zamknięcie deskryptora pliku w innym wątku
       nie wpłynie na select(). Podsumowując, każda  aplikacja  polegająca  na  konkretnym  zachowaniu  w  takim
       przypadku musi być uznana za błędną.

   Różnice biblioteki C/jądra
       Jądro  Linux  pozwala  deskryptorowi  pliku  ustawić  dowolny  rozmiar,  na podstawie długości zbiorów do
       sprawdzenia z wartości nfds. Jednak w implementacji glibc, typ fd_set ma stały rozmiar. Zob. też USTERKI.

       Interfejs pselect() opisany w niniejszym podręczniku  jest  zaimplementowany  w  glibc.  Stojące  za  nim
       linuksowe  wywołanie  systemowe  nazywa  się  pselect6().  Cechuje go nieco inne zachowanie od opisywanej
       funkcji opakowującej glibc.

       Wywołanie systemowe pselect6() pod Linuksem modyfikuje argument timeout. Jednakże funkcja glibc ukrywa to
       zachowanie przez użycie dla argumentu timeout lokalnej zmiennej, która  jest  przekazywana  do  wywołania
       systemowego. Dlatego pselect() z glibc nie zmienia argumentu timeout, co jest zachowaniem wymaganym przez
       POSIX.1-2001.

       Ostatnim argumentem wywołania systemowego pselect6() nie jest wskaźnik sigset_t * lecz struktura postaci:

           struct {
               const kernel_sigset_t *ss;   /* Wskaźnik do zestawu sygnałów */
               size_t ss_len;               /* Rozmiar (w bajtach) obiektu, na
                                               który wskazuje 'ss' */
           };

       Pozwala to wywołaniu systemowemu pobrać oba wskaźniki do zestawu sygnałowego wraz z rozmiarem, biorąc pod
       uwagę,  że większość architektur obsługuje maksymalnie 6 argumentów do wywołania systemowego. Opis różnic
       pomiędzy podejściem jądra i libc do zestawu sygnałów znajduje się w podręczniku sigprocmask(2).

   Historyczne detale glibc
       glibc 2.0 dostarczała niepoprawną wersję pselect(), która nie przyjmowała argumentu sigmask.

       Od glibc 2.1 do glibc 2.2.1 konieczne było zdefiniowanie _GNU_SOURCE, aby uzyskać deklarację pselect()  z
       <sys/select.h>.

USTERKI

       POSIX  pozwala  implementacji  zdefiniować  górny  limit zakresu deskryptorów plików, które można podać w
       zbiorze deskryptora pliku, rozgłaszany stałą FD_SETSIZE. Jądro Linux nie  wymusza  stałego  limitu,  lecz
       implementacja glibc czyni fd_set typem o stałym rozmiarze, z FD_SETSIZE zdefiniowanym jako 1024 i makrami
       FD_*()  działającymi zgodnie z tym limitem. Aby monitorować deskryptory plików większe niż 1023, należy w
       zamian użyć poll(2) lub epoll(7).

       Implementacja argumentów fd_set jako argumentów wartość-wynik jest błędem projektowym, którego  uniknięto
       w poll(2) i epoll(7).

       Zgodnie  z  POSIX,  select()  powinien  sprawdzać  wszystkie  podane  deskryptory pliku w trzech zbiorach
       deskryptorów pliku, do limitu nfds-1. Jednak bieżąca implementacja ignoruje wszelkie deskryptory pliku  w
       tych zbiorach, które są wyższe od maksymalnego numeru aktualnie otwartego przez proces deskryptora pliku.
       Zgodnie  z POSIX, w przypadku wystąpienia takiego deskryptora pliku w jednym z zbiorów, powinien wystąpić
       błąd EBADF.

       Od  glibc  2.1,  glibc  dostarczała  emulację  pselect(),  która  była   zaimplementowana   przy   użyciu
       sigprocmask(2) i select(). Implementacja ta pozostaje podatna na wiele błędów wyścigów (race conditions),
       których  uniknięcie  stanowiło  ideę funkcji pselect(). Nowsze wersje glibc używają (wolnego od wyścigów)
       wywołania systemowego, jeśli tylko jądro dostarcza takiego wywołania.

       W Linuksie select() może raportować deskryptory plików gniazd jako „dostępne do  czytania”,  podczas  gdy
       kolejne  czytania  zostaną  zablokowane.  Może  to  się zdarzyć na przykład wtedy, gdy dane nadeszły, ale
       podczas sprawdzania okazało się, że mają złą sumę kontrolną i zostały odrzucone. Mogą wystąpić także inne
       sytuacje, w których deskryptor pliku jest błędnie raportowany jako gotowy. Dlatego używanie O_NONBLOCK na
       gniazdach, które nie powinny się blokować może być bezpieczniejsze.

       Pod Linuksem wywołanie select() zmienia  wartość  timeout  także  wtedy,  gdy  zostanie  przerwane  przez
       procedurę  obsługi  sygnału  (tj. zostanie zwrócony błąd EINTR). POSIX.1 nie pozwala na takie zachowanie.
       Wywołanie systemowe pselect() pod Linuksem zachowuje się tak samo,  ale  funkcja  opakowująca  biblioteki
       glibc  ukrywa  to  zachowanie, kopiując wartość timeout do wewnętrznej lokalnej zmiennej i przekazując tę
       zmienną do wywołania systemowego.

PRZYKŁADY

       #include <stdio.h>
       #include <stdlib.h>
       #include <sys/select.h>

       int
       main(void)
       {
           int             retval;
           fd_set          rfds;
           struct timeval  tv;

           /* Obserwacja stdin (fd 0) i sprawdzanie kiedy ma wejście. */

           FD_ZERO(&rfds);
           FD_SET(0, &rfds);

           /* Czekanie do pięciu sekund. */

           tv.tv_sec = 5;
           tv.tv_usec = 0;

           retval = select(1, &rfds, NULL, NULL, &tv);
           /* Nie należy już polegać na wartości tv! */

           if (retval == -1)
               perror("select()");
           else if (retval)
               printf("Dane są już dostępne.\n");
               /* FD_ISSET(0, &rfds) będzie prawdziwy. */
           else
               printf("Brak danych w ciągu pięciu sekund.\n");

           exit(EXIT_SUCCESS);
       }

ZOBACZ TAKŻE

       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)

       Samouczek z dyskusją i przykładami znajduje się w select_tut(2).

TŁUMACZENIE

       Autorami  polskiego  tłumaczenia  niniejszej  strony podręcznika są: Przemek Borys <pborys@dione.ids.pl>,
       Robert Luberda <robert@debian.org> i Michał Kułach <michal.kulach@gmail.com>

       Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje  o  warunkach  licencji  można  uzyskać
       zapoznając   się   z   GNU General Public License w wersji 3   lub  nowszej.  Nie  przyjmuje  się  ŻADNEJ
       ODPOWIEDZIALNOŚCI.

       Błędy w  tłumaczeniu  strony  podręcznika  prosimy  zgłaszać  na  adres  listy  dyskusyjnej  manpages-pl-
       list@lists.sourceforge.net.

Linux man-pages 6.8                              2 maja 2024 r.                                        select(2)