Add metrics for when a cast is started or stopped from the system tray.
[chromium-blink-merge.git] / third_party / libevent / epoll.c
blob4387ef896dfb03e66a4da83f0db1951c0f638898
1 /*
2 * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
31 #include <stdint.h>
32 #include <sys/types.h>
33 #include <sys/resource.h>
34 #ifdef HAVE_SYS_TIME_H
35 #include <sys/time.h>
36 #else
37 #include <sys/_libevent_time.h>
38 #endif
39 #include <sys/queue.h>
40 #include <sys/epoll.h>
41 #include <signal.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <errno.h>
47 #ifdef HAVE_FCNTL_H
48 #include <fcntl.h>
49 #endif
51 #include "event.h"
52 #include "event-internal.h"
53 #include "evsignal.h"
54 #include "log.h"
56 /* due to limitations in the epoll interface, we need to keep track of
57 * all file descriptors outself.
59 struct evepoll {
60 struct event *evread;
61 struct event *evwrite;
64 struct epollop {
65 struct evepoll *fds;
66 int nfds;
67 struct epoll_event *events;
68 int nevents;
69 int epfd;
72 static void *epoll_init (struct event_base *);
73 static int epoll_add (void *, struct event *);
74 static int epoll_del (void *, struct event *);
75 static int epoll_dispatch (struct event_base *, void *, struct timeval *);
76 static void epoll_dealloc (struct event_base *, void *);
78 const struct eventop epollops = {
79 "epoll",
80 epoll_init,
81 epoll_add,
82 epoll_del,
83 epoll_dispatch,
84 epoll_dealloc,
85 1 /* need reinit */
88 #ifdef HAVE_SETFD
89 #define FD_CLOSEONEXEC(x) do { \
90 if (fcntl(x, F_SETFD, 1) == -1) \
91 event_warn("fcntl(%d, F_SETFD)", x); \
92 } while (0)
93 #else
94 #define FD_CLOSEONEXEC(x)
95 #endif
97 /* On Linux kernels at least up to 2.6.24.4, epoll can't handle timeout
98 * values bigger than (LONG_MAX - 999ULL)/HZ. HZ in the wild can be
99 * as big as 1000, and LONG_MAX can be as small as (1<<31)-1, so the
100 * largest number of msec we can support here is 2147482. Let's
101 * round that down by 47 seconds.
103 #define MAX_EPOLL_TIMEOUT_MSEC (35*60*1000)
105 #define INITIAL_NFILES 32
106 #define INITIAL_NEVENTS 32
107 #define MAX_NEVENTS 4096
109 static void *
110 epoll_init(struct event_base *base)
112 int epfd;
113 struct epollop *epollop;
115 /* Disable epollueue when this environment variable is set */
116 if (evutil_getenv("EVENT_NOEPOLL"))
117 return (NULL);
119 /* Initalize the kernel queue */
120 if ((epfd = epoll_create(32000)) == -1) {
121 if (errno != ENOSYS)
122 event_warn("epoll_create");
123 return (NULL);
126 FD_CLOSEONEXEC(epfd);
128 if (!(epollop = calloc(1, sizeof(struct epollop))))
129 return (NULL);
131 epollop->epfd = epfd;
133 /* Initalize fields */
134 epollop->events = malloc(INITIAL_NEVENTS * sizeof(struct epoll_event));
135 if (epollop->events == NULL) {
136 free(epollop);
137 return (NULL);
139 epollop->nevents = INITIAL_NEVENTS;
141 epollop->fds = calloc(INITIAL_NFILES, sizeof(struct evepoll));
142 if (epollop->fds == NULL) {
143 free(epollop->events);
144 free(epollop);
145 return (NULL);
147 epollop->nfds = INITIAL_NFILES;
149 evsignal_init(base);
151 return (epollop);
154 static int
155 epoll_recalc(struct event_base *base, void *arg, int max)
157 struct epollop *epollop = arg;
159 if (max >= epollop->nfds) {
160 struct evepoll *fds;
161 int nfds;
163 nfds = epollop->nfds;
164 while (nfds <= max)
165 nfds <<= 1;
167 fds = realloc(epollop->fds, nfds * sizeof(struct evepoll));
168 if (fds == NULL) {
169 event_warn("realloc");
170 return (-1);
172 epollop->fds = fds;
173 memset(fds + epollop->nfds, 0,
174 (nfds - epollop->nfds) * sizeof(struct evepoll));
175 epollop->nfds = nfds;
178 return (0);
181 static int
182 epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
184 struct epollop *epollop = arg;
185 struct epoll_event *events = epollop->events;
186 struct evepoll *evep;
187 int i, res, timeout = -1;
189 if (tv != NULL)
190 timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
192 if (timeout > MAX_EPOLL_TIMEOUT_MSEC) {
193 /* Linux kernels can wait forever if the timeout is too big;
194 * see comment on MAX_EPOLL_TIMEOUT_MSEC. */
195 timeout = MAX_EPOLL_TIMEOUT_MSEC;
198 res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
200 if (res == -1) {
201 if (errno != EINTR) {
202 event_warn("epoll_wait");
203 return (-1);
206 evsignal_process(base);
207 return (0);
208 } else if (base->sig.evsignal_caught) {
209 evsignal_process(base);
212 event_debug(("%s: epoll_wait reports %d", __func__, res));
214 for (i = 0; i < res; i++) {
215 int what = events[i].events;
216 struct event *evread = NULL, *evwrite = NULL;
217 int fd = events[i].data.fd;
219 if (fd < 0 || fd >= epollop->nfds)
220 continue;
221 evep = &epollop->fds[fd];
223 if (what & (EPOLLHUP|EPOLLERR)) {
224 evread = evep->evread;
225 evwrite = evep->evwrite;
226 } else {
227 if (what & EPOLLIN) {
228 evread = evep->evread;
231 if (what & EPOLLOUT) {
232 evwrite = evep->evwrite;
236 if (!(evread||evwrite))
237 continue;
239 if (evread != NULL)
240 event_active(evread, EV_READ, 1);
241 if (evwrite != NULL)
242 event_active(evwrite, EV_WRITE, 1);
245 if (res == epollop->nevents && epollop->nevents < MAX_NEVENTS) {
246 /* We used all of the event space this time. We should
247 be ready for more events next time. */
248 int new_nevents = epollop->nevents * 2;
249 struct epoll_event *new_events;
251 new_events = realloc(epollop->events,
252 new_nevents * sizeof(struct epoll_event));
253 if (new_events) {
254 epollop->events = new_events;
255 epollop->nevents = new_nevents;
259 return (0);
263 static int
264 epoll_add(void *arg, struct event *ev)
266 struct epollop *epollop = arg;
267 struct epoll_event epev = {0, {0}};
268 struct evepoll *evep;
269 int fd, op, events;
271 if (ev->ev_events & EV_SIGNAL)
272 return (evsignal_add(ev));
274 fd = ev->ev_fd;
275 if (fd >= epollop->nfds) {
276 /* Extent the file descriptor array as necessary */
277 if (epoll_recalc(ev->ev_base, epollop, fd) == -1)
278 return (-1);
280 evep = &epollop->fds[fd];
281 op = EPOLL_CTL_ADD;
282 events = 0;
283 if (evep->evread != NULL) {
284 events |= EPOLLIN;
285 op = EPOLL_CTL_MOD;
287 if (evep->evwrite != NULL) {
288 events |= EPOLLOUT;
289 op = EPOLL_CTL_MOD;
292 if (ev->ev_events & EV_READ)
293 events |= EPOLLIN;
294 if (ev->ev_events & EV_WRITE)
295 events |= EPOLLOUT;
297 epev.data.fd = fd;
298 epev.events = events;
299 if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1)
300 return (-1);
302 /* Update events responsible */
303 if (ev->ev_events & EV_READ)
304 evep->evread = ev;
305 if (ev->ev_events & EV_WRITE)
306 evep->evwrite = ev;
308 return (0);
311 static int
312 epoll_del(void *arg, struct event *ev)
314 struct epollop *epollop = arg;
315 struct epoll_event epev = {0, {0}};
316 struct evepoll *evep;
317 int fd, events, op;
318 int needwritedelete = 1, needreaddelete = 1;
320 if (ev->ev_events & EV_SIGNAL)
321 return (evsignal_del(ev));
323 fd = ev->ev_fd;
324 if (fd >= epollop->nfds)
325 return (0);
326 evep = &epollop->fds[fd];
328 op = EPOLL_CTL_DEL;
329 events = 0;
331 if (ev->ev_events & EV_READ)
332 events |= EPOLLIN;
333 if (ev->ev_events & EV_WRITE)
334 events |= EPOLLOUT;
336 if ((events & (EPOLLIN|EPOLLOUT)) != (EPOLLIN|EPOLLOUT)) {
337 if ((events & EPOLLIN) && evep->evwrite != NULL) {
338 needwritedelete = 0;
339 events = EPOLLOUT;
340 op = EPOLL_CTL_MOD;
341 } else if ((events & EPOLLOUT) && evep->evread != NULL) {
342 needreaddelete = 0;
343 events = EPOLLIN;
344 op = EPOLL_CTL_MOD;
348 epev.events = events;
349 epev.data.fd = fd;
351 if (needreaddelete)
352 evep->evread = NULL;
353 if (needwritedelete)
354 evep->evwrite = NULL;
356 if (epoll_ctl(epollop->epfd, op, fd, &epev) == -1)
357 return (-1);
359 return (0);
362 static void
363 epoll_dealloc(struct event_base *base, void *arg)
365 struct epollop *epollop = arg;
367 evsignal_dealloc(base);
368 if (epollop->fds)
369 free(epollop->fds);
370 if (epollop->events)
371 free(epollop->events);
372 if (epollop->epfd >= 0)
373 close(epollop->epfd);
375 memset(epollop, 0, sizeof(struct epollop));
376 free(epollop);