roken: provide poll fallback

This commit is contained in:
Roland C. Dowdeswell
2026-05-24 18:34:54 +01:00
committed by Nico Williams
parent 6ce504ad84
commit 6efb8b405e
8 changed files with 334 additions and 4 deletions
+1 -1
View File
@@ -192,7 +192,6 @@ AC_CHECK_FUNCS([ \
mkdtemp \
mkostemp \
on_exit \
poll \
random \
secure_getenv \
setprogname \
@@ -360,6 +359,7 @@ AC_BROKEN([ \
mergesort \
mergesort_r \
mkstemp \
poll \
pread \
putenv \
rcmd \
-2
View File
@@ -41,8 +41,6 @@
#include <sys/un.h>
#endif
#include <poll.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
+3
View File
@@ -38,6 +38,7 @@ check_PROGRAMS = \
parse_bytes-test \
parse_reply-test \
parse_time-test \
poll-test \
snprintf-test \
strpftime-test \
timeval \
@@ -282,6 +283,8 @@ EXTRA_DIST = \
getline.c \
ndbm_wrap.c \
ndbm_wrap.h \
poll.c \
poll-test.c \
rename.c \
simple_exec_w32.c \
sleep.c \
+6 -1
View File
@@ -90,6 +90,7 @@ libroken_la_OBJS = \
$(OBJ)\parse_bytes.obj \
$(OBJ)\parse_time.obj \
$(OBJ)\parse_units.obj \
$(OBJ)\poll.obj \
$(OBJ)\pread.obj \
$(OBJ)\realloc.obj \
$(OBJ)\rename.obj \
@@ -214,6 +215,7 @@ TEST_PROGS = \
$(OBJ)\parse_bytes-test.exe \
$(OBJ)\parse_reply-test.exe \
$(OBJ)\parse_time-test.exe \
$(OBJ)\poll-test.exe \
$(OBJ)\snprintf-test.exe \
$(OBJ)\strpftime-test.exe \
$(OBJ)\dirent-test.exe \
@@ -246,6 +248,9 @@ $(OBJ)\test-readenv.exe: $(OBJ)\test-readenv.obj $(OBJ)\test-mem.obj $(LIBROKEN)
$(OBJ)\parse_time-test.exe: $(OBJ)\parse_time-test.obj $(OBJ)\test-mem.obj $(LIBROKEN)
$(EXECONLINK)
$(OBJ)\poll-test.exe: $(OBJ)\poll-test.obj $(LIBROKEN)
$(EXECONLINK)
$(OBJ)\strpftime-test.obj: strpftime-test.c
$(C2OBJ) -DTEST_STRPFTIME -DBUILD_ROKEN_LIB
@@ -307,9 +312,9 @@ test-run:
# Need to rewrite this test:
# -parse_reply-test.exe
-parse_time-test.exe
poll-test.exe
-snprintf-test.exe
-strpftime-test.exe
cd $(SRCDIR)
test:: test-binaries test-run
+131
View File
@@ -0,0 +1,131 @@
#include <config.h>
#include <roken.h>
static void
close_pair(rk_socket_t a, rk_socket_t b)
{
if (!rk_IS_BAD_SOCKET(a))
rk_closesocket(a);
if (!rk_IS_BAD_SOCKET(b))
rk_closesocket(b);
}
static int
connected_pair(rk_socket_t *a, rk_socket_t *b)
{
struct sockaddr_in sin;
socklen_t len = sizeof(sin);
rk_socket_t ls = rk_INVALID_SOCKET;
rk_socket_t cs = rk_INVALID_SOCKET;
rk_socket_t as = rk_INVALID_SOCKET;
int one = 1;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sin.sin_port = 0;
ls = socket(AF_INET, SOCK_STREAM, 0);
if (rk_IS_BAD_SOCKET(ls))
return rk_SOCK_ERRNO;
setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
if (rk_IS_SOCKET_ERROR(bind(ls, (struct sockaddr *)&sin, sizeof(sin))) ||
rk_IS_SOCKET_ERROR(listen(ls, 1)) ||
rk_IS_SOCKET_ERROR(getsockname(ls, (struct sockaddr *)&sin, &len))) {
int ret = rk_SOCK_ERRNO;
rk_closesocket(ls);
return ret;
}
cs = socket(AF_INET, SOCK_STREAM, 0);
if (rk_IS_BAD_SOCKET(cs)) {
int ret = rk_SOCK_ERRNO;
rk_closesocket(ls);
return ret;
}
if (rk_IS_SOCKET_ERROR(connect(cs, (struct sockaddr *)&sin, len))) {
int ret = rk_SOCK_ERRNO;
close_pair(ls, cs);
return ret;
}
as = accept(ls, NULL, NULL);
if (rk_IS_BAD_SOCKET(as)) {
int ret = rk_SOCK_ERRNO;
close_pair(ls, cs);
return ret;
}
rk_closesocket(ls);
*a = as;
*b = cs;
return 0;
}
int
main(int argc, char **argv)
{
struct pollfd pfd;
rk_socket_t a = rk_INVALID_SOCKET;
rk_socket_t b = rk_INVALID_SOCKET;
char c = 'x';
int ret;
setprogname(argv[0]);
ret = rk_SOCK_INIT();
if (ret)
err(1, "rk_SOCK_INIT");
ret = poll(NULL, 0, 0);
if (ret != 0)
errx(1, "poll with no fds returned %d", ret);
ret = connected_pair(&a, &b);
if (ret)
errx(1, "connected_pair failed: %d", ret);
pfd.fd = a;
pfd.events = POLLIN;
pfd.revents = 0;
ret = poll(&pfd, 1, 0);
if (ret != 0)
errx(1, "poll readable before send returned %d", ret);
if (pfd.revents != 0)
errx(1, "poll timeout left revents as %#x", pfd.revents);
ret = send(b, &c, 1, 0);
if (rk_IS_SOCKET_ERROR(ret))
err(1, "send");
pfd.fd = a;
pfd.events = POLLIN;
pfd.revents = 0;
ret = poll(&pfd, 1, 5000);
if (ret != 1)
errx(1, "poll readable after send returned %d", ret);
if ((pfd.revents & POLLIN) == 0)
errx(1, "poll readable missing POLLIN in %#x", pfd.revents);
ret = recv(a, &c, 1, 0);
if (rk_IS_SOCKET_ERROR(ret))
err(1, "recv");
if (ret != 1)
errx(1, "recv returned %d", ret);
pfd.fd = b;
pfd.events = POLLOUT;
pfd.revents = 0;
ret = poll(&pfd, 1, 5000);
if (ret != 1)
errx(1, "poll writable returned %d", ret);
if ((pfd.revents & POLLOUT) == 0)
errx(1, "poll writable missing POLLOUT in %#x", pfd.revents);
close_pair(a, b);
rk_SOCK_EXIT();
return 0;
}
+152
View File
@@ -0,0 +1,152 @@
#include <config.h>
#include "roken.h"
#ifndef HAVE_POLL
#ifdef HAVE_WINSOCK
#include <windows.h>
static int
poll_errno_from_winsock(void)
{
switch (WSAGetLastError()) {
case WSAEINTR:
return EINTR;
case WSAEINVAL:
return EINVAL;
case WSAENOTSOCK:
return EBADF;
default:
return EIO;
}
}
#endif
static void
poll_timeout(int timeout, struct timeval **tvp, struct timeval *tv)
{
if (timeout < 0) {
*tvp = NULL;
return;
}
tv->tv_sec = timeout / 1000;
tv->tv_usec = (timeout % 1000) * 1000;
*tvp = tv;
}
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
poll(struct pollfd fds[], nfds_t nfds, int timeout)
{
struct timeval tv, *tvp;
fd_set rfds, wfds, efds;
rk_socket_t maxfd = rk_INVALID_SOCKET;
int have_rfds = 0, have_wfds = 0, have_efds = 0;
int width, ret, nready = 0;
nfds_t i;
if (timeout < -1) {
errno = EINVAL;
return -1;
}
poll_timeout(timeout, &tvp, &tv);
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&efds);
for (i = 0; i < nfds; i++) {
short events;
fds[i].revents = 0;
if (rk_IS_BAD_SOCKET(fds[i].fd))
continue;
#ifndef NO_LIMIT_FD_SETSIZE
if (fds[i].fd >= FD_SETSIZE) {
fds[i].revents = POLLNVAL;
nready++;
continue;
}
#endif
events = fds[i].events;
if (events & (POLLIN | POLLPRI)) {
FD_SET(fds[i].fd, &rfds);
have_rfds = 1;
}
if (events & POLLOUT) {
FD_SET(fds[i].fd, &wfds);
have_wfds = 1;
}
FD_SET(fds[i].fd, &efds);
have_efds = 1;
if (maxfd == rk_INVALID_SOCKET || fds[i].fd > maxfd)
maxfd = fds[i].fd;
}
if (nready)
return nready;
if (maxfd == rk_INVALID_SOCKET) {
#ifdef HAVE_WINSOCK
Sleep(timeout < 0 ? INFINITE : (DWORD)timeout);
return 0;
#else
return select(0, NULL, NULL, NULL, tvp);
#endif
}
#ifdef HAVE_WINSOCK
width = 0;
#else
width = maxfd + 1;
#endif
ret = select(width,
have_rfds ? &rfds : NULL,
have_wfds ? &wfds : NULL,
have_efds ? &efds : NULL,
tvp);
if (rk_IS_SOCKET_ERROR(ret)) {
#ifdef HAVE_WINSOCK
errno = poll_errno_from_winsock();
#endif
return -1;
}
if (ret == 0)
return 0;
nready = 0;
for (i = 0; i < nfds; i++) {
short revents = 0;
if (rk_IS_BAD_SOCKET(fds[i].fd))
continue;
#ifndef NO_LIMIT_FD_SETSIZE
if (fds[i].fd >= FD_SETSIZE)
continue;
#endif
if (have_rfds && FD_ISSET(fds[i].fd, &rfds))
revents |= fds[i].events & (POLLIN | POLLPRI);
if (have_wfds && FD_ISSET(fds[i].fd, &wfds))
revents |= POLLOUT;
if (have_efds && FD_ISSET(fds[i].fd, &efds))
revents |= (fds[i].events & POLLPRI) ? POLLPRI : POLLERR;
fds[i].revents = revents;
if (revents)
nready++;
}
return nready;
}
#endif /* !HAVE_POLL */
+40
View File
@@ -192,6 +192,46 @@ static inline ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL rk_SOCK_INIT(void) {
#endif /* WinSock */
#ifdef HAVE_POLL_H
#include <poll.h>
#else
/*
* poll(2) compatibility. Windows may provide struct pollfd and the
* POLL* constants through winsock2.h even though it has no <poll.h>.
*/
typedef unsigned long nfds_t;
# ifndef POLLIN
struct pollfd {
rk_socket_t fd;
short events;
short revents;
};
# endif
# ifndef POLLIN
# define POLLIN 0x0001
# endif
# ifndef POLLPRI
# define POLLPRI 0x0002
# endif
# ifndef POLLOUT
# define POLLOUT 0x0004
# endif
# ifndef POLLERR
# define POLLERR 0x0008
# endif
# ifndef POLLHUP
# define POLLHUP 0x0010
# endif
# ifndef POLLNVAL
# define POLLNVAL 0x0020
# endif
#endif
#ifndef HAVE_POLL
#define poll rk_poll
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL poll(struct pollfd *, nfds_t, int);
#endif
#ifndef IN_LOOPBACKNET
#define IN_LOOPBACKNET 127
#endif
+1
View File
@@ -107,6 +107,7 @@ HEIMDAL_ROKEN_2.0 {
rk_pid_file_write;
rk_pidfile;
rk_pipe_execv;
rk_poll;
rk_print_flags_table;
rk_print_time_table;
rk_print_units_table;