1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/*
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * Copyright 2000-2004 Niels Provos <provos@citi.umich.edu>
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * All rights reserved.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * Redistribution and use in source and binary forms, with or without
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * modification, are permitted provided that the following conditions
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * are met:
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * 1. Redistributions of source code must retain the above copyright
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *    notice, this list of conditions and the following disclaimer.
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * 2. Redistributions in binary form must reproduce the above copyright
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *    notice, this list of conditions and the following disclaimer in the
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *    documentation and/or other materials provided with the distribution.
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * 3. The name of the author may not be used to endorse or promote products
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *    derived from this software without specific prior written permission.
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#ifdef HAVE_CONFIG_H
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "config.h"
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sys/types.h>
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sys/resource.h>
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#ifdef HAVE_SYS_TIME_H
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sys/time.h>
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#else
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sys/_libevent_time.h>
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sys/queue.h>
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <sys/devpoll.h>
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <signal.h>
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <stdio.h>
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <stdlib.h>
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <string.h>
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <unistd.h>
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <fcntl.h>
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <errno.h>
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <assert.h>
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "event.h"
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "event-internal.h"
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "evsignal.h"
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "log.h"
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott/* due to limitations in the devpoll interface, we need to keep track of
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott * all file descriptors outself.
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott */
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct evdevpoll {
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct event *evread;
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct event *evwrite;
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct devpollop {
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct evdevpoll *fds;
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	int nfds;
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct pollfd *events;
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	int nevents;
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	int dpfd;
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct pollfd *changes;
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	int nchanges;
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic void *devpoll_init	(struct event_base *);
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int devpoll_add	(void *, struct event *);
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int devpoll_del	(void *, struct event *);
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int devpoll_dispatch	(struct event_base *, void *, struct timeval *);
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic void devpoll_dealloc	(struct event_base *, void *);
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst struct eventop devpollops = {
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	"devpoll",
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpoll_init,
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpoll_add,
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpoll_del,
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpoll_dispatch,
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpoll_dealloc,
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	1 /* need reinit */
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#define NEVENT	32000
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottdevpoll_commit(struct devpollop *devpollop)
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	/*
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 * Due to a bug in Solaris, we have to use pwrite with an offset of 0.
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 * Write is limited to 2GB of data, until it will fail.
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 */
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (pwrite(devpollop->dpfd, devpollop->changes,
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		sizeof(struct pollfd) * devpollop->nchanges, 0) == -1)
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return(-1);
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpollop->nchanges = 0;
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	return(0);
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottdevpoll_queue(struct devpollop *devpollop, int fd, int events) {
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct pollfd *pfd;
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (devpollop->nchanges >= devpollop->nevents) {
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		/*
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		 * Change buffer is full, must commit it to /dev/poll before
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		 * adding more
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		 */
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (devpoll_commit(devpollop) != 0)
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			return(-1);
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	pfd = &devpollop->changes[devpollop->nchanges++];
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	pfd->fd = fd;
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	pfd->events = events;
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	pfd->revents = 0;
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	return(0);
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic void *
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottdevpoll_init(struct event_base *base)
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	int dpfd, nfiles = NEVENT;
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct rlimit rl;
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct devpollop *devpollop;
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	/* Disable devpoll when this environment variable is set */
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (evutil_getenv("EVENT_NODEVPOLL"))
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return (NULL);
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (!(devpollop = calloc(1, sizeof(struct devpollop))))
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return (NULL);
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	    rl.rlim_cur != RLIM_INFINITY)
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		nfiles = rl.rlim_cur;
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	/* Initialize the kernel queue */
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if ((dpfd = open("/dev/poll", O_RDWR)) == -1) {
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                event_warn("open: /dev/poll");
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		free(devpollop);
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return (NULL);
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpollop->dpfd = dpfd;
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	/* Initialize fields */
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpollop->events = calloc(nfiles, sizeof(struct pollfd));
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (devpollop->events == NULL) {
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		free(devpollop);
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		close(dpfd);
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return (NULL);
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpollop->nevents = nfiles;
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpollop->fds = calloc(nfiles, sizeof(struct evdevpoll));
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (devpollop->fds == NULL) {
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		free(devpollop->events);
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		free(devpollop);
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		close(dpfd);
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return (NULL);
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpollop->nfds = nfiles;
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	devpollop->changes = calloc(nfiles, sizeof(struct pollfd));
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (devpollop->changes == NULL) {
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		free(devpollop->fds);
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		free(devpollop->events);
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		free(devpollop);
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		close(dpfd);
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return (NULL);
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	evsignal_init(base);
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	return (devpollop);
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottdevpoll_recalc(struct event_base *base, void *arg, int max)
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct devpollop *devpollop = arg;
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (max >= devpollop->nfds) {
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		struct evdevpoll *fds;
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		int nfds;
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		nfds = devpollop->nfds;
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		while (nfds <= max)
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			nfds <<= 1;
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		fds = realloc(devpollop->fds, nfds * sizeof(struct evdevpoll));
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (fds == NULL) {
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			event_warn("realloc");
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			return (-1);
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		}
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		devpollop->fds = fds;
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		memset(fds + devpollop->nfds, 0,
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		    (nfds - devpollop->nfds) * sizeof(struct evdevpoll));
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		devpollop->nfds = nfds;
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	return (0);
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottdevpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct devpollop *devpollop = arg;
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct pollfd *events = devpollop->events;
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct dvpoll dvp;
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct evdevpoll *evdp;
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	int i, res, timeout = -1;
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (devpollop->nchanges)
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		devpoll_commit(devpollop);
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (tv != NULL)
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	dvp.dp_fds = devpollop->events;
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	dvp.dp_nfds = devpollop->nevents;
229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	dvp.dp_timeout = timeout;
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	res = ioctl(devpollop->dpfd, DP_POLL, &dvp);
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (res == -1) {
234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (errno != EINTR) {
235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			event_warn("ioctl: DP_POLL");
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			return (-1);
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		}
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		evsignal_process(base);
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return (0);
241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	} else if (base->sig.evsignal_caught) {
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		evsignal_process(base);
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	event_debug(("%s: devpoll_wait reports %d", __func__, res));
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	for (i = 0; i < res; i++) {
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		int which = 0;
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		int what = events[i].revents;
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		struct event *evread = NULL, *evwrite = NULL;
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		assert(events[i].fd < devpollop->nfds);
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		evdp = &devpollop->fds[events[i].fd];
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                if (what & POLLHUP)
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                        what |= POLLIN | POLLOUT;
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                else if (what & POLLERR)
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                        what |= POLLIN | POLLOUT;
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (what & POLLIN) {
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			evread = evdp->evread;
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			which |= EV_READ;
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		}
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (what & POLLOUT) {
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			evwrite = evdp->evwrite;
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			which |= EV_WRITE;
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		}
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (!which)
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			continue;
272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (evread != NULL && !(evread->ev_events & EV_PERSIST))
274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			event_del(evread);
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (evwrite != NULL && evwrite != evread &&
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		    !(evwrite->ev_events & EV_PERSIST))
277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			event_del(evwrite);
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (evread != NULL)
280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			event_active(evread, EV_READ, 1);
281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (evwrite != NULL)
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			event_active(evwrite, EV_WRITE, 1);
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	return (0);
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottdevpoll_add(void *arg, struct event *ev)
291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct devpollop *devpollop = arg;
293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct evdevpoll *evdp;
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	int fd, events;
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (ev->ev_events & EV_SIGNAL)
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return (evsignal_add(ev));
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	fd = ev->ev_fd;
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (fd >= devpollop->nfds) {
301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		/* Extend the file descriptor array as necessary */
302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (devpoll_recalc(ev->ev_base, devpollop, fd) == -1)
303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			return (-1);
304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	evdp = &devpollop->fds[fd];
306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	/*
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 * It's not necessary to OR the existing read/write events that we
309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 * are currently interested in with the new event we are adding.
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 * The /dev/poll driver ORs any new events with the existing events
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 * that it has cached for the fd.
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 */
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	events = 0;
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (ev->ev_events & EV_READ) {
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (evdp->evread && evdp->evread != ev) {
317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		   /* There is already a different read event registered */
318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		   return(-1);
319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		}
320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		events |= POLLIN;
321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (ev->ev_events & EV_WRITE) {
324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if (evdp->evwrite && evdp->evwrite != ev) {
325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		   /* There is already a different write event registered */
326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		   return(-1);
327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		}
328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		events |= POLLOUT;
329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (devpoll_queue(devpollop, fd, events) != 0)
332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return(-1);
333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	/* Update events responsible */
335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (ev->ev_events & EV_READ)
336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		evdp->evread = ev;
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (ev->ev_events & EV_WRITE)
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		evdp->evwrite = ev;
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	return (0);
341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic int
344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottdevpoll_del(void *arg, struct event *ev)
345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct devpollop *devpollop = arg;
347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct evdevpoll *evdp;
348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	int fd, events;
349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	int needwritedelete = 1, needreaddelete = 1;
350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (ev->ev_events & EV_SIGNAL)
352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return (evsignal_del(ev));
353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	fd = ev->ev_fd;
355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (fd >= devpollop->nfds)
356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return (0);
357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	evdp = &devpollop->fds[fd];
358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	events = 0;
360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (ev->ev_events & EV_READ)
361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		events |= POLLIN;
362c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (ev->ev_events & EV_WRITE)
363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		events |= POLLOUT;
364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
365c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	/*
366c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 * The only way to remove an fd from the /dev/poll monitored set is
367c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 * to use POLLREMOVE by itself.  This removes ALL events for the fd
368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 * provided so if we care about two events and are only removing one
369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 * we must re-add the other event after POLLREMOVE.
370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	 */
371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0)
373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		return(-1);
374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if ((events & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) {
376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		/*
377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		 * We're not deleting all events, so we must resubmit the
378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		 * event that we are still interested in if one exists.
379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		 */
380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		if ((events & POLLIN) && evdp->evwrite != NULL) {
382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			/* Deleting read, still care about write */
383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			devpoll_queue(devpollop, fd, POLLOUT);
384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			needwritedelete = 0;
385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		} else if ((events & POLLOUT) && evdp->evread != NULL) {
386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			/* Deleting write, still care about read */
387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			devpoll_queue(devpollop, fd, POLLIN);
388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott			needreaddelete = 0;
389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		}
390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	}
391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (needreaddelete)
393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		evdp->evread = NULL;
394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (needwritedelete)
395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		evdp->evwrite = NULL;
396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	return (0);
398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic void
401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottdevpoll_dealloc(struct event_base *base, void *arg)
402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott{
403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	struct devpollop *devpollop = arg;
404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	evsignal_dealloc(base);
406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (devpollop->fds)
407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		free(devpollop->fds);
408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (devpollop->events)
409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		free(devpollop->events);
410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (devpollop->changes)
411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		free(devpollop->changes);
412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	if (devpollop->dpfd >= 0)
413c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott		close(devpollop->dpfd);
414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	memset(devpollop, 0, sizeof(struct devpollop));
416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott	free(devpollop);
417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
418