]>
Commit | Line | Data |
---|---|---|
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 | 27 | extern "C" int |
b23bc8c3 | 28 | poll (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 | |
141 | extern "C" int | |
142 | ppoll (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 | } |