focal (2) select.2.gz

Provided by: manpages-pl-dev_0.7-2_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.