1 /*
2   Copyright (C) 2008 Tomash Brechko.  All rights reserved.
3 
4   When used to build Perl module:
5 
6   This library is free software; you can redistribute it and/or modify
7   it under the same terms as Perl itself, either Perl version 5.8.8
8   or, at your option, any later version of Perl 5 you may have
9   available.
10 
11   When used as a standalone library:
12 
13   This library is free software; you can redistribute it and/or modify
14   it under the terms of the GNU Lesser General Public License as
15   published by the Free Software Foundation; either version 2.1 of the
16   License, or (at your option) any later version.
17 
18   This library is distributed in the hope that it will be useful, but
19   WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21   Lesser General Public License for more details.
22 */
23 
24 #include "poll_select.h"
25 #ifndef WIN32
26 #include "socket_posix.h"
27 #else  /* WIN32 */
28 #include "socket_win32.h"
29 #endif  /* WIN32 */
30 
31 
32 int
poll_select(struct pollfd * fds,int nfds,int timeout)33 poll_select(struct pollfd *fds, int nfds, int timeout)
34 {
35   fd_set read_set, write_set, exception_set;
36   struct timeval to, *pto;
37   int max_fd = -1;
38   int select_res, poll_res;
39   int i;
40 
41   if (timeout >= 0)
42     {
43       pto = &to;
44       pto->tv_sec = timeout / 1000;
45       pto->tv_usec = (timeout % 1000) * 1000;
46     }
47   else
48     {
49       pto = NULL;
50     }
51 
52   FD_ZERO(&read_set);
53   FD_ZERO(&write_set);
54   FD_ZERO(&exception_set);
55 
56   for (i = 0; i < nfds; ++i)
57     {
58       fds[i].revents = 0;
59 
60       /* POSIX requires skipping fd less than zero.  */
61       if (fds[i].fd < 0)
62         continue;
63 
64       /*
65         To continue is the best we can do here, but we shouldn't be
66         called with non-select()'able descriptor at the first place.
67       */
68       if (! can_poll_fd(fds[i].fd))
69         continue;
70 
71       if (max_fd < fds[i].fd)
72         max_fd = fds[i].fd;
73 
74       if (fds[i].events & POLLIN)
75         FD_SET(fds[i].fd, &read_set);
76       if (fds[i].events & POLLOUT)
77         FD_SET(fds[i].fd, &write_set);
78       /*
79         poll() waits for error condition even when no other event is
80         requested (events == 0).  POSIX says that pending socket error
81         should be an exceptional condition.  However other exceptional
82         conditions are protocol-specific.  For instance for TCP
83         out-of-band data is often also exceptional.  So we enable
84         exceptions unconditionally, and callers should treat returned
85         POLLERR as "may read/write".
86       */
87       FD_SET(fds[i].fd, &exception_set);
88     }
89 
90   select_res = select(max_fd + 1, &read_set, &write_set, &exception_set, pto);
91 
92   if (select_res > 0)
93     {
94       /*
95         select() returns number of bits set, but poll() returns number
96         of flagged structures.
97       */
98       poll_res = 0;
99       for (i = 0; i < nfds; ++i)
100         {
101           if (FD_ISSET(fds[i].fd, &read_set))
102             {
103               fds[i].revents |= POLLIN;
104               --select_res;
105             }
106           if (FD_ISSET(fds[i].fd, &write_set))
107             {
108               fds[i].revents |= POLLOUT;
109               --select_res;
110             }
111           if (FD_ISSET(fds[i].fd, &exception_set))
112             {
113               fds[i].revents |= POLLERR;
114               --select_res;
115             }
116 
117           if (fds[i].revents != 0)
118             {
119               ++poll_res;
120 
121               if (select_res == 0)
122                 break;
123             }
124         }
125     }
126   else
127     {
128       poll_res = select_res;
129     }
130 
131   return poll_res;
132 }
133