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