feat(select): poll/select and fd_set
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
#ifndef VLIBC_POLL_H
|
||||
#define VLIBC_POLL_H
|
||||
|
||||
/*
|
||||
* vlibc — <poll.h>.
|
||||
*
|
||||
* Poll multiple file descriptors for readiness. Every declaration here is a
|
||||
* thin pass-through to the kernel: poll() blocks per its millisecond
|
||||
* timeout, ppoll() takes a struct timespec and an optional signal mask
|
||||
* directly, and both return the count of ready descriptors (0 on timeout,
|
||||
* -1 with errno set on error).
|
||||
*
|
||||
* Level 1 (onlyposix): poll, nfds_t, struct pollfd, the POLL* event bits.
|
||||
* Level 2 (muslmimic): ppoll (Linux-specific; POSIX has only poll).
|
||||
*
|
||||
* struct pollfd and the POLL* values mirror the kernel ABI (x86_64
|
||||
* asm-generic/poll.h) exactly: the wrappers pass them to SYS_ppoll
|
||||
* unmodified. POLLERR, POLLHUP and POLLNVAL are report-only — they can
|
||||
* appear in revents even when not requested in events.
|
||||
*
|
||||
* The signal mask type ppoll takes is declared under the shared guard
|
||||
* below; <signal.h> is its canonical POSIX home and will own the full sig*
|
||||
* API.
|
||||
*/
|
||||
|
||||
#include <vlibc/features.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Requestable event bits (poll()'s events field). */
|
||||
#define POLLIN 0x001 /* readable */
|
||||
#define POLLPRI 0x002 /* urgent readable (out-of-band) */
|
||||
#define POLLOUT 0x004 /* writable */
|
||||
|
||||
/* Report-only event bits (poll()'s revents field). */
|
||||
#define POLLERR 0x008 /* error condition */
|
||||
#define POLLHUP 0x010 /* hung up */
|
||||
#define POLLNVAL 0x020 /* invalid fd */
|
||||
|
||||
/* The number of struct pollfd entries poll()/ppoll() watch. */
|
||||
typedef unsigned long nfds_t;
|
||||
|
||||
/*
|
||||
* One descriptor watched by poll()/ppoll(). fd is the descriptor (negative
|
||||
* to ignore), events the requested bits (POLLIN/POLLOUT), revents the bits
|
||||
* the kernel reports (the requested bits plus any POLLERR/POLLHUP/POLLNVAL).
|
||||
*/
|
||||
struct pollfd
|
||||
{
|
||||
int fd;
|
||||
short events;
|
||||
short revents;
|
||||
};
|
||||
|
||||
/*
|
||||
* Wait for readiness on the first nfds entries of fds, blocking up to
|
||||
* timeout milliseconds (timeout < 0 blocks indefinitely, 0 never blocks).
|
||||
* Return the number of entries with a nonzero revents, 0 on timeout, or -1
|
||||
* with errno set on error.
|
||||
*/
|
||||
int
|
||||
poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
|
||||
#if VLIBC_LEVEL_GE(2)
|
||||
/* Level 2 (muslmimic): Linux-specific. */
|
||||
|
||||
#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). <signal.h> is the canonical POSIX home for sigset_t and builds
|
||||
* the sig* API on this same layout; the typedef is repeated in
|
||||
* <sys/select.h> under this guard so the two headers stay consistent.
|
||||
*/
|
||||
typedef unsigned long sigset_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Like poll(), 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).
|
||||
* Linux-specific.
|
||||
*/
|
||||
int
|
||||
ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask);
|
||||
|
||||
#endif /* VLIBC_LEVEL_GE(2) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* VLIBC_POLL_H */
|
||||
@@ -0,0 +1,120 @@
|
||||
#ifndef VLIBC_SYS_SELECT_H
|
||||
#define VLIBC_SYS_SELECT_H
|
||||
|
||||
/*
|
||||
* vlibc — <sys/select.h>.
|
||||
*
|
||||
* 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; <signal.h>
|
||||
* is its canonical POSIX home and will own the full sig* API.
|
||||
*/
|
||||
|
||||
#include <vlibc/features.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#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. <signal.h> is the canonical POSIX
|
||||
* home for sigset_t and builds the sig* API on this same layout; the
|
||||
* typedef is repeated in <poll.h> 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 */
|
||||
Reference in New Issue
Block a user