]> arthur.barton.de Git - netatalk.git/blob - libevent/poll.c
Add silent rules to libevent
[netatalk.git] / libevent / poll.c
1 /*      $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
2
3 /*
4  * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
5  * Copyright 2007-2012 Niels Provos and Nick Mathewson
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 #include "event2/event-config.h"
30
31 #include <sys/types.h>
32 #ifdef _EVENT_HAVE_SYS_TIME_H
33 #include <sys/time.h>
34 #endif
35 #include <sys/queue.h>
36 #include <poll.h>
37 #include <signal.h>
38 #include <limits.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <errno.h>
44
45 #include "event-internal.h"
46 #include "evsignal-internal.h"
47 #include "log-internal.h"
48 #include "evmap-internal.h"
49 #include "event2/thread.h"
50 #include "evthread-internal.h"
51
52 struct pollidx {
53         int idxplus1;
54 };
55
56 struct pollop {
57         int event_count;                /* Highest number alloc */
58         int nfds;                       /* Highest number used */
59         int realloc_copy;               /* True iff we must realloc
60                                          * event_set_copy */
61         struct pollfd *event_set;
62         struct pollfd *event_set_copy;
63 };
64
65 static void *poll_init(struct event_base *);
66 static int poll_add(struct event_base *, int, short old, short events, void *_idx);
67 static int poll_del(struct event_base *, int, short old, short events, void *_idx);
68 static int poll_dispatch(struct event_base *, struct timeval *);
69 static void poll_dealloc(struct event_base *);
70
71 const struct eventop pollops = {
72         "poll",
73         poll_init,
74         poll_add,
75         poll_del,
76         poll_dispatch,
77         poll_dealloc,
78         0, /* doesn't need_reinit */
79         EV_FEATURE_FDS,
80         sizeof(struct pollidx),
81 };
82
83 static void *
84 poll_init(struct event_base *base)
85 {
86         struct pollop *pollop;
87
88         if (!(pollop = mm_calloc(1, sizeof(struct pollop))))
89                 return (NULL);
90
91         evsig_init(base);
92
93         return (pollop);
94 }
95
96 #ifdef CHECK_INVARIANTS
97 static void
98 poll_check_ok(struct pollop *pop)
99 {
100         int i, idx;
101         struct event *ev;
102
103         for (i = 0; i < pop->fd_count; ++i) {
104                 idx = pop->idxplus1_by_fd[i]-1;
105                 if (idx < 0)
106                         continue;
107                 EVUTIL_ASSERT(pop->event_set[idx].fd == i);
108         }
109         for (i = 0; i < pop->nfds; ++i) {
110                 struct pollfd *pfd = &pop->event_set[i];
111                 EVUTIL_ASSERT(pop->idxplus1_by_fd[pfd->fd] == i+1);
112         }
113 }
114 #else
115 #define poll_check_ok(pop)
116 #endif
117
118 static int
119 poll_dispatch(struct event_base *base, struct timeval *tv)
120 {
121         int res, i, j, nfds;
122         long msec = -1;
123         struct pollop *pop = base->evbase;
124         struct pollfd *event_set;
125
126         poll_check_ok(pop);
127
128         nfds = pop->nfds;
129
130 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
131         if (base->th_base_lock) {
132                 /* If we're using this backend in a multithreaded setting,
133                  * then we need to work on a copy of event_set, so that we can
134                  * let other threads modify the main event_set while we're
135                  * polling. If we're not multithreaded, then we'll skip the
136                  * copy step here to save memory and time. */
137                 if (pop->realloc_copy) {
138                         struct pollfd *tmp = mm_realloc(pop->event_set_copy,
139                             pop->event_count * sizeof(struct pollfd));
140                         if (tmp == NULL) {
141                                 event_warn("realloc");
142                                 return -1;
143                         }
144                         pop->event_set_copy = tmp;
145                         pop->realloc_copy = 0;
146                 }
147                 memcpy(pop->event_set_copy, pop->event_set,
148                     sizeof(struct pollfd)*nfds);
149                 event_set = pop->event_set_copy;
150         } else {
151                 event_set = pop->event_set;
152         }
153 #else
154         event_set = pop->event_set;
155 #endif
156
157         if (tv != NULL) {
158                 msec = evutil_tv_to_msec(tv);
159                 if (msec < 0 || msec > INT_MAX)
160                         msec = INT_MAX;
161         }
162
163         EVBASE_RELEASE_LOCK(base, th_base_lock);
164
165         res = poll(event_set, nfds, msec);
166
167         EVBASE_ACQUIRE_LOCK(base, th_base_lock);
168
169         if (res == -1) {
170                 if (errno != EINTR) {
171                         event_warn("poll");
172                         return (-1);
173                 }
174
175                 return (0);
176         }
177
178         event_debug(("%s: poll reports %d", __func__, res));
179
180         if (res == 0 || nfds == 0)
181                 return (0);
182
183         i = random() % nfds;
184         for (j = 0; j < nfds; j++) {
185                 int what;
186                 if (++i == nfds)
187                         i = 0;
188                 what = event_set[i].revents;
189                 if (!what)
190                         continue;
191
192                 res = 0;
193
194                 /* If the file gets closed notify */
195                 if (what & (POLLHUP|POLLERR))
196                         what |= POLLIN|POLLOUT;
197                 if (what & POLLIN)
198                         res |= EV_READ;
199                 if (what & POLLOUT)
200                         res |= EV_WRITE;
201                 if (res == 0)
202                         continue;
203
204                 evmap_io_active(base, event_set[i].fd, res);
205         }
206
207         return (0);
208 }
209
210 static int
211 poll_add(struct event_base *base, int fd, short old, short events, void *_idx)
212 {
213         struct pollop *pop = base->evbase;
214         struct pollfd *pfd = NULL;
215         struct pollidx *idx = _idx;
216         int i;
217
218         EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
219         if (!(events & (EV_READ|EV_WRITE)))
220                 return (0);
221
222         poll_check_ok(pop);
223         if (pop->nfds + 1 >= pop->event_count) {
224                 struct pollfd *tmp_event_set;
225                 int tmp_event_count;
226
227                 if (pop->event_count < 32)
228                         tmp_event_count = 32;
229                 else
230                         tmp_event_count = pop->event_count * 2;
231
232                 /* We need more file descriptors */
233                 tmp_event_set = mm_realloc(pop->event_set,
234                                  tmp_event_count * sizeof(struct pollfd));
235                 if (tmp_event_set == NULL) {
236                         event_warn("realloc");
237                         return (-1);
238                 }
239                 pop->event_set = tmp_event_set;
240
241                 pop->event_count = tmp_event_count;
242                 pop->realloc_copy = 1;
243         }
244
245         i = idx->idxplus1 - 1;
246
247         if (i >= 0) {
248                 pfd = &pop->event_set[i];
249         } else {
250                 i = pop->nfds++;
251                 pfd = &pop->event_set[i];
252                 pfd->events = 0;
253                 pfd->fd = fd;
254                 idx->idxplus1 = i + 1;
255         }
256
257         pfd->revents = 0;
258         if (events & EV_WRITE)
259                 pfd->events |= POLLOUT;
260         if (events & EV_READ)
261                 pfd->events |= POLLIN;
262         poll_check_ok(pop);
263
264         return (0);
265 }
266
267 /*
268  * Nothing to be done here.
269  */
270
271 static int
272 poll_del(struct event_base *base, int fd, short old, short events, void *_idx)
273 {
274         struct pollop *pop = base->evbase;
275         struct pollfd *pfd = NULL;
276         struct pollidx *idx = _idx;
277         int i;
278
279         EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
280         if (!(events & (EV_READ|EV_WRITE)))
281                 return (0);
282
283         poll_check_ok(pop);
284         i = idx->idxplus1 - 1;
285         if (i < 0)
286                 return (-1);
287
288         /* Do we still want to read or write? */
289         pfd = &pop->event_set[i];
290         if (events & EV_READ)
291                 pfd->events &= ~POLLIN;
292         if (events & EV_WRITE)
293                 pfd->events &= ~POLLOUT;
294         poll_check_ok(pop);
295         if (pfd->events)
296                 /* Another event cares about that fd. */
297                 return (0);
298
299         /* Okay, so we aren't interested in that fd anymore. */
300         idx->idxplus1 = 0;
301
302         --pop->nfds;
303         if (i != pop->nfds) {
304                 /*
305                  * Shift the last pollfd down into the now-unoccupied
306                  * position.
307                  */
308                 memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
309                        sizeof(struct pollfd));
310                 idx = evmap_io_get_fdinfo(&base->io, pop->event_set[i].fd);
311                 EVUTIL_ASSERT(idx);
312                 EVUTIL_ASSERT(idx->idxplus1 == pop->nfds + 1);
313                 idx->idxplus1 = i + 1;
314         }
315
316         poll_check_ok(pop);
317         return (0);
318 }
319
320 static void
321 poll_dealloc(struct event_base *base)
322 {
323         struct pollop *pop = base->evbase;
324
325         evsig_dealloc(base);
326         if (pop->event_set)
327                 mm_free(pop->event_set);
328         if (pop->event_set_copy)
329                 mm_free(pop->event_set_copy);
330
331         memset(pop, 0, sizeof(struct pollop));
332         mm_free(pop);
333 }