oracular (2) select.2.gz

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 ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩ 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⟩.