summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2023-05-12 20:48:31 +0100
committerEdward Thomson <ethomson@edwardthomson.com>2023-05-13 16:42:04 +0100
commit94f98400bf950aa9835ff9b04c724f2aa3ebd0fc (patch)
tree0dccc76a32683ac34918c8371bcb29f3b489e9bf
parentfad90428970e332153027773b517a1606c0efa1f (diff)
downloadlibgit2-94f98400bf950aa9835ff9b04c724f2aa3ebd0fc.tar.gz
posix: introduce p_poll emulation with select
Not all systems have poll(2); emulate it with select(2).
-rw-r--r--src/CMakeLists.txt5
-rw-r--r--src/libgit2/streams/socket.c9
-rw-r--r--src/util/git2_features.h.in3
-rw-r--r--src/util/posix.c54
-rw-r--r--src/util/posix.h19
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 <netdb.h>
# include <netinet/in.h>
# include <arpa/inet.h>
-# include <poll.h>
#else
# include <winsock2.h>
# include <ws2tcpip.h>
@@ -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 <poll.h>
+# 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