diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -538,7 +538,7 @@ # Checks for header files. AC_CHECK_HEADERS_ONCE([locale.h sys/select.h sys/uio.h argp.h stdint.h - unistd.h sys/time.h sys/types.h sys/stat.h]) + unistd.h poll.h sys/time.h sys/types.h sys/stat.h]) # Type checks. diff --git a/src/ath.h b/src/ath.h --- a/src/ath.h +++ b/src/ath.h @@ -32,12 +32,15 @@ # include #else /*!HAVE_W32_SYSTEM*/ - -# ifdef HAVE_SYS_SELECT_H -# include +# ifdef HAVE_POLL_H +# include # else -# ifdef HAVE_SYS_TIME_H -# include +# ifdef HAVE_SYS_SELECT_H +# include +# else +# ifdef HAVE_SYS_TIME_H +# include +# endif # endif # endif # ifdef HAVE_SYS_TYPES_H diff --git a/src/ath.c b/src/ath.c --- a/src/ath.c +++ b/src/ath.c @@ -26,11 +26,15 @@ #ifdef HAVE_UNISTD_H # include #endif -#ifdef HAVE_SYS_SELECT_H -# include +#ifdef HAVE_POLL_H +# include #else -# ifdef HAVE_SYS_TIME_H -# include +# ifdef HAVE_SYS_SELECT_H +# include +# else +# ifdef HAVE_SYS_TIME_H +# include +# endif # endif #endif #ifdef HAVE_SYS_TYPES_H @@ -89,6 +93,7 @@ } +#if !defined(HAVE_POLL_H) gpgme_ssize_t ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset, struct timeval *timeout) @@ -99,7 +104,7 @@ return select (nfd, rset, wset, eset, timeout); #endif } - +#endif gpgme_ssize_t ath_waitpid (pid_t pid, int *status, int options) diff --git a/src/posix-io.c b/src/posix-io.c --- a/src/posix-io.c +++ b/src/posix-io.c @@ -691,8 +691,119 @@ /* Select on the list of fds. Returns: -1 = error, 0 = timeout or nothing to select, > 0 = number of signaled fds. */ -int -_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) +#ifdef HAVE_POLL_H +static int +_gpgme_io_select_poll (struct io_select_fd_s *fds, size_t nfds, int nonblock) +{ + struct pollfd *poll_fds = NULL; + nfds_t poll_nfds; + /* Use a 1s timeout. */ + int timeout = 1000; + unsigned int i; + int any; + int count; + void *dbg_help = NULL; + TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_select", NULL, + "nfds=%zu, nonblock=%u", nfds, nonblock); + + + if (nonblock) + timeout = 0; + + poll_fds = malloc (sizeof (*poll_fds)*nfds); + if (!poll_fds) + return -1; + + poll_nfds = 0; + + TRACE_SEQ (dbg_help, "poll on [ "); + + any = 0; + for (i = 0; i < nfds; i++) + { + if (fds[i].fd == -1) + continue; + if (fds[i].for_read || fds[i].for_write) + { + poll_fds[poll_nfds].fd = fds[i].fd; + poll_fds[poll_nfds].events = 0; + poll_fds[poll_nfds].revents = 0; + if (fds[i].for_read) + { + poll_fds[poll_nfds].events |= POLLIN; + TRACE_ADD1 (dbg_help, "r=%d ", fds[i].fd); + } + if (fds[i].for_write) + { + poll_fds[poll_nfds].events |= POLLOUT; + TRACE_ADD1 (dbg_help, "w=%d ", fds[i].fd); + } + poll_nfds++; + any = 1; + } + fds[i].signaled = 0; + } + TRACE_END (dbg_help, "]"); + if (!any) + { + free (poll_fds); + return TRACE_SYSRES (0); + } + + do + count = poll (poll_fds, poll_nfds, timeout); + while (count < 0 && (errno == EINTR || errno == EAGAIN)); + if (count < 0) + { + int save_errno = errno; + free (poll_fds); + errno = save_errno; + return TRACE_SYSRES (-1); + } + + TRACE_SEQ (dbg_help, "poll OK [ "); + if (TRACE_ENABLED (dbg_help)) + { + poll_nfds = 0; + for (i = 0; i < nfds; i++) + { + if (fds[i].fd == -1) + continue; + if ((poll_fds[poll_nfds].revents & (POLLIN|POLLHUP))) + TRACE_ADD1 (dbg_help, "r=%d ", i); + if ((poll_fds[poll_nfds].revents & POLLOUT)) + TRACE_ADD1 (dbg_help, "w=%d ", i); + poll_nfds++; + } + TRACE_END (dbg_help, "]"); + } + + poll_nfds = 0; + for (i = 0; i < nfds; i++) + { + if (fds[i].fd == -1) + continue; + if (fds[i].for_read || fds[i].for_write) + { + short events_to_be_checked = 0; + + if (fds[i].for_read) + events_to_be_checked |= (POLLIN|POLLHUP); + if (fds[i].for_write) + events_to_be_checked |= POLLOUT; + if ((poll_fds[poll_nfds].revents & events_to_be_checked)) + fds[i].signaled = 1; + + poll_nfds++; + } + } + + free (poll_fds); + return TRACE_SYSRES (count); +} +#else +static int +_gpgme_io_select_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) { fd_set readfds; fd_set writefds; @@ -802,7 +913,17 @@ } return TRACE_SYSRES (count); } +#endif +int +_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) +{ +#ifdef HAVE_POLL_H + return _gpgme_io_select_poll (fds, nfds, nonblock); +#else + return _gpgme_io_select_select (fds, nfds, nonblock); +#endif +} int _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags) diff --git a/tests/gpg/t-cancel.c b/tests/gpg/t-cancel.c --- a/tests/gpg/t-cancel.c +++ b/tests/gpg/t-cancel.c @@ -38,8 +38,16 @@ #include #include #include -#ifdef HAVE_SYS_SELECT_H -# include +#ifdef HAVE_POLL_H +# include +#else +# ifdef HAVE_SYS_SELECT_H +# include +# else +# ifdef HAVE_SYS_TIME_H +# include +# endif +# endif #endif #include @@ -116,6 +124,60 @@ } +#ifdef HAVE_POLL_H +static int +do_select (void) +{ + struct pollfd poll_fds[FDLIST_MAX]; + nfds_t poll_nfds; + int i, n; + int any = 0; + + pthread_mutex_lock (&lock); + poll_nfds = 0; + for (i = 0; i < FDLIST_MAX; i++) + if (fdlist[i].fd != -1) + { + poll_fds[poll_nfds].fd = fdlist[i].fd; + poll_fds[poll_nfds].events = 0; + poll_fds[poll_nfds].revents = 0; + if (fdlist[i].dir) + poll_fds[poll_nfds].events |= POLLIN; + else + poll_fds[poll_nfds].events |= POLLOUT; + poll_nfds++; + } + pthread_mutex_unlock (&lock); + + do + { + n = poll (poll_fds, poll_nfds, 1000); + } + while (n < 0 && (errno == EINTR || errno == EAGAIN)); + + if (n < 0) + return n; /* Error or timeout. */ + + pthread_mutex_lock (&lock); + poll_nfds = 0; + for (i = 0; i < FDLIST_MAX && n; i++) + { + if (fdlist[i].fd != -1) + { + if ((poll_fds[poll_nfds++].revents + & (fdlist[i].dir ? (POLLIN|POLLHUP) : POLLOUT))) + { + assert (n); + n--; + any = 1; + (*fdlist[i].fnc) (fdlist[i].fnc_data, fdlist[i].fd); + } + } + } + pthread_mutex_unlock (&lock); + return any; +} +#else static int do_select (void) { @@ -162,6 +224,7 @@ pthread_mutex_unlock (&lock); return any; } +#endif static int my_wait (void) diff --git a/tests/gpg/t-eventloop.c b/tests/gpg/t-eventloop.c --- a/tests/gpg/t-eventloop.c +++ b/tests/gpg/t-eventloop.c @@ -31,7 +31,17 @@ #include #include #include -#include +#ifdef HAVE_POLL_H +# include +#else +# ifdef HAVE_SYS_SELECT_H +# include +# else +# ifdef HAVE_SYS_TIME_H +# include +# endif +# endif +#endif #include @@ -104,6 +114,56 @@ } +#ifdef HAVE_POLL_H +int +do_select (void) +{ + struct pollfd poll_fds[FDLIST_MAX]; + nfds_t poll_nfds; + int i, n; + int any = 0; + + poll_nfds = 0; + for (i = 0; i < FDLIST_MAX; i++) + if (fdlist[i].fd != -1) + { + poll_fds[poll_nfds].fd = fdlist[i].fd; + poll_fds[poll_nfds].events = 0; + poll_fds[poll_nfds].revents = 0; + if (fdlist[i].dir) + poll_fds[poll_nfds].events |= POLLIN; + else + poll_fds[poll_nfds].events |= POLLOUT; + poll_nfds++; + } + + do + { + n = poll (poll_fds, poll_nfds, 1000); + } + while (n < 0 && (errno == EINTR || errno == EAGAIN)); + + if (n < 0) + return n; /* Error or timeout. */ + + poll_nfds = 0; + for (i = 0; i < FDLIST_MAX && n; i++) + { + if (fdlist[i].fd != -1) + { + if ((poll_fds[poll_nfds++].revents + & (fdlist[i].dir ? (POLLIN|POLLHUP) : POLLOUT))) + { + assert (n); + n--; + any = 1; + (*fdlist[i].fnc) (fdlist[i].fnc_data, fdlist[i].fd); + } + } + } + return any; +} +#else int do_select (void) { @@ -146,6 +206,7 @@ } return any; } +#endif int my_wait (void) diff --git a/tests/gpg/t-support.h b/tests/gpg/t-support.h --- a/tests/gpg/t-support.h +++ b/tests/gpg/t-support.h @@ -150,6 +150,18 @@ init_gpgme (gpgme_protocol_t proto) { gpgme_error_t err; + static int initialized = 0; + + /* Artificially using many file descriptors. */ + if (!initialized) + { + int fd[1024]; + int i; + + for (i = 0; i < DIM (fd); i++) + fd[i] = dup (0); + initialized++; + } gpgme_check_version (NULL); setlocale (LC_ALL, ""); @@ -159,6 +171,7 @@ #endif err = gpgme_engine_check_version (proto); + fail_if_err (err); }