]> git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/poll.c
Use poll() instead of select() to remove limits on open file descriptors.
[people/ms/dnsmasq.git] / src / poll.c
1 /* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include "dnsmasq.h"
18
19 /* Wrapper for poll(). Allocates and extends array of struct pollfds,
20 keeps them in fd order so that we can set and test conditions on
21 fd using a simple but efficient binary chop. */
22
23 /* poll_reset()
24 poll_listen(fd, event)
25 .
26 .
27 poll_listen(fd, event);
28
29 hits = do_poll(timeout);
30
31 if (poll_check(fd, event)
32 .
33 .
34
35 if (poll_check(fd, event)
36 .
37 .
38
39 event is OR of POLLIN, POLLOUT, POLLERR, etc
40 */
41
42 static struct pollfd *pollfds = NULL;
43 static nfds_t nfds, arrsize = 0;
44
45 /* Binary search. Returns either the pollfd with fd, or
46 if the fd doesn't match, or return equals nfds, the entry
47 to the left of which a new record should be inserted. */
48 static nfds_t fd_search(int fd)
49 {
50 nfds_t left, right, mid;
51
52 if ((right = nfds) == 0)
53 return 0;
54
55 left = 0;
56
57 while (1)
58 {
59 if (right == left + 1)
60 return (pollfds[left].fd >= fd) ? left : right;
61
62 mid = (left + right)/2;
63
64 if (pollfds[mid].fd > fd)
65 right = mid;
66 else
67 left = mid;
68 }
69 }
70
71 void poll_reset(void)
72 {
73 nfds = 0;
74 }
75
76 int do_poll(int timeout)
77 {
78 return poll(pollfds, nfds, timeout);
79 }
80
81 int poll_check(int fd, short event)
82 {
83 nfds_t i = fd_search(fd);
84
85 if (i < nfds && pollfds[i].fd == fd)
86 return pollfds[i].revents & event;
87
88 return 0;
89 }
90
91 void poll_listen(int fd, short event)
92 {
93 nfds_t i = fd_search(fd);
94
95 if (i < nfds && pollfds[i].fd == fd)
96 pollfds[i].events |= event;
97 else
98 {
99 if (arrsize != nfds)
100 memmove(&pollfds[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
101 else
102 {
103 /* Array too small, extend. */
104 struct pollfd *new;
105 arrsize += 64;
106
107 if (!(new = whine_malloc(arrsize * sizeof(struct pollfd))))
108 return;
109
110 if (pollfds)
111 {
112 memcpy(new, pollfds, i * sizeof(struct pollfd));
113 memcpy(&new[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
114 free(pollfds);
115 }
116
117 pollfds = new;
118 }
119
120 pollfds[i].fd = fd;
121 pollfds[i].events = event;
122 nfds++;
123 }
124 }