]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/poll.cc
Throughout, update copyrights to reflect dates which correspond to main-branch
[newlib-cygwin.git] / winsup / cygwin / poll.cc
CommitLineData
afb7e719
CV
1/* poll.cc. Implements poll(2) via usage of select(2) call.
2
bc837d22
CF
3 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
4 2012 Red Hat, Inc.
afb7e719
CV
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
03b65245
CV
12#define __INSIDE_CYGWIN_NET__
13
42a737d0 14#define FD_SETSIZE 16384 // lots of fds
b2007749 15#include "winsup.h"
4c8d72de 16#include <sys/poll.h>
e2b3dc25 17#include <stdlib.h>
03b65245 18#define USE_SYS_TYPES_FD_SET
169c465a 19#include "cygerrno.h"
47063f00 20#include "path.h"
7ac61736 21#include "fhandler.h"
e2ebe117 22#include "dtable.h"
df63bd49 23#include "cygheap.h"
20a0b8c8
CV
24#include "pinfo.h"
25#include "sigproc.h"
afb7e719 26
c367dfd0 27extern "C" int
b23bc8c3 28poll (struct pollfd *fds, nfds_t nfds, int timeout)
afb7e719
CV
29{
30 int max_fd = 0;
58ef30a4 31 int invalid_fds = 0;
6ea9c716 32 fd_set *read_fds, *write_fds, *except_fds;
afb7e719
CV
33 struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
34
427b6d03
CV
35 for (unsigned int i = 0; i < nfds; ++i)
36 if (fds[i].fd > max_fd)
37 max_fd = fds[i].fd;
38
c90e1cf1 39 size_t fds_size = howmany (max_fd + 1, NFDBITS) * sizeof (fd_mask);
427b6d03 40
427b6d03
CV
41 read_fds = (fd_set *) alloca (fds_size);
42 write_fds = (fd_set *) alloca (fds_size);
43 except_fds = (fd_set *) alloca (fds_size);
44
6ea9c716 45 if (!read_fds || !write_fds || !except_fds)
427b6d03 46 {
04843bf4 47 set_errno (EINVAL); /* According to SUSv3. */
427b6d03
CV
48 return -1;
49 }
50
427b6d03
CV
51 memset (read_fds, 0, fds_size);
52 memset (write_fds, 0, fds_size);
53 memset (except_fds, 0, fds_size);
afb7e719 54
2402700d
CF
55 for (unsigned int i = 0; i < nfds; ++i)
56 {
57 fds[i].revents = 0;
c90e1cf1 58 if (!cygheap->fdtab.not_open (fds[i].fd))
2402700d
CF
59 {
60 if (fds[i].events & POLLIN)
61 FD_SET(fds[i].fd, read_fds);
62 if (fds[i].events & POLLOUT)
63 FD_SET(fds[i].fd, write_fds);
fd5879c1 64 if (fds[i].events & POLLPRI)
2402700d
CF
65 FD_SET(fds[i].fd, except_fds);
66 }
67 else if (fds[i].fd >= 0)
68 {
69 ++invalid_fds;
70 fds[i].revents = POLLNVAL;
71 }
72 }
afb7e719 73
58ef30a4
CV
74 /* Invalid fds? */
75 if (invalid_fds > 0)
76 {
77 /* Only invalid fds? Return. */
78 if ((nfds_t) invalid_fds == nfds)
79 return invalid_fds;
80 /* POSIX doesn't explicitely define this behaviour, but on Linux,
81 the timeout is set to 0 if an error occurs, and POLLNVAL is one
82 of these errors. So, for Linux-compatibility's sake... */
83 tv.tv_sec = tv.tv_usec = 0;
84 }
99dbafac 85
d1f36688
CV
86 int ret = cygwin_select (max_fd + 1, read_fds, write_fds, except_fds,
87 timeout < 0 ? NULL : &tv);
58ef30a4
CV
88 /* timeout, signal, whatever? Return. If invalid fds exist, return with
89 their number. */
d1f36688 90 if (ret <= 0)
58ef30a4 91 return invalid_fds ?: ret;
d1f36688
CV
92
93 /* Set revents fields and count fds with non-zero revents fields for
94 return value. */
95 ret = 0;
96 for (unsigned int i = 0; i < nfds; ++i)
97 {
58ef30a4 98 if (fds[i].fd >= 0 && fds[i].revents != POLLNVAL)
d1f36688 99 {
0077cd10
CV
100 fhandler_socket *sock;
101
102 /* Check if the descriptor has been closed, or if shutdown for the
103 read side has been called on a socket. */
104 if (cygheap->fdtab.not_open (fds[i].fd)
105 || ((sock = cygheap->fdtab[fds[i].fd]->is_socket ())
106 && sock->saw_shutdown_read ()))
d1f36688
CV
107 fds[i].revents = POLLHUP;
108 else
109 {
d1f36688
CV
110 if (FD_ISSET(fds[i].fd, read_fds))
111 /* This should be sufficient for sockets, too. Using
112 MSG_PEEK, as before, can be considered dangerous at
113 best. Quote from W. Richard Stevens: "The presence
114 of an error can be considered either normal data or
115 an error (POLLERR). In either case, a subsequent read
116 will return -1 with errno set to the appropriate value."
117 So it looks like there's actually no good reason to
118 return POLLERR. */
119 fds[i].revents |= POLLIN;
120 /* Handle failed connect. */
121 if (FD_ISSET(fds[i].fd, write_fds)
122 && (sock = cygheap->fdtab[fds[i].fd]->is_socket ())
123 && sock->connect_state () == connect_failed)
124 fds[i].revents |= (POLLIN | POLLERR);
125 else
126 {
127 if (FD_ISSET(fds[i].fd, write_fds))
128 fds[i].revents |= POLLOUT;
129 if (FD_ISSET(fds[i].fd, except_fds))
130 fds[i].revents |= POLLPRI;
131 }
132 }
133 if (fds[i].revents)
134 ++ret;
135 }
136 }
58ef30a4
CV
137 /* Number of fds with event includes the invalid fds. */
138 return ret + invalid_fds;
2402700d 139}
20a0b8c8
CV
140
141extern "C" int
142ppoll (struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts,
143 const sigset_t *sigmask)
144{
145 int timeout;
146 sigset_t oldset = _my_tls.sigmask;
147
148 myfault efault;
149 if (efault.faulted (EFAULT))
150 return -1;
151 timeout = (timeout_ts == NULL)
152 ? -1
153 : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
154 if (sigmask)
962f9a2c 155 set_signal_mask (_my_tls.sigmask, *sigmask);
20a0b8c8
CV
156 int ret = poll (fds, nfds, timeout);
157 if (sigmask)
962f9a2c 158 set_signal_mask (_my_tls.sigmask, oldset);
20a0b8c8
CV
159 return ret;
160}
This page took 0.441107 seconds and 5 git commands to generate.