diff options
Diffstat (limited to 'src/posix-io.c')
-rw-r--r-- | src/posix-io.c | 127 |
1 files changed, 124 insertions, 3 deletions
diff --git a/src/posix-io.c b/src/posix-io.c index e712ef2..5c6cf1d 100644 --- a/src/posix-io.c +++ b/src/posix-io.c @@ -570,7 +570,7 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, if (fd_list[i].fd > fd) fd = fd_list[i].fd; fd++; -#if defined(__sun) || defined(__FreeBSD__) +#if defined(__sun) || defined(__FreeBSD__) || defined(__GLIBC__) closefrom (fd); max_fds = fd; #else /*!__sun */ @@ -691,8 +691,119 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, /* 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 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) } 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) |