Provided by:
manpages-pl-dev_20060617-1_all 
NAZWA
select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchroniczne
zwielokratnianie we/wy
SKŁADNIA
/* Zgodnie z POSIX 1003.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);
#define _XOPEN_SOURCE 600
#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);
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 czasu parametru timeout, który jest 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 przykmuje parametru sigmask i zachowuje
się, jak pselect() wywołane z NULL 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.
timeout jest górną granicą czasu, który upłynie przed zakończeniem
działania funkcji select(). Gdy przyjmie 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' i ponownie 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;
sigprocmask(SIG_SETMASK, &sigmask, &origmask);
ready = select(nfds, &readfds, &writefds, &exceptfds, timeout);
sigprocmask(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 odnośnie wersji POSIX 1003.1-2001 zobacz poniżej).
Niektóre programy wywołują select() z wszystkimi trzema zbiorami
pustymi, z n 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 struct timeval dla wielu select()ów w
pętli, bez powtórnej inicjacji. Należy traktować timeout jako
niezdefiniowany po zakończeniu 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ł.
EINVAL nfds jest ujemne lub wartość timeout jest nieprawidłowa.
ENOMEM nie można było przydzielić pamięci dla wewnętrznych tablic.
PRZYKŁAD
#include <stdio.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");
return 0;
}
ZGODNE Z
BSD 4.4 (funkcja select() pojawiła się pierwotnie w BSD 4.2). W
ogólności 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 IEEE Std 1003.1g-2000 (POSIX.1g) i w
POSIX 1003.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.
Odnośnie używanych typów, 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 1003.1-2001 sytuacja jest
następująca
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>.
Odnośnie do prototypów, klasyczna sytuacja polega na tym, że dla
select() należy włączyć <time.h>. 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>; w glibc
2.0 i późniejszymi ten plik nagłówkowy istnieje. W glibc 2.0 udostępnia
on bezwarunkowo błędny prototyp dla pselect(). W glibc 2.1-2.2.1
udostępnia on pselect(), jeżeli zdefiniowane jest _GNU_SOURCE. W glibc
2.2.2-2.2.4 udostępnia go natomiast, gdy zdefiniowane jest
_XOPEN_SOURCE i ma wartość 600 lub większą. Niewątpliwie, począwszy od
POSIX 1003.1-2001 plik ten powinien udostępniać prototyp standardowo.
WERSJE
pselect() został dodany do jadra Linuksa 2.6.16.
Wcześniej pselect() był emulowany w glibc (patrz również BŁĘDY
IMPLEMENTACJI).
UWAGI LINUKSOWE
Wywołanie systemowa pselect() 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.
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(). W systemach, które
nie mają pselect() niezawodne (i bardziej przenośne) przechwytywanie
sygnałów można osiągnąć, używając triku potoku do siebie (gdzie
procedura obsługi sygnału zapisuje bajt do potoku, którego drugi koniec
jest monitorowany przez select() w głównym programie).
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.
ZOBACZ TAKŻE
Samouczek z dyskusją i przykładami znajduje się w select_tut(2).
Rzeczy w nieokreślony sposób powiązane z tym można znaleźć w accept(2),
connect(2), poll(2), read(2), recv(2), send(2), sigprocmask(2),
write(2), epoll(7), feature_test_macros(7)