Provided by: manpages-pl-dev_0.7-1_all bug

NAZWA

       select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchroniczne zwielokrotnianie wejście/wyjście

SKŁADNIA

       /* Zgodnie z POSIX.1-2001, POSIX.1-2008 */
       #include <sys/select.h>

       /* Zgodnie z wcześniejszymi standardami */
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *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);

       #include <sys/select.h>

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

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

       pselect(): _POSIX_C_SOURCE >= 200112L

OPIS

       select()  i  pselect()  umożliwiają  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) bez blokowania lub odpowiednio małe write(2)).

       select() może monitorować wyłącznie numery deskryptorów  plików  mniejsze  niż  FD_SETSIZE;  poll(2)  nie
       posiada tego ograniczenia. Zob. BŁĘDY.

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

       (i)    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).

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

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

       Podglądane są trzy niezależne zestawy deskryptorów. Te, które są wymienione w readfds, będą obserwowane w
       celu  dowiedzenia  się,  czy nie ma tam jakichś znaków dostępnych do czytania (dokładniej, aby dowiedzieć
       się, czy read nie spowoduje zablokowania, deskryptor pliku jest również przygotowany  na  koniec  pliku).
       Deskryptory  wymienione  w writefds będą obserwowane w celu dowiedzenia się, czy jest dostępna przestrzeń
       do zapisu (choć duże zapisy wciąż  mogą  być  blokowane),  a  deskryptory  wymienione  w  exceptfds  będą
       obserwowane  w celu dowiedzenia się, czy nie ma na nich wyjątku. Przy wyjściu, zbiory te są modyfikowane,
       wskazując, które z deskryptorów zmieniły status. Każdy z tych trzech zbiorów deskryptorów plików może być
       przekazany jako NULL, jeżeli dla żadnego deskryptora pliku na ma potrzeby obserwowania odpowiedniej klasy
       zdarzeń.

       Do obsługi tych zbiorów udostępnione są cztery makra: FD_ZERO() czyści zbiór; FD_SET() i FD_CLR()  dodają
       lub usuwają ze zbioru podany deskryptor; FD_ISSET() sprawdza, czy deskryptor jest częścią zbioru. Jest to
       przydatne po zakończeniu select().

       nfds jest najwyższym numerem deskryptora z wszystkich trzech zbiorów plus 1.

       Argument  timeout  określa  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() zakończy pracę natychmiast jest to przydatne w uwspólnianiu). Jeśli
       timeout jest równe NULL (brak czasu przeterminowania), select() może blokować w nieskończoność.

       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.

       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
       Struktury czasu, których to dotyczy, są zdefiniowane w <sys/time.h> i wyglądają następująco

           struct timeval {
               long    tv_sec;         /* sekundy */
               long    tv_usec;        /* mikrosekundy */
           };

       i

           struct timespec {
               long    tv_sec;         /* sekundy */
               long    tv_nsec;        /* nanosekundy */
           };

       (Jednakże zobacz poniżej uwagi dotyczące POSIX.1).

       Niektóre programy wywołują 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ą.

       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). Może ona być zerowa, jeśli nastąpi
       przeterminowanie, nim coś ciekawego się zdarzy. Po błędzie, zwracane  jest  -1  i  odpowiednio  ustawiane
       errno aby wskazać 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).

       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

       pselect() został dodany w wersji 2.6.16 jądra Linuksa. Wcześniej pselect() był emulowany w  glibc  (patrz
       również BŁĘDY IMPLEMENTACJI).

ZGODNE Z

       select()  jest  zgodny z POSIX.1-2001, POSIX.1-2008 i BSD 4.4 (funkcja select() pojawiła się pierwotnie w
       BSD 4.2). 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ą timeout przed zakończeniem, ale wariant BSD tego nie robi.

       pselect() jest zdefiniowany w POSIX.1g, w POSIX.1-2001 i w POSIX.1-2008.

UWAGI

       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 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.

       Jeśli chodzi o używane typy, klasyczna sytuacja polega na tym, że oba pola struktury timeval są typu long
       (jak  pokazano  powyżej),  a  sama  struktura  jest  zdefiniowana  w  <sys/time.h>.  W POSIX.1 wygląda to
       następująco:

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

       przy czym struktura jest zdefiniowana w <sys/select.h>,  a  typy  time_t  i  suseconds_t  zdefiniowano  w
       <sys/types.h>.

       Jeśli chodzi o prototypy opisywanych funkcji, to klasyczna sytuacja polega na tym, że dla select() należy
       włączyć  <time.h>, natomiast sytuacja z POSIX.1 polega na tym, że dla select() i pselect() należy włączyć
       <sys/select.h>.

       W glibc 2.0 <sys/select.h> udostępnia bezwarunkowo błędny prototyp dla pselect(). W glibc 2.1 aż do 2.2.1
       udostępnia on pselect(), jeżeli zdefiniowane jest _GNU_SOURCE. Od glibc 2.2.2  wymagania  są  takie,  jak
       pokazano powyżej w rozdziale SKŁADNIA.

   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  otwarty  zostanie  inny  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  zestawów  do
       sprawdzenia z wartości nfds. Jednak w implementacji glibc, typ fd_set ma stały rozmiar. Zob. też BŁĘDY.

       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 sigset_t *ss;     /* Pointer to signal set */
               size_t          ss_len; /* Size (in bytes) of object pointed
                                          to by '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.

BŁĘDY IMPLEMENTACJI

       POSIX pozwala implementacji zdefiniować górny limit zakresu deskryptorów  plików,  które  można  podać  w
       zestawie  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).

       Glibc 2.0 dostarczała wersję pselect(), która nie przyjmowała argumentu sigmask.

       Od wersji 2.1 glibc dostarczał 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  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.

       Pod  Linuksem 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ŁAD

       #include <stdio.h>
       #include <stdlib.h>
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

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

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

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

           /* Czekanie nie dłużej niż 5 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 5 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),
       epoll(7), time(7)

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

O STRONIE

       Angielska wersja tej strony pochodzi z wydania 4.07 projektu Linux man-pages. Opis  projektu,  informacje
       dotyczące   zgłaszania   błędów,   oraz   najnowszą   wersję   oryginału   można   znaleźć   pod  adresem
       https://www.kernel.org/doc/man-pages/.

TŁUMACZENIE

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

       Polskie  tłumaczenie  jest  częścią  projektu  manpages-pl;  uwagi,  pomoc,  zgłaszanie błędów na stronie
       http://sourceforge.net/projects/manpages-pl/. Jest zgodne z wersją  4.07 oryginału.

Linux                                              2016-03-15                                          SELECT(2)