feat(select): poll/select and fd_set
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
/*
|
||||
* poll: plain POSIX poll over SYS_ppoll with a NULL sigmask (Linux has no
|
||||
* separate poll syscall for >1024 fds; ppoll is the generic form). The
|
||||
* millisecond timeout is converted to the struct timespec the kernel
|
||||
* expects; a negative timeout means "block indefinitely" and stays NULL.
|
||||
*
|
||||
* The (nfds_t, int) parameter pair is the fixed POSIX signature, so the
|
||||
* easily-swappable-parameters warning does not apply.
|
||||
*/
|
||||
int
|
||||
poll(struct pollfd *fds, nfds_t nfds, // NOLINT(bugprone-easily-swappable-parameters)
|
||||
int timeout)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct timespec *tsp = NULL;
|
||||
|
||||
if (timeout >= 0)
|
||||
{
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (long)(timeout % 1000) * 1000000L;
|
||||
tsp = &ts;
|
||||
}
|
||||
return syscall_ret(__syscall5(SYS_ppoll, (long)fds, (long)nfds, (long)tsp, 0L, 0L));
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
#if VLIBC_LEVEL_GE(2)
|
||||
|
||||
/*
|
||||
* ppoll: Linux-specific poll over SYS_ppoll with a struct timespec timeout
|
||||
* and an optional signal mask (the kernel takes the mask and its size as
|
||||
* separate trailing arguments; the size is only announced — as the 8-byte
|
||||
* kernel sigset size — when a mask is actually given).
|
||||
*/
|
||||
int
|
||||
ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask)
|
||||
{
|
||||
return syscall_ret(__syscall5(SYS_ppoll, (long)fds, (long)nfds, (long)timeout, (long)sigmask,
|
||||
sigmask != NULL ? (long)sizeof(sigset_t) : 0L));
|
||||
}
|
||||
|
||||
#endif /* VLIBC_LEVEL_GE(2) */
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
/*
|
||||
* pselect: plain POSIX pselect over SYS_pselect6. Its 6th kernel argument is
|
||||
* a pointer to a { sigset_t *, size_t } pair (the kernel reads two words);
|
||||
* NULL means "leave the signal mask alone", so the pair is only supplied —
|
||||
* and only the 8-byte kernel sigset size announced — when sigmask is given.
|
||||
* The timeout passes through as a struct timespec (NULL = indefinite).
|
||||
*/
|
||||
int
|
||||
pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
const struct timespec *timeout, const sigset_t *sigmask)
|
||||
{
|
||||
long data[2];
|
||||
|
||||
data[0] = (long)sigmask;
|
||||
data[1] = (long)sizeof(sigset_t);
|
||||
return syscall_ret(__syscall6(SYS_pselect6, (long)nfds, (long)readfds, (long)writefds,
|
||||
(long)exceptfds, (long)timeout,
|
||||
sigmask != NULL ? (long)data : 0L));
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "../internal/syscall.h"
|
||||
|
||||
/*
|
||||
* select: plain POSIX select over SYS_pselect6. The kernel wants a struct
|
||||
* timespec, so the struct timeval timeout is converted here (NULL passes
|
||||
* through as "block indefinitely") and the sigset pair stays NULL: select
|
||||
* never changes the signal mask. select() and pselect() share this syscall
|
||||
* on Linux; the 6th argument of pselect6 is a { sigset_t *, size_t } pair
|
||||
* pointer that is NULL when the mask is left alone.
|
||||
*/
|
||||
int
|
||||
select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct timespec *tsp = NULL;
|
||||
|
||||
if (timeout != NULL)
|
||||
{
|
||||
if (timeout->tv_sec < 0 || timeout->tv_usec < 0 || timeout->tv_usec >= 1000000L)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
ts.tv_sec = timeout->tv_sec;
|
||||
ts.tv_nsec = (long)timeout->tv_usec * 1000;
|
||||
tsp = &ts;
|
||||
}
|
||||
return syscall_ret(__syscall6(SYS_pselect6, (long)nfds, (long)readfds, (long)writefds,
|
||||
(long)exceptfds, (long)tsp, 0L));
|
||||
}
|
||||
Reference in New Issue
Block a user