From b23bc8c33cfd5ca607bcc07deaee616f9dceff35 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Mon, 31 Jul 2006 14:27:56 +0000 Subject: [PATCH] * fhandler_socket.cc (fhandler_socket::recv_internal): Fix a problem with poll(2) after shutdown(SHUT_RD) has been called on the local side. * poll.cc (poll): Use POSIX type nfds_t for second parameter. Drop special socket handling for POLLIN. Add comment to explain why. * include/sys/poll.h: Declare nfds_t. Use as type for second parameter in poll(2) declaration. --- winsup/cygwin/ChangeLog | 9 +++++++ winsup/cygwin/fhandler_socket.cc | 3 ++- winsup/cygwin/include/sys/poll.h | 6 +++-- winsup/cygwin/poll.cc | 44 ++++++++------------------------ 4 files changed, 25 insertions(+), 37 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 5e3f33762..e55394f79 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,12 @@ +2006-07-31 Corinna Vinschen + + * fhandler_socket.cc (fhandler_socket::recv_internal): Fix a problem + with poll(2) after shutdown(SHUT_RD) has been called on the local side. + * poll.cc (poll): Use POSIX type nfds_t for second parameter. Drop + special socket handling for POLLIN. Add comment to explain why. + * include/sys/poll.h: Declare nfds_t. Use as type for second parameter + in poll(2) declaration. + 2006-07-31 Corinna Vinschen * fhandler_socket.cc (fhandler_socket::evaluate_events): Circumvent diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 6a1cdd1e0..0fecdaaac 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -1160,7 +1160,8 @@ fhandler_socket::recv_internal (WSABUF *wsabuf, DWORD wsacnt, DWORD flags, /* Note: Don't call WSARecvFrom(MSG_PEEK) without actually having data waiting in the buffers, otherwise the event handling gets messed up for some reason. */ - while (!(res = wait_for_events (evt_mask | FD_CLOSE))) + while (!(res = wait_for_events (evt_mask | FD_CLOSE)) + || saw_shutdown_read ()) { res = WSARecvFrom (get_socket (), wsabuf, wsacnt, &ret, &flags, from, fromlen, NULL, NULL); diff --git a/winsup/cygwin/include/sys/poll.h b/winsup/cygwin/include/sys/poll.h index a5bd4bded..7fd1c6eb0 100644 --- a/winsup/cygwin/include/sys/poll.h +++ b/winsup/cygwin/include/sys/poll.h @@ -1,6 +1,6 @@ /* sys/poll.h - Copyright 2000, 2001 Red Hat, Inc. + Copyright 2000, 2001, 2006 Red Hat, Inc. This file is part of Cygwin. @@ -36,7 +36,9 @@ struct pollfd { short revents; }; -extern int poll __P ((struct pollfd *fds, unsigned int nfds, int timeout)); +typedef unsigned int nfds_t; + +extern int poll __P ((struct pollfd *fds, nfds_t nfds, int timeout)); __END_DECLS diff --git a/winsup/cygwin/poll.cc b/winsup/cygwin/poll.cc index a7db49ef8..3be689c90 100644 --- a/winsup/cygwin/poll.cc +++ b/winsup/cygwin/poll.cc @@ -27,7 +27,7 @@ #include "sigproc.h" extern "C" int -poll (struct pollfd *fds, unsigned int nfds, int timeout) +poll (struct pollfd *fds, nfds_t nfds, int timeout) { int max_fd = 0; fd_set *read_fds, *write_fds, *except_fds; @@ -90,39 +90,15 @@ poll (struct pollfd *fds, unsigned int nfds, int timeout) fhandler_socket *sock; if (FD_ISSET(fds[i].fd, read_fds)) - { - char peek[1]; - sock = cygheap->fdtab[fds[i].fd]->is_socket (); - if (!sock) - fds[i].revents |= POLLIN; - else if (sock->listener ()) - { - fds[i].revents |= POLLIN; - } - else - { - /* The following action can change errno. We have to - reset it to it's old value. */ - int old_errno = get_errno (); - switch (sock->recvfrom (peek, sizeof (peek), MSG_PEEK, - NULL, NULL)) - { - case -1: - fds[i].revents |= POLLERR; - break; - case 0: /* Closed on the read side... */ - /* ...or shutdown(SHUT_WR) on the write side. - We set revents to POLLHUP until 1.5.18, but - this is semantically borderline. */ - fds[i].revents |= POLLIN; - break; - default: - fds[i].revents |= POLLIN; - break; - } - set_errno (old_errno); - } - } + /* This should be sufficient for sockets, too. Using + MSG_PEEK, as before, can be considered dangerous at + best. Quote from W. Richard Stevens: "The presence + of an error can be considered either normal data or + an error (POLLERR). In either case, a subsequent read + will return -1 with errno set to the appropriate value." + So it looks like there's actually no good reason to + return POLLERR. */ + fds[i].revents |= POLLIN; /* Handle failed connect. */ if (FD_ISSET(fds[i].fd, write_fds) && (sock = cygheap->fdtab[fds[i].fd]->is_socket ())