Implement the subset of poll() semantics needed by git in terms of select(), for use by the Interix port. Inspired by commit 6ed807f (Windows: A rudimentary poll() emulation, 2007-12-01). This will only poll on descriptors with value <= the maximum fd that select() can portably handle, FD_SETSIZE - 1. On Windows (and not on Unix), in principle git could permit higher fds as long as the number of descriptors used in a single select() call was limited to FD_SETSIZE; but such a facility would be rarely used, since the number of sockets the ‘git daemon’ parent process keeps open tends to be very small. Helped-by: Erik Faye-Lund <kusmabite@xxxxxxxxxxxxxx> Cc: Johannes Sixt <j6t@xxxxxxxx> Cc: Jonathan Callen <abcd@xxxxxxxxxx> Signed-off-by: Jonathan Nieder <jrnieder@xxxxxxxxx> --- Erik Faye-Lund wrote: > But perhaps you should include a check along the lines of this: > > if (nfds > FD_SETSIZE) > return errno = EINVAL, error("poll: nfds must be below %d", FD_SETSIZE); > > Just so we can know when the code fails :) Good catch, thanks. I opted to check each fd instead so the NO_POLL code can be safely used on Unix for debugging. Other changes from v1: . use COMPAT_CFLAGS instead of BASIC_CFLAGS . timeout is a number of milliseconds, not seconds . lightly tested on Linux I would be interested to hear whether this works on msysgit and Interix. Thanks again for the help. Makefile | 8 +++++++ compat/poll.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ compat/poll.h | 13 ++++++++++++ git-compat-util.h | 6 ++++- 4 files changed, 82 insertions(+), 1 deletions(-) create mode 100644 compat/poll.c create mode 100644 compat/poll.h diff --git a/Makefile b/Makefile index 2f5d631..ed9f03b 100644 --- a/Makefile +++ b/Makefile @@ -111,6 +111,9 @@ all:: # # Define NO_PTHREADS if you do not have or do not want to use Pthreads. # +# Define NO_POLL if you have a problem with the poll() system call (e.g. +# Interix). +# # Define NO_PREAD if you have a problem with pread() system call (e.g. # cygwin1.dll before v1.5.22). # @@ -470,6 +473,7 @@ LIB_H += commit.h LIB_H += compat/bswap.h LIB_H += compat/cygwin.h LIB_H += compat/mingw.h +LIB_H += compat/poll.h LIB_H += compat/win32/pthread.h LIB_H += csum-file.h LIB_H += decorate.h @@ -1284,6 +1288,10 @@ endif ifdef OBJECT_CREATION_USES_RENAMES COMPAT_CFLAGS += -DOBJECT_CREATION_MODE=1 endif +ifdef NO_POLL + COMPAT_CFLAGS += -DNO_POLL + COMPAT_OBJS += compat/poll.o +endif ifdef NO_PREAD COMPAT_CFLAGS += -DNO_PREAD COMPAT_OBJS += compat/pread.o diff --git a/compat/poll.c b/compat/poll.c new file mode 100644 index 0000000..0b3c2ae --- /dev/null +++ b/compat/poll.c @@ -0,0 +1,56 @@ +#include "../git-compat-util.h" + +static int msleep(int timeout) +{ + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 1000 * timeout; + return select(0, NULL, NULL, NULL, &tv); +} + +static int validate_fd(const struct git_pollfd *ufd) +{ + const int fd = ufd->fd; + if (ufd->events != POLLIN) { + errno = EINVAL; + return error("poll: unsupported events"); + } + if (fd >= FD_SETSIZE) { + errno = EINVAL; + return error("poll: fd must be below %d", FD_SETSIZE); + } + return fd; +} + +int git_poll(struct git_pollfd *ufds, int nfds, int timeout) +{ + int i, maxfd, result; + fd_set fds; + + if (timeout >= 0) { + if (nfds != 0) { + errno = EINVAL; + return error("poll timeout not supported"); + } + return msleep(timeout); + } + + FD_ZERO(&fds); + maxfd = -1; + for (i = 0; i < nfds; i++) { + const int fd = validate_fd(&ufds[i]); + if (fd < 0) + return fd; + maxfd = (fd > maxfd) ? fd : maxfd; + FD_SET(fd, &fds); + } + + result = select(maxfd + 1, &fds, NULL, NULL, NULL); + if (result < 0) + return result; + for (i = 0; i < nfds; i++) { + if (FD_ISSET(ufds[i].fd, &fds)) + ufds[i].revents |= POLLIN; + } + return result; +} diff --git a/compat/poll.h b/compat/poll.h new file mode 100644 index 0000000..65775ab --- /dev/null +++ b/compat/poll.h @@ -0,0 +1,13 @@ +#ifndef POLLIN +#define POLLIN 1 +#define POLLHUP 2 +#endif + +#define pollfd git_pollfd +#define poll git_poll +struct git_pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; +extern int git_poll(struct git_pollfd *fds, int nfds, int timeout); diff --git a/git-compat-util.h b/git-compat-util.h index 824c175..2494378 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -94,13 +94,17 @@ #include <utime.h> #ifndef __MINGW32__ #include <sys/wait.h> -#include <sys/poll.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <termios.h> #ifndef NO_SYS_SELECT_H #include <sys/select.h> #endif +#ifdef NO_POLL +#include "compat/poll.h" +#else +#include <sys/poll.h> +#endif #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html