]> git.sesse.net Git - vlc/blob - compat/poll.c
Compute the lib directory dynamically
[vlc] / compat / poll.c
1 /*****************************************************************************
2  * poll.c: poll() emulation
3  *****************************************************************************
4  * Copyright © 2007-2012 Rémi Denis-Courmont
5  *
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.
10  *
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.
15  *
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  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #ifdef WIN32
30 # ifdef FD_SETSIZE
31 /* Too late for #undef FD_SETSIZE to work: fd_set is already defined. */
32 #  error Header inclusion order compromised!
33 # endif
34 # define FD_SETSIZE 0
35 # include <winsock2.h>
36 #else
37 # include <sys/select.h>
38 #endif
39
40 int (poll) (struct pollfd *fds, unsigned nfds, int timeout)
41 {
42 #ifdef WIN32
43     size_t setsize = sizeof (fd_set) + nfds * sizeof (SOCKET);
44     fd_set *rdset = malloc (setsize);
45     fd_set *wrset = malloc (setsize);
46     fd_set *exset = malloc (setsize);
47
48     if (rdset == NULL || wrset == NULL || exset == NULL)
49     {
50         free (rdset);
51         free (wrset);
52         free (exset);
53         errno = ENOMEM;
54         return -1;
55     }
56 /* Winsock FD_SET uses FD_SETSIZE in its expansion */
57 # undef FD_SETSIZE
58 # define FD_SETSIZE (nfds)
59 #else
60     fd_set rdset[1], wrset[1], exset[1];
61 #endif
62     struct timeval tv = { 0, 0 };
63     int val = -1;
64
65     FD_ZERO (rdset);
66     FD_ZERO (wrset);
67     FD_ZERO (exset);
68     for (unsigned i = 0; i < nfds; i++)
69     {
70         int fd = fds[i].fd;
71         if (val < fd)
72             val = fd;
73
74         /* With POSIX, FD_SET & FD_ISSET are not defined if fd is negative or
75          * bigger or equal than FD_SETSIZE. That is one of the reasons why VLC
76          * uses poll() rather than select(). Most POSIX systems implement
77          * fd_set has a bit field with no sanity checks. This is especially bad
78          * on systems (such as BSD) that have no process open files limit by
79          * default, such that it is quite feasible to get fd >= FD_SETSIZE.
80          * The next instructions will result in a buffer overflow if run on
81          * a POSIX system, and the later FD_ISSET would perform an undefined
82          * memory read.
83          *
84          * With Winsock, fd_set is a table of integers. This is awfully slow.
85          * However, FD_SET and FD_ISSET silently and safely discard excess
86          * entries. Here, overflow cannot happen anyway: fd_set of adequate
87          * size are allocated.
88          * Note that Vista has a much nicer WSAPoll(), but Mingw does not
89          * support it yet.
90          */
91 #ifndef WIN32
92         if ((unsigned)fd >= FD_SETSIZE)
93         {
94             errno = EINVAL;
95             return -1;
96         }
97 #endif
98         if (fds[i].events & POLLIN)
99             FD_SET (fd, rdset);
100         if (fds[i].events & POLLOUT)
101             FD_SET (fd, wrset);
102         if (fds[i].events & POLLPRI)
103             FD_SET (fd, exset);
104     }
105
106     if (timeout >= 0)
107     {
108         div_t d = div (timeout, 1000);
109         tv.tv_sec = d.quot;
110         tv.tv_usec = d.rem * 1000;
111     }
112
113     val = select (val + 1, rdset, wrset, exset,
114                   (timeout >= 0) ? &tv : NULL);
115     if (val == -1)
116         return -1;
117
118     for (unsigned i = 0; i < nfds; i++)
119     {
120         int fd = fds[i].fd;
121         fds[i].revents = (FD_ISSET (fd, rdset) ? POLLIN : 0)
122                        | (FD_ISSET (fd, wrset) ? POLLOUT : 0)
123                        | (FD_ISSET (fd, exset) ? POLLPRI : 0);
124     }
125 #ifdef WIN32
126     free (exset);
127     free (wrset);
128     free (rdset);
129 #endif
130     return val;
131 }