From 94f98400bf950aa9835ff9b04c724f2aa3ebd0fc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 12 May 2023 20:48:31 +0100 Subject: posix: introduce p_poll emulation with select Not all systems have poll(2); emulate it with select(2). --- src/CMakeLists.txt | 5 ++++ src/libgit2/streams/socket.c | 9 ++++---- src/util/git2_features.h.in | 3 +++ src/util/posix.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ src/util/posix.h | 19 ++++++++++++++++ 5 files changed, 85 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 88d616cec..a00ab600a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -87,6 +87,11 @@ check_prototype_definition_safe(qsort_s check_function_exists(getentropy GIT_RAND_GETENTROPY) check_function_exists(getloadavg GIT_RAND_GETLOADAVG) +# poll + +check_symbol_exists(poll poll.h GIT_IO_POLL) +check_symbol_exists(select sys/select.h GIT_IO_SELECT) + # determine architecture of the machine if(CMAKE_SIZEOF_VOID_P EQUAL 8) diff --git a/src/libgit2/streams/socket.c b/src/libgit2/streams/socket.c index 0e0aa6934..ecbdf7b7d 100644 --- a/src/libgit2/streams/socket.c +++ b/src/libgit2/streams/socket.c @@ -20,7 +20,6 @@ # include # include # include -# include #else # include # include @@ -135,13 +134,13 @@ static int connect_with_timeout( fd.events = POLLOUT; fd.revents = 0; - error = poll(&fd, 1, timeout); + error = p_poll(&fd, 1, timeout); if (error == 0) { return GIT_TIMEOUT; } else if (error != 1) { return -1; - } else if ((fd.revents & (POLLHUP | POLLERR))) { + } else if ((fd.revents & (POLLPRI | POLLHUP | POLLERR))) { return handle_sockerr(socket); } else if ((fd.revents & POLLOUT) != POLLOUT) { git_error_set(GIT_ERROR_NET, @@ -236,7 +235,7 @@ static ssize_t socket_write( fd.events = POLLOUT; fd.revents = 0; - ret = poll(&fd, 1, st->parent.timeout); + ret = p_poll(&fd, 1, st->parent.timeout); if (ret == 1) { ret = p_send(st->s, data, len, 0); @@ -272,7 +271,7 @@ static ssize_t socket_read( fd.events = POLLIN; fd.revents = 0; - ret = poll(&fd, 1, st->parent.timeout); + ret = p_poll(&fd, 1, st->parent.timeout); if (ret == 1) { ret = p_recv(st->s, data, len, 0); diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index 18644c3cc..cf955122c 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -61,4 +61,7 @@ #cmakedefine GIT_RAND_GETENTROPY 1 #cmakedefine GIT_RAND_GETLOADAVG 1 +#cmakedefine GIT_IO_POLL 1 +#cmakedefine GIT_IO_SELECT 1 + #endif diff --git a/src/util/posix.c b/src/util/posix.c index b1f85dc94..cfc0e0751 100644 --- a/src/util/posix.c +++ b/src/util/posix.c @@ -301,3 +301,57 @@ int p_munmap(git_map *map) } #endif + +#if defined(GIT_IO_POLL) || defined(GIT_IO_WSAPOLL) + +/* Handled by posix.h; this test simplifies the final else */ + +#elif defined(GIT_IO_SELECT) + +int p_poll(struct pollfd *fds, unsigned int nfds, int timeout_ms) +{ + fd_set read_fds, write_fds, except_fds; + struct timeval timeout = { 0, 0 }; + unsigned int i; + int max_fd = -1, ret; + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + FD_ZERO(&except_fds); + + for (i = 0; i < nfds; i++) { + if ((fds[i].events & POLLIN)) + FD_SET(fds[i].fd, &read_fds); + + if ((fds[i].events & POLLOUT)) + FD_SET(fds[i].fd, &write_fds); + + if ((fds[i].events & POLLPRI)) + FD_SET(fds[i].fd, &except_fds); + + max_fd = MAX(max_fd, fds[i].fd); + } + + if (timeout_ms > 0) { + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms % 1000) * 1000; + } + + if ((ret = select(max_fd + 1, &read_fds, &write_fds, &except_fds, + timeout_ms < 0 ? NULL : &timeout)) < 0) + goto done; + + for (i = 0; i < nfds; i++) { + fds[i].revents = 0 | + FD_ISSET(fds[i].fd, &read_fds) ? POLLIN : 0 | + FD_ISSET(fds[i].fd, &write_fds) ? POLLOUT : 0 | + FD_ISSET(fds[i].fd, &except_fds) ? POLLPRI : 0; + } + +done: + return ret; +} + +#else +# error no poll compatible implementation +#endif diff --git a/src/util/posix.h b/src/util/posix.h index 607aa9dce..f516bb3cc 100644 --- a/src/util/posix.h +++ b/src/util/posix.h @@ -195,4 +195,23 @@ extern const char *p_gai_strerror(int ret); # define p_gai_strerror(c) gai_strerror(c) #endif /* NO_ADDRINFO */ +#ifdef GIT_IO_POLL +# include +# define p_poll poll +#else +# define POLLIN 0x01 +# define POLLPRI 0x02 +# define POLLOUT 0x04 +# define POLLERR 0x08 +# define POLLHUP 0x10 + +struct pollfd { + int fd; + short events; + short revents; +}; + +extern int p_poll(struct pollfd *fds, unsigned int nfds, int timeout); +#endif + #endif -- cgit v1.2.1