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 *****************************************************************************/
30 # include <sys/time.h>
31 # include <sys/select.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 };
43 for (unsigned i
= 0; i
< nfds
; i
++)
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
58 if ((unsigned)fd
>= FD_SETSIZE
)
63 if (fds
[i
].events
& POLLRDNORM
)
65 if (fds
[i
].events
& POLLWRNORM
)
67 if (fds
[i
].events
& POLLPRI
)
73 div_t d
= div (timeout
, 1000);
75 tv
.tv_usec
= d
.rem
* 1000;
78 val
= select (val
+ 1, rdset
, wrset
, exset
,
79 (timeout
>= 0) ? &tv
: NULL
);
87 for (unsigned i
= 0; i
< nfds
; i
++)
88 if (fcntl (fds
[i
].fd
, F_GETFD
) == -1)
90 fds
[i
].revents
= POLLNVAL
;
96 return val
? val
: -1;
99 for (unsigned i
= 0; i
< nfds
; i
++)
102 fds
[i
].revents
= (FD_ISSET (fd
, rdset
) ? POLLRDNORM
: 0)
103 | (FD_ISSET (fd
, wrset
) ? POLLWRNORM
: 0)
104 | (FD_ISSET (fd
, exset
) ? POLLPRI
: 0);
109 # include <windows.h>
110 # include <winsock2.h>
112 static int poll_compat(struct pollfd
*fds
, unsigned nfds
, int timeout
)
114 DWORD to
= (timeout
>= 0) ? (DWORD
)timeout
: INFINITE
;
117 { /* WSAWaitForMultipleEvents() does not allow zero events */
118 if (SleepEx(to
, TRUE
))
126 WSAEVENT
*evts
= malloc(nfds
* sizeof (WSAEVENT
));
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
;
142 if (fds
[i
].events
& POLLRDNORM
)
144 mask
|= FD_READ
| FD_ACCEPT
;
147 if (fds
[i
].events
& POLLWRNORM
)
149 mask
|= FD_WRITE
| FD_CONNECT
;
152 if (fds
[i
].events
& POLLPRI
)
157 evts
[i
] = WSACreateEvent();
158 if (evts
[i
] == WSA_INVALID_EVENT
)
161 WSACloseEvent(evts
[--i
]);
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
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
);
197 for (unsigned i
= 0; i
< nfds
; i
++)
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;
247 if (count
== 0 && ret
== WSA_WAIT_IO_COMPLETION
)
255 int poll(struct pollfd
*fds
, unsigned nfds
, int timeout
)
259 /* HACK: In some cases, we lose some events because events are
260 * destroyed and recreated only when we need to poll. In order to work
261 * arround this issue, we try to call the poll compat function every
262 * 100ms (in case of infinite timeout). */
264 while ((ret
= poll_compat(fds
, nfds
, 100)) == 0);
268 return poll_compat(fds
, nfds
, timeout
);