diff options
author | Corinna Vinschen <vinschen@redhat.com> | 2007-12-13 17:19:46 +0000 |
---|---|---|
committer | Corinna Vinschen <vinschen@redhat.com> | 2007-12-13 17:19:46 +0000 |
commit | 999141f8b9b44ae5a3e384d8df8137648dcf9dba (patch) | |
tree | a3a05c3a2d4d1b32379bb05982f25a1a1c47d06c | |
parent | 7e2e8391646a2af815b950b1f18a03d7ecccfe6e (diff) | |
download | gdb-999141f8b9b44ae5a3e384d8df8137648dcf9dba.tar.gz |
* poll.cc (poll): Return count of fds with events instead of total
event count.
* poll.cc (poll): Use POSIX type nfds_t for second parameter.
* include/sys/poll.h: Declare nfds_t. Use as type for second parameter
in poll(2) declaration.
-rw-r--r-- | winsup/cygwin/ChangeLog | 12 | ||||
-rw-r--r-- | winsup/cygwin/include/sys/poll.h | 45 | ||||
-rw-r--r-- | winsup/cygwin/poll.cc | 159 |
3 files changed, 216 insertions, 0 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 81ea10f82fb..06136ffefa9 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,9 @@ +2007-12-13 Craig MacGregor <cmacgreg@gmail.com> + Corinna Vinschen <corinna@vinschen.de> + + * poll.cc (poll): Return count of fds with events instead of total + event count. + 2007-12-11 Corinna Vinschen <corinna@vinschen.de> * fhandler_disk_file.cc (fhandler_base::fstat_helper): Fix R/O bit @@ -632,6 +638,12 @@ * fhandler_disk_file.cc (fhandler_disk_file::lock): Handle ERROR_NOT_LOCKED returned from UnlockFileEx. +2006-07-31 Corinna Vinschen <corinna@vinschen.de> + + * poll.cc (poll): Use POSIX type nfds_t for second parameter. + * include/sys/poll.h: Declare nfds_t. Use as type for second parameter + in poll(2) declaration. + 2006-07-23 Christopher Faylor <cgf@timesys.com> * include/cygwin/version.h: Bump DLL minor version number to 22. diff --git a/winsup/cygwin/include/sys/poll.h b/winsup/cygwin/include/sys/poll.h new file mode 100644 index 00000000000..7fd1c6eb053 --- /dev/null +++ b/winsup/cygwin/include/sys/poll.h @@ -0,0 +1,45 @@ +/* sys/poll.h + + Copyright 2000, 2001, 2006 Red Hat, Inc. + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +#ifndef _SYS_POLL_H +#define _SYS_POLL_H + +#include <sys/cdefs.h> + +__BEGIN_DECLS + +#define POLLIN 1 /* Set if data to read. */ +#define POLLPRI 2 /* Set if urgent data to read. */ +#define POLLOUT 4 /* Set if writing data wouldn't block. */ +#define POLLERR 8 /* An error occured. */ +#define POLLHUP 16 /* Shutdown or close happened. */ +#define POLLNVAL 32 /* Invalid file descriptor. */ + +#define NPOLLFILE 64 /* Number of canonical fd's in one call to poll(). */ + +/* The following values are defined by XPG4. */ +#define POLLRDNORM POLLIN +#define POLLRDBAND POLLPRI +#define POLLWRNORM POLLOUT +#define POLLWRBAND POLLOUT + +struct pollfd { + int fd; + short events; + short revents; +}; + +typedef unsigned int nfds_t; + +extern int poll __P ((struct pollfd *fds, nfds_t nfds, int timeout)); + +__END_DECLS + +#endif /* _SYS_POLL_H */ diff --git a/winsup/cygwin/poll.cc b/winsup/cygwin/poll.cc new file mode 100644 index 00000000000..a9b4a233a68 --- /dev/null +++ b/winsup/cygwin/poll.cc @@ -0,0 +1,159 @@ +/* poll.cc. Implements poll(2) via usage of select(2) call. + + Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +#define __INSIDE_CYGWIN_NET__ + +#define FD_SETSIZE 16384 // lots of fds +#include "winsup.h" +#include <sys/time.h> +#include <sys/poll.h> +#include <sys/socket.h> +#include <stdlib.h> +#define USE_SYS_TYPES_FD_SET +#include <winsock2.h> +#include "cygerrno.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" +#include "sigproc.h" + +extern "C" int +poll (struct pollfd *fds, nfds_t nfds, int timeout) +{ + int max_fd = 0; + fd_set *read_fds, *write_fds, *except_fds; + struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 }; + + for (unsigned int i = 0; i < nfds; ++i) + if (fds[i].fd > max_fd) + max_fd = fds[i].fd; + + size_t fds_size = howmany (max_fd + 1, NFDBITS) * sizeof (fd_mask); + + read_fds = (fd_set *) alloca (fds_size); + write_fds = (fd_set *) alloca (fds_size); + except_fds = (fd_set *) alloca (fds_size); + + if (!read_fds || !write_fds || !except_fds) + { + set_errno (EINVAL); /* According to SUSv3. */ + return -1; + } + + memset (read_fds, 0, fds_size); + memset (write_fds, 0, fds_size); + memset (except_fds, 0, fds_size); + + int invalid_fds = 0; + for (unsigned int i = 0; i < nfds; ++i) + { + fds[i].revents = 0; + if (!cygheap->fdtab.not_open (fds[i].fd)) + { + if (fds[i].events & POLLIN) + FD_SET(fds[i].fd, read_fds); + if (fds[i].events & POLLOUT) + FD_SET(fds[i].fd, write_fds); + /* On sockets, except_fds is needed to catch failed connects. */ + if ((fds[i].events & POLLPRI) + || cygheap->fdtab[fds[i].fd]->is_socket ()) + FD_SET(fds[i].fd, except_fds); + } + else if (fds[i].fd >= 0) + { + ++invalid_fds; + fds[i].revents = POLLNVAL; + } + } + + if (invalid_fds) + return invalid_fds; + + int ret = cygwin_select (max_fd + 1, read_fds, write_fds, except_fds, + timeout < 0 ? NULL : &tv); + if (ret <= 0) + return ret; + + /* Set revents fields and count fds with non-zero revents fields for + return value. */ + ret = 0; + for (unsigned int i = 0; i < nfds; ++i) + { + if (fds[i].fd >= 0) + { + if (cygheap->fdtab.not_open (fds[i].fd)) + fds[i].revents = POLLHUP; + else + { + 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 + { + /* 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: /* Something weird happened */ + /* When select returns that data is available, + that could mean that the socket is in + listen mode and a client tries to connect. + Unfortunately, recvfrom() doesn't make much + sense then. It returns WSAENOTCONN in that + case. Since that's not actually an error, + we must not set POLLERR but POLLIN. */ + if (WSAGetLastError () != WSAENOTCONN) + fds[i].revents |= POLLERR; + else + fds[i].revents |= POLLIN; + 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); + } + } + /* Handle failed connect. */ + if (FD_ISSET(fds[i].fd, write_fds) + && FD_ISSET(fds[i].fd, except_fds) + && (sock = cygheap->fdtab[fds[i].fd]->is_socket ()) + && sock->connect_state () == connect_failed) + fds[i].revents |= (POLLIN | POLLERR); + else + { + if (FD_ISSET(fds[i].fd, write_fds)) + fds[i].revents |= POLLOUT; + if (FD_ISSET(fds[i].fd, except_fds)) + fds[i].revents |= POLLPRI; + } + } + if (fds[i].revents) + ++ret; + } + } + + return ret; +} |