contribs: only force ass optimizations when WITH_OPTIMIZATION is set
[vlc.git] / compat / poll.c
blobfa94c932ccfa57eda8a37874de60712c1b305718
1 /*****************************************************************************
2 * poll.c: poll() emulation
3 *****************************************************************************
4 * Copyright © 2007-2012 Rémi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
29 #ifndef _WIN32
30 # include <sys/time.h>
31 # include <sys/select.h>
32 # include <fcntl.h>
34 int (poll) (struct pollfd *fds, unsigned nfds, int timeout)
36 fd_set rdset[1], wrset[1], exset[1];
37 struct timeval tv = { 0, 0 };
38 int val = -1;
40 FD_ZERO (rdset);
41 FD_ZERO (wrset);
42 FD_ZERO (exset);
43 for (unsigned i = 0; i < nfds; i++)
45 int fd = fds[i].fd;
46 if (val < fd)
47 val = fd;
49 /* With POSIX, FD_SET & FD_ISSET are not defined if fd is negative or
50 * bigger or equal than FD_SETSIZE. That is one of the reasons why VLC
51 * uses poll() rather than select(). Most POSIX systems implement
52 * fd_set has a bit field with no sanity checks. This is especially bad
53 * on systems (such as BSD) that have no process open files limit by
54 * default, such that it is quite feasible to get fd >= FD_SETSIZE.
55 * The next instructions will result in a buffer overflow if run on
56 * a POSIX system, and the later FD_ISSET would perform an undefined
57 * memory read. */
58 if ((unsigned)fd >= FD_SETSIZE)
60 errno = EINVAL;
61 return -1;
63 if (fds[i].events & POLLRDNORM)
64 FD_SET (fd, rdset);
65 if (fds[i].events & POLLWRNORM)
66 FD_SET (fd, wrset);
67 if (fds[i].events & POLLPRI)
68 FD_SET (fd, exset);
71 if (timeout >= 0)
73 div_t d = div (timeout, 1000);
74 tv.tv_sec = d.quot;
75 tv.tv_usec = d.rem * 1000;
78 val = select (val + 1, rdset, wrset, exset,
79 (timeout >= 0) ? &tv : NULL);
80 if (val == -1)
82 if (errno != EBADF)
83 return -1;
85 val = 0;
87 for (unsigned i = 0; i < nfds; i++)
88 if (fcntl (fds[i].fd, F_GETFD) == -1)
90 fds[i].revents = POLLNVAL;
91 val++;
93 else
94 fds[i].revents = 0;
96 return val ? val : -1;
99 for (unsigned i = 0; i < nfds; i++)
101 int fd = fds[i].fd;
102 fds[i].revents = (FD_ISSET (fd, rdset) ? POLLRDNORM : 0)
103 | (FD_ISSET (fd, wrset) ? POLLWRNORM : 0)
104 | (FD_ISSET (fd, exset) ? POLLPRI : 0);
106 return val;
108 #else
109 # include <windows.h>
110 # include <winsock2.h>
112 int poll(struct pollfd *fds, unsigned nfds, int timeout)
114 DWORD to = (timeout >= 0) ? (DWORD)timeout : INFINITE;
116 if (nfds == 0)
117 { /* WSAWaitForMultipleEvents() does not allow zero events */
118 if (SleepEx(to, TRUE))
120 errno = EINTR;
121 return -1;
123 return 0;
126 WSAEVENT *evts = malloc(nfds * sizeof (WSAEVENT));
127 if (evts == NULL)
128 return -1; /* ENOMEM */
130 DWORD ret = WSA_WAIT_FAILED;
131 for (unsigned i = 0; i < nfds; i++)
133 SOCKET fd = fds[i].fd;
134 long mask = FD_CLOSE;
135 fd_set rdset, wrset, exset;
137 FD_ZERO(&rdset);
138 FD_ZERO(&wrset);
139 FD_ZERO(&exset);
140 FD_SET(fd, &exset);
142 if (fds[i].events & POLLRDNORM)
144 mask |= FD_READ | FD_ACCEPT;
145 FD_SET(fd, &rdset);
147 if (fds[i].events & POLLWRNORM)
149 mask |= FD_WRITE | FD_CONNECT;
150 FD_SET(fd, &wrset);
152 if (fds[i].events & POLLPRI)
153 mask |= FD_OOB;
155 fds[i].revents = 0;
157 evts[i] = WSACreateEvent();
158 if (evts[i] == WSA_INVALID_EVENT)
160 while (i > 0)
161 WSACloseEvent(evts[--i]);
162 free(evts);
163 errno = ENOMEM;
164 return -1;
167 if (WSAEventSelect(fds[i].fd, evts[i], mask)
168 && WSAGetLastError() == WSAENOTSOCK)
169 fds[i].revents |= POLLNVAL;
171 struct timeval tv = { 0, 0 };
172 /* By its horrible design, WSAEnumNetworkEvents() only enumerates
173 * events that were not already signaled (i.e. it is edge-triggered).
174 * WSAPoll() would be better in this respect, but worse in others.
175 * So use WSAEnumNetworkEvents() after manually checking for pending
176 * events. */
177 if (select(0, &rdset, &wrset, &exset, &tv) > 0)
179 if (FD_ISSET(fd, &rdset))
180 fds[i].revents |= fds[i].events & POLLRDNORM;
181 if (FD_ISSET(fd, &wrset))
182 fds[i].revents |= fds[i].events & POLLWRNORM;
183 if (FD_ISSET(fd, &exset))
184 /* To add pain to injury, POLLERR and POLLPRI cannot be
185 * distinguished here. */
186 fds[i].revents |= POLLERR | (fds[i].events & POLLPRI);
189 if (fds[i].revents != 0 && ret == WSA_WAIT_FAILED)
190 ret = WSA_WAIT_EVENT_0 + i;
193 if (ret == WSA_WAIT_FAILED)
194 ret = WSAWaitForMultipleEvents(nfds, evts, FALSE, to, TRUE);
196 unsigned count = 0;
197 for (unsigned i = 0; i < nfds; i++)
199 WSANETWORKEVENTS ne;
201 if (WSAEnumNetworkEvents(fds[i].fd, evts[i], &ne))
202 memset(&ne, 0, sizeof (ne));
203 WSAEventSelect(fds[i].fd, evts[i], 0);
204 WSACloseEvent(evts[i]);
206 if (ne.lNetworkEvents & FD_CONNECT)
208 fds[i].revents |= POLLWRNORM;
209 if (ne.iErrorCode[FD_CONNECT_BIT] != 0)
210 fds[i].revents |= POLLERR;
212 if (ne.lNetworkEvents & FD_CLOSE)
214 fds[i].revents |= (fds[i].events & POLLRDNORM) | POLLHUP;
215 if (ne.iErrorCode[FD_CLOSE_BIT] != 0)
216 fds[i].revents |= POLLERR;
218 if (ne.lNetworkEvents & FD_ACCEPT)
220 fds[i].revents |= POLLRDNORM;
221 if (ne.iErrorCode[FD_ACCEPT_BIT] != 0)
222 fds[i].revents |= POLLERR;
224 if (ne.lNetworkEvents & FD_OOB)
226 fds[i].revents |= POLLPRI;
227 if (ne.iErrorCode[FD_OOB_BIT] != 0)
228 fds[i].revents |= POLLERR;
230 if (ne.lNetworkEvents & FD_READ)
232 fds[i].revents |= POLLRDNORM;
233 if (ne.iErrorCode[FD_READ_BIT] != 0)
234 fds[i].revents |= POLLERR;
236 if (ne.lNetworkEvents & FD_WRITE)
238 fds[i].revents |= POLLWRNORM;
239 if (ne.iErrorCode[FD_WRITE_BIT] != 0)
240 fds[i].revents |= POLLERR;
242 count += fds[i].revents != 0;
245 free(evts);
247 if (count == 0 && ret == WSA_WAIT_IO_COMPLETION)
249 errno = EINTR;
250 return -1;
252 return count;
254 #endif