Files
mtkports/www-client/netsurf/compat/sys/select.h
T

108 lines
3.0 KiB
C

/*
* Minimal <sys/select.h> for the MontaukOS NetSurf port.
*
* MontaukOS has no select(). Readiness on a socket is expressed through the
* kernel's waitset (SYS_WAITSET_*), which is a different shape entirely, and
* stdio descriptors are not waitable objects at all.
*
* NetSurf's core uses select() in exactly one place -- content/fetch.c's
* fetch_fdset() collects descriptors from the registered fetchers, and the
* frontend's main loop selects over them plus its own input. With
* NETSURF_USE_CURL=NO no fetcher registers a descriptor, so the only fd that
* ever appears is the monkey frontend's stdin (fd 0).
*
* That makes a useful shim possible:
*
* - if any read descriptor is requested, report them ready immediately and
* let the caller block in read(). monkey is a line-driven REPL, so
* blocking on stdin is what it wants anyway.
* - otherwise sleep for the timeout so an idle loop does not spin.
*
* LIMITATION: because a requested read fd is always reported ready, scheduled
* callbacks do not fire while the process sits idle waiting for a command.
* That is fine for driving monkey by hand or by script, and it is wrong for
* anything with real network activity. When fetch_montauk lands it will
* register descriptors here and this needs replacing with a genuine
* waitset-backed implementation.
*/
#ifndef _MONTAUK_COMPAT_SYS_SELECT_H_
#define _MONTAUK_COMPAT_SYS_SELECT_H_
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#define FD_SETSIZE 64
typedef struct {
unsigned long fds_bits[(FD_SETSIZE + (8 * sizeof(unsigned long)) - 1) /
(8 * sizeof(unsigned long))];
} fd_set;
#define __NFDBITS (8 * (int) sizeof(unsigned long))
#define FD_ZERO(s) memset((s), 0, sizeof(fd_set))
#define FD_SET(fd, s) \
((void) ((s)->fds_bits[(fd) / __NFDBITS] |= \
(1UL << ((fd) % __NFDBITS))))
#define FD_CLR(fd, s) \
((void) ((s)->fds_bits[(fd) / __NFDBITS] &= \
~(1UL << ((fd) % __NFDBITS))))
#define FD_ISSET(fd, s) \
(((s)->fds_bits[(fd) / __NFDBITS] & (1UL << ((fd) % __NFDBITS))) != 0)
static inline int montauk_fdset_empty(const fd_set *s)
{
unsigned i;
if (s == NULL)
return 1;
for (i = 0; i < sizeof(s->fds_bits) / sizeof(s->fds_bits[0]); i++) {
if (s->fds_bits[i] != 0)
return 0;
}
return 1;
}
static inline int montauk_fdset_count(const fd_set *s, int nfds)
{
int fd, n = 0;
if (s == NULL)
return 0;
for (fd = 0; fd < nfds && fd < FD_SETSIZE; fd++) {
if (FD_ISSET(fd, s))
n++;
}
return n;
}
static inline int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout)
{
int ready;
if (writefds != NULL)
FD_ZERO(writefds);
if (exceptfds != NULL)
FD_ZERO(exceptfds);
if (montauk_fdset_empty(readfds) == 0) {
/* leave readfds as-is: every requested fd is "ready" */
return montauk_fdset_count(readfds, nfds);
}
ready = 0;
if (timeout != NULL) {
unsigned long usec = (unsigned long) timeout->tv_sec * 1000000UL +
(unsigned long) timeout->tv_usec;
if (usec != 0)
usleep(usec);
}
return ready;
}
#endif