Provided by: manpages-pl-dev_0.5-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 */
       #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 || _XOPEN_SOURCE >= 600

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 (np. read(2)) bez blokowania.

       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  zapis  nie  spowoduje
       blokady, 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 minimalny  interwał  który  powinien  blokować  select()  czekając  na  gotowość
       deskryptora plików (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-2001).

       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-2001 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;  zbiory  deskryptorów  i  timeout  stają  się  niezdefiniowane,  więc  nie  należy  polegać na ich
       zawartości.

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 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 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 i w POSIX.1-2001.

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.

       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-2001  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 1003.1-2001 polega na  tym,  że  dla  select()  i  pselect()
       należy włączyć <sys/select.h>.

       Libc4 i libc5 nie zawierają pliku nagłówkowego <sys/select.h>; ten plik nagłówkowy istnieje w glibc 2.0 i
       późniejszych.  W  glibc  2.0  udostępnia on 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ą.

   Uwagi linuksowe
       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

       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-2001  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), 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  3.52  projektu  Linux man-pages. Opis projektu oraz
       informacje dotyczące zgłaszania błędów można znaleźć pod adresem http://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ą  3.52 oryginału.

Linux                                              2012-08-17                                          SELECT(2)