#ifndef VLIBC_SYS_SELECT_H #define VLIBC_SYS_SELECT_H /* * vlibc — . * * Synchronous I/O multiplexing: wait for readiness on file-descriptor sets * with select() or pselect(). Both are thin wrappers over the SYS_pselect6 * kernel ABI, (nfds, readfds, writefds, exceptfds, struct timespec *, * { sigset_t *, size_t } *): pselect passes its timespec and optional signal * mask straight through, select converts its struct timeval timeout to a * timespec and passes a NULL sigset pair. * * Level 1 (onlyposix): select, pselect, FD_* macros, fd_set, struct * timeval. * * fd_set is the kernel's bitmap layout on x86_64: an array of unsigned long * words, with descriptor d held in bit d % 64 of word d / 64. FD_SETSIZE * caps the tracked descriptors at 1024 (16 words), so select()/pselect() * must be called with nfds <= FD_SETSIZE and FD_SET() only ever receives * descriptors below FD_SETSIZE. select() and pselect() report the number of * ready descriptors, 0 on timeout, or -1 with errno set on error. * * The signal mask type is declared here under the shared guard; * is its canonical POSIX home and will own the full sig* API. */ #include #include #include #ifdef __cplusplus extern "C" { #endif /* Maximum descriptors select()/pselect() track (fd_set's bit capacity). */ #define FD_SETSIZE 1024 /* * A set of file descriptors, one bit per descriptor, stored in the kernel * bitmap layout: an array of unsigned long words, bit d in word * d / (8 * sizeof(unsigned long)). Descriptors 0..FD_SETSIZE-1 fit; no * operation may touch a descriptor at or above FD_SETSIZE. */ typedef struct { unsigned long fds_bits[FD_SETSIZE / (8 * sizeof(unsigned long))]; } fd_set; /* The word holding bit d of an fd_set, and that bit's mask within the word. */ #define VLIBC_FDS_WORD(d) ((d) / (8 * sizeof(unsigned long))) #define VLIBC_FDS_MASK(d) (1UL << ((d) % (8 * sizeof(unsigned long)))) /* Clear every descriptor bit of set. */ #define FD_ZERO(set) \ do \ { \ size_t fd_zero_i; \ for (fd_zero_i = 0; fd_zero_i < sizeof(fd_set) / sizeof(unsigned long); fd_zero_i++) \ { \ (set)->fds_bits[fd_zero_i] = 0UL; \ } \ } while (0) /* Add descriptor d to set. */ #define FD_SET(d, set) ((set)->fds_bits[VLIBC_FDS_WORD(d)] |= VLIBC_FDS_MASK(d)) /* Remove descriptor d from set. */ #define FD_CLR(d, set) ((set)->fds_bits[VLIBC_FDS_WORD(d)] &= ~VLIBC_FDS_MASK(d)) /* Nonzero when descriptor d is a member of set. */ #define FD_ISSET(d, set) ((set)->fds_bits[VLIBC_FDS_WORD(d)] & VLIBC_FDS_MASK(d)) #ifndef VLIBC_SIGSET_T_DEFINED #define VLIBC_SIGSET_T_DEFINED /* * Signal mask type: a single 64-bit word — the x86_64 Linux sigset_t (see * setjmp.h). pselect() and ppoll() only ever forward a pointer to the * kernel, which reads the word directly. is the canonical POSIX * home for sigset_t and builds the sig* API on this same layout; the * typedef is repeated in under this guard so the two headers stay * consistent. */ typedef unsigned long sigset_t; #endif /* Elapsed time in seconds and microseconds (see select()'s timeout). */ struct timeval { time_t tv_sec; suseconds_t tv_usec; }; /* * Wait for readiness on the descriptors marked in readfds, writefds and * exceptfds (each may be NULL), up to nfds descriptors (the highest * descriptor in any set plus one). timeout is an upper bound on the wait; a * NULL timeout blocks indefinitely, { 0, 0 } never blocks. On return each * non-NULL set holds only its ready descriptors. Return the number of ready * descriptors across the sets, 0 on timeout, or -1 with errno set. */ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); /* * Like select(), but the timeout is a struct timespec and, when sigmask is * not NULL, the given signal mask is atomically installed for the duration * of the wait (the previous mask is restored before returning). */ int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask); #ifdef __cplusplus } #endif #endif /* VLIBC_SYS_SELECT_H */