]>
Commit | Line | Data |
---|---|---|
afb7e719 CV |
1 | /* poll.cc. Implements poll(2) via usage of select(2) call. |
2 | ||
d1f36688 | 3 | Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. |
afb7e719 CV |
4 | |
5 | This file is part of Cygwin. | |
6 | ||
7 | This software is a copyrighted work licensed under the terms of the | |
8 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
9 | details. */ | |
10 | ||
03b65245 CV |
11 | #define __INSIDE_CYGWIN_NET__ |
12 | ||
42a737d0 | 13 | #define FD_SETSIZE 16384 // lots of fds |
b2007749 | 14 | #include "winsup.h" |
4c8d72de | 15 | #include <sys/poll.h> |
7382e593 | 16 | #include <sys/socket.h> |
e2b3dc25 | 17 | #include <stdlib.h> |
03b65245 | 18 | #define USE_SYS_TYPES_FD_SET |
169c465a | 19 | #include "cygerrno.h" |
6b91b8d5 | 20 | #include "security.h" |
47063f00 | 21 | #include "path.h" |
7ac61736 | 22 | #include "fhandler.h" |
e2ebe117 | 23 | #include "dtable.h" |
df63bd49 | 24 | #include "cygheap.h" |
afb7e719 | 25 | |
c367dfd0 | 26 | extern "C" int |
b23bc8c3 | 27 | poll (struct pollfd *fds, nfds_t nfds, int timeout) |
afb7e719 CV |
28 | { |
29 | int max_fd = 0; | |
6ea9c716 | 30 | fd_set *read_fds, *write_fds, *except_fds; |
afb7e719 CV |
31 | struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 }; |
32 | ||
427b6d03 CV |
33 | for (unsigned int i = 0; i < nfds; ++i) |
34 | if (fds[i].fd > max_fd) | |
35 | max_fd = fds[i].fd; | |
36 | ||
c90e1cf1 | 37 | size_t fds_size = howmany (max_fd + 1, NFDBITS) * sizeof (fd_mask); |
427b6d03 | 38 | |
427b6d03 CV |
39 | read_fds = (fd_set *) alloca (fds_size); |
40 | write_fds = (fd_set *) alloca (fds_size); | |
41 | except_fds = (fd_set *) alloca (fds_size); | |
42 | ||
6ea9c716 | 43 | if (!read_fds || !write_fds || !except_fds) |
427b6d03 | 44 | { |
04843bf4 | 45 | set_errno (EINVAL); /* According to SUSv3. */ |
427b6d03 CV |
46 | return -1; |
47 | } | |
48 | ||
427b6d03 CV |
49 | memset (read_fds, 0, fds_size); |
50 | memset (write_fds, 0, fds_size); | |
51 | memset (except_fds, 0, fds_size); | |
afb7e719 | 52 | |
2402700d CF |
53 | int invalid_fds = 0; |
54 | for (unsigned int i = 0; i < nfds; ++i) | |
55 | { | |
56 | fds[i].revents = 0; | |
c90e1cf1 | 57 | if (!cygheap->fdtab.not_open (fds[i].fd)) |
2402700d CF |
58 | { |
59 | if (fds[i].events & POLLIN) | |
60 | FD_SET(fds[i].fd, read_fds); | |
61 | if (fds[i].events & POLLOUT) | |
62 | FD_SET(fds[i].fd, write_fds); | |
fd5879c1 | 63 | if (fds[i].events & POLLPRI) |
2402700d CF |
64 | FD_SET(fds[i].fd, except_fds); |
65 | } | |
66 | else if (fds[i].fd >= 0) | |
67 | { | |
68 | ++invalid_fds; | |
69 | fds[i].revents = POLLNVAL; | |
70 | } | |
71 | } | |
afb7e719 | 72 | |
2402700d CF |
73 | if (invalid_fds) |
74 | return invalid_fds; | |
99dbafac | 75 | |
d1f36688 CV |
76 | int ret = cygwin_select (max_fd + 1, read_fds, write_fds, except_fds, |
77 | timeout < 0 ? NULL : &tv); | |
78 | if (ret <= 0) | |
79 | return ret; | |
80 | ||
81 | /* Set revents fields and count fds with non-zero revents fields for | |
82 | return value. */ | |
83 | ret = 0; | |
84 | for (unsigned int i = 0; i < nfds; ++i) | |
85 | { | |
86 | if (fds[i].fd >= 0) | |
87 | { | |
88 | if (cygheap->fdtab.not_open (fds[i].fd)) | |
89 | fds[i].revents = POLLHUP; | |
90 | else | |
91 | { | |
92 | fhandler_socket *sock; | |
93 | ||
94 | if (FD_ISSET(fds[i].fd, read_fds)) | |
95 | /* This should be sufficient for sockets, too. Using | |
96 | MSG_PEEK, as before, can be considered dangerous at | |
97 | best. Quote from W. Richard Stevens: "The presence | |
98 | of an error can be considered either normal data or | |
99 | an error (POLLERR). In either case, a subsequent read | |
100 | will return -1 with errno set to the appropriate value." | |
101 | So it looks like there's actually no good reason to | |
102 | return POLLERR. */ | |
103 | fds[i].revents |= POLLIN; | |
104 | /* Handle failed connect. */ | |
105 | if (FD_ISSET(fds[i].fd, write_fds) | |
106 | && (sock = cygheap->fdtab[fds[i].fd]->is_socket ()) | |
107 | && sock->connect_state () == connect_failed) | |
108 | fds[i].revents |= (POLLIN | POLLERR); | |
109 | else | |
110 | { | |
111 | if (FD_ISSET(fds[i].fd, write_fds)) | |
112 | fds[i].revents |= POLLOUT; | |
113 | if (FD_ISSET(fds[i].fd, except_fds)) | |
114 | fds[i].revents |= POLLPRI; | |
115 | } | |
116 | } | |
117 | if (fds[i].revents) | |
118 | ++ret; | |
119 | } | |
120 | } | |
afb7e719 | 121 | |
2402700d CF |
122 | return ret; |
123 | } |