Imported Upstream version 2.88
[platform/upstream/dnsmasq.git] / src / poll.c
1 /* dnsmasq is Copyright (c) 2000-2022 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          {
101            /* Array too small, extend. */
102            struct pollfd *new;
103
104            arrsize = (arrsize == 0) ? 64 : arrsize * 2;
105
106            if (!(new = whine_realloc(pollfds, arrsize * sizeof(struct pollfd))))
107              return;
108
109            pollfds = new;
110          }
111
112        memmove(&pollfds[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
113
114        pollfds[i].fd = fd;
115        pollfds[i].events = event;
116        nfds++;
117      }
118 }