Rechercher une page de manuel
FD_SET
Langue: pl
Version: 2006\-03\-11 (ubuntu - 01/11/07)
Section: 2 (Appels système)
Sommaire
NAZWA
select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchroniczne zwielokratnianie we/wySK£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)
mondiale; les communications, les informations, les échanges de
biens ainsi que la pollution franchissent les frontières et
inondent notre globe.
Ceci implique une solidarité mondiale croissante ou des choix au
niveau mondial. En sommes-nous conscients ?
-+- Joachim Charles Hitzke -+-
Contenus ©2006-2008 Benjamin Poulain
Design ©2006-2008 Maxime Vantorre