xref: /freebsd/contrib/libevent/poll.c (revision b50261e21f39a6c7249a49e7b60aa878c98512a8)
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