Blame libevent/epoll.c

Packit e9ba0d
/*
Packit e9ba0d
 * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
Packit e9ba0d
 * Copyright 2007-2012 Niels Provos, Nick Mathewson
Packit e9ba0d
 *
Packit e9ba0d
 * Redistribution and use in source and binary forms, with or without
Packit e9ba0d
 * modification, are permitted provided that the following conditions
Packit e9ba0d
 * are met:
Packit e9ba0d
 * 1. Redistributions of source code must retain the above copyright
Packit e9ba0d
 *    notice, this list of conditions and the following disclaimer.
Packit e9ba0d
 * 2. Redistributions in binary form must reproduce the above copyright
Packit e9ba0d
 *    notice, this list of conditions and the following disclaimer in the
Packit e9ba0d
 *    documentation and/or other materials provided with the distribution.
Packit e9ba0d
 * 3. The name of the author may not be used to endorse or promote products
Packit e9ba0d
 *    derived from this software without specific prior written permission.
Packit e9ba0d
 *
Packit e9ba0d
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
Packit e9ba0d
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit e9ba0d
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit e9ba0d
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit e9ba0d
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit e9ba0d
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit e9ba0d
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit e9ba0d
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit e9ba0d
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit e9ba0d
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit e9ba0d
 */
Packit e9ba0d
#include "event2/event-config.h"
Packit e9ba0d
Packit e9ba0d
#include <stdint.h>
Packit e9ba0d
#include <sys/types.h>
Packit e9ba0d
#include <sys/resource.h>
Packit e9ba0d
#ifdef _EVENT_HAVE_SYS_TIME_H
Packit e9ba0d
#include <sys/time.h>
Packit e9ba0d
#endif
Packit e9ba0d
#include <sys/queue.h>
Packit e9ba0d
#include <sys/epoll.h>
Packit e9ba0d
#include <signal.h>
Packit e9ba0d
#include <limits.h>
Packit e9ba0d
#include <stdio.h>
Packit e9ba0d
#include <stdlib.h>
Packit e9ba0d
#include <string.h>
Packit e9ba0d
#include <unistd.h>
Packit e9ba0d
#include <errno.h>
Packit e9ba0d
#ifdef _EVENT_HAVE_FCNTL_H
Packit e9ba0d
#include <fcntl.h>
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
#include "event-internal.h"
Packit e9ba0d
#include "evsignal-internal.h"
Packit e9ba0d
#include "event2/thread.h"
Packit e9ba0d
#include "evthread-internal.h"
Packit e9ba0d
#include "log-internal.h"
Packit e9ba0d
#include "evmap-internal.h"
Packit e9ba0d
#include "changelist-internal.h"
Packit e9ba0d
Packit e9ba0d
struct epollop {
Packit e9ba0d
	struct epoll_event *events;
Packit e9ba0d
	int nevents;
Packit e9ba0d
	int epfd;
Packit e9ba0d
};
Packit e9ba0d
Packit e9ba0d
static void *epoll_init(struct event_base *);
Packit e9ba0d
static int epoll_dispatch(struct event_base *, struct timeval *);
Packit e9ba0d
static void epoll_dealloc(struct event_base *);
Packit e9ba0d
Packit e9ba0d
static const struct eventop epollops_changelist = {
Packit e9ba0d
	"epoll (with changelist)",
Packit e9ba0d
	epoll_init,
Packit e9ba0d
	event_changelist_add,
Packit e9ba0d
	event_changelist_del,
Packit e9ba0d
	epoll_dispatch,
Packit e9ba0d
	epoll_dealloc,
Packit e9ba0d
	1, /* need reinit */
Packit e9ba0d
	EV_FEATURE_ET|EV_FEATURE_O1,
Packit e9ba0d
	EVENT_CHANGELIST_FDINFO_SIZE
Packit e9ba0d
};
Packit e9ba0d
Packit e9ba0d
Packit e9ba0d
static int epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
Packit e9ba0d
    short old, short events, void *p);
Packit e9ba0d
static int epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
Packit e9ba0d
    short old, short events, void *p);
Packit e9ba0d
Packit e9ba0d
const struct eventop epollops = {
Packit e9ba0d
	"epoll",
Packit e9ba0d
	epoll_init,
Packit e9ba0d
	epoll_nochangelist_add,
Packit e9ba0d
	epoll_nochangelist_del,
Packit e9ba0d
	epoll_dispatch,
Packit e9ba0d
	epoll_dealloc,
Packit e9ba0d
	1, /* need reinit */
Packit e9ba0d
	EV_FEATURE_ET|EV_FEATURE_O1,
Packit e9ba0d
	0
Packit e9ba0d
};
Packit e9ba0d
Packit e9ba0d
#define INITIAL_NEVENT 32
Packit e9ba0d
#define MAX_NEVENT 4096
Packit e9ba0d
Packit e9ba0d
/* On Linux kernels at least up to 2.6.24.4, epoll can't handle timeout
Packit e9ba0d
 * values bigger than (LONG_MAX - 999ULL)/HZ.  HZ in the wild can be
Packit e9ba0d
 * as big as 1000, and LONG_MAX can be as small as (1<<31)-1, so the
Packit e9ba0d
 * largest number of msec we can support here is 2147482.  Let's
Packit e9ba0d
 * round that down by 47 seconds.
Packit e9ba0d
 */
Packit e9ba0d
#define MAX_EPOLL_TIMEOUT_MSEC (35*60*1000)
Packit e9ba0d
Packit e9ba0d
static void *
Packit e9ba0d
epoll_init(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	int epfd;
Packit e9ba0d
	struct epollop *epollop;
Packit e9ba0d
Packit e9ba0d
	/* Initialize the kernel queue.  (The size field is ignored since
Packit e9ba0d
	 * 2.6.8.) */
Packit e9ba0d
	if ((epfd = epoll_create(32000)) == -1) {
Packit e9ba0d
		if (errno != ENOSYS)
Packit e9ba0d
			event_warn("epoll_create");
Packit e9ba0d
		return (NULL);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	evutil_make_socket_closeonexec(epfd);
Packit e9ba0d
Packit e9ba0d
	if (!(epollop = mm_calloc(1, sizeof(struct epollop)))) {
Packit e9ba0d
		close(epfd);
Packit e9ba0d
		return (NULL);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	epollop->epfd = epfd;
Packit e9ba0d
Packit e9ba0d
	/* Initialize fields */
Packit e9ba0d
	epollop->events = mm_calloc(INITIAL_NEVENT, sizeof(struct epoll_event));
Packit e9ba0d
	if (epollop->events == NULL) {
Packit e9ba0d
		mm_free(epollop);
Packit e9ba0d
		close(epfd);
Packit e9ba0d
		return (NULL);
Packit e9ba0d
	}
Packit e9ba0d
	epollop->nevents = INITIAL_NEVENT;
Packit e9ba0d
Packit e9ba0d
	if ((base->flags & EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST) != 0 ||
Packit e9ba0d
	    ((base->flags & EVENT_BASE_FLAG_IGNORE_ENV) == 0 &&
Packit e9ba0d
		evutil_getenv("EVENT_EPOLL_USE_CHANGELIST") != NULL))
Packit e9ba0d
		base->evsel = &epollops_changelist;
Packit e9ba0d
Packit e9ba0d
	evsig_init(base);
Packit e9ba0d
Packit e9ba0d
	return (epollop);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static const char *
Packit e9ba0d
change_to_string(int change)
Packit e9ba0d
{
Packit e9ba0d
	change &= (EV_CHANGE_ADD|EV_CHANGE_DEL);
Packit e9ba0d
	if (change == EV_CHANGE_ADD) {
Packit e9ba0d
		return "add";
Packit e9ba0d
	} else if (change == EV_CHANGE_DEL) {
Packit e9ba0d
		return "del";
Packit e9ba0d
	} else if (change == 0) {
Packit e9ba0d
		return "none";
Packit e9ba0d
	} else {
Packit e9ba0d
		return "???";
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static const char *
Packit e9ba0d
epoll_op_to_string(int op)
Packit e9ba0d
{
Packit e9ba0d
	return op == EPOLL_CTL_ADD?"ADD":
Packit e9ba0d
	    op == EPOLL_CTL_DEL?"DEL":
Packit e9ba0d
	    op == EPOLL_CTL_MOD?"MOD":
Packit e9ba0d
	    "???";
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
epoll_apply_one_change(struct event_base *base,
Packit e9ba0d
    struct epollop *epollop,
Packit e9ba0d
    const struct event_change *ch)
Packit e9ba0d
{
Packit e9ba0d
	struct epoll_event epev;
Packit e9ba0d
	int op, events = 0;
Packit e9ba0d
Packit e9ba0d
	if (1) {
Packit e9ba0d
		/* The logic here is a little tricky.  If we had no events set
Packit e9ba0d
		   on the fd before, we need to set op="ADD" and set
Packit e9ba0d
		   events=the events we want to add.  If we had any events set
Packit e9ba0d
		   on the fd before, and we want any events to remain on the
Packit e9ba0d
		   fd, we need to say op="MOD" and set events=the events we
Packit e9ba0d
		   want to remain.  But if we want to delete the last event,
Packit e9ba0d
		   we say op="DEL" and set events=the remaining events.  What
Packit e9ba0d
		   fun!
Packit e9ba0d
		*/
Packit e9ba0d
Packit e9ba0d
		/* TODO: Turn this into a switch or a table lookup. */
Packit e9ba0d
Packit e9ba0d
		if ((ch->read_change & EV_CHANGE_ADD) ||
Packit e9ba0d
		    (ch->write_change & EV_CHANGE_ADD)) {
Packit e9ba0d
			/* If we are adding anything at all, we'll want to do
Packit e9ba0d
			 * either an ADD or a MOD. */
Packit e9ba0d
			events = 0;
Packit e9ba0d
			op = EPOLL_CTL_ADD;
Packit e9ba0d
			if (ch->read_change & EV_CHANGE_ADD) {
Packit e9ba0d
				events |= EPOLLIN;
Packit e9ba0d
			} else if (ch->read_change & EV_CHANGE_DEL) {
Packit e9ba0d
				;
Packit e9ba0d
			} else if (ch->old_events & EV_READ) {
Packit e9ba0d
				events |= EPOLLIN;
Packit e9ba0d
			}
Packit e9ba0d
			if (ch->write_change & EV_CHANGE_ADD) {
Packit e9ba0d
				events |= EPOLLOUT;
Packit e9ba0d
			} else if (ch->write_change & EV_CHANGE_DEL) {
Packit e9ba0d
				;
Packit e9ba0d
			} else if (ch->old_events & EV_WRITE) {
Packit e9ba0d
				events |= EPOLLOUT;
Packit e9ba0d
			}
Packit e9ba0d
			if ((ch->read_change|ch->write_change) & EV_ET)
Packit e9ba0d
				events |= EPOLLET;
Packit e9ba0d
Packit e9ba0d
			if (ch->old_events) {
Packit e9ba0d
				/* If MOD fails, we retry as an ADD, and if
Packit e9ba0d
				 * ADD fails we will retry as a MOD.  So the
Packit e9ba0d
				 * only hard part here is to guess which one
Packit e9ba0d
				 * will work.  As a heuristic, we'll try
Packit e9ba0d
				 * MOD first if we think there were old
Packit e9ba0d
				 * events and ADD if we think there were none.
Packit e9ba0d
				 *
Packit e9ba0d
				 * We can be wrong about the MOD if the file
Packit e9ba0d
				 * has in fact been closed and re-opened.
Packit e9ba0d
				 *
Packit e9ba0d
				 * We can be wrong about the ADD if the
Packit e9ba0d
				 * the fd has been re-created with a dup()
Packit e9ba0d
				 * of the same file that it was before.
Packit e9ba0d
				 */
Packit e9ba0d
				op = EPOLL_CTL_MOD;
Packit e9ba0d
			}
Packit e9ba0d
		} else if ((ch->read_change & EV_CHANGE_DEL) ||
Packit e9ba0d
		    (ch->write_change & EV_CHANGE_DEL)) {
Packit e9ba0d
			/* If we're deleting anything, we'll want to do a MOD
Packit e9ba0d
			 * or a DEL. */
Packit e9ba0d
			op = EPOLL_CTL_DEL;
Packit e9ba0d
Packit e9ba0d
			if (ch->read_change & EV_CHANGE_DEL) {
Packit e9ba0d
				if (ch->write_change & EV_CHANGE_DEL) {
Packit e9ba0d
					events = EPOLLIN|EPOLLOUT;
Packit e9ba0d
				} else if (ch->old_events & EV_WRITE) {
Packit e9ba0d
					events = EPOLLOUT;
Packit e9ba0d
					op = EPOLL_CTL_MOD;
Packit e9ba0d
				} else {
Packit e9ba0d
					events = EPOLLIN;
Packit e9ba0d
				}
Packit e9ba0d
			} else if (ch->write_change & EV_CHANGE_DEL) {
Packit e9ba0d
				if (ch->old_events & EV_READ) {
Packit e9ba0d
					events = EPOLLIN;
Packit e9ba0d
					op = EPOLL_CTL_MOD;
Packit e9ba0d
				} else {
Packit e9ba0d
					events = EPOLLOUT;
Packit e9ba0d
				}
Packit e9ba0d
			}
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		if (!events)
Packit e9ba0d
			return 0;
Packit e9ba0d
Packit e9ba0d
		memset(&epev, 0, sizeof(epev));
Packit e9ba0d
		epev.data.fd = ch->fd;
Packit e9ba0d
		epev.events = events;
Packit e9ba0d
		if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == -1) {
Packit e9ba0d
			if (op == EPOLL_CTL_MOD && errno == ENOENT) {
Packit e9ba0d
				/* If a MOD operation fails with ENOENT, the
Packit e9ba0d
				 * fd was probably closed and re-opened.  We
Packit e9ba0d
				 * should retry the operation as an ADD.
Packit e9ba0d
				 */
Packit e9ba0d
				if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, ch->fd, &epev) == -1) {
Packit e9ba0d
					event_warn("Epoll MOD(%d) on %d retried as ADD; that failed too",
Packit e9ba0d
					    (int)epev.events, ch->fd);
Packit e9ba0d
					return -1;
Packit e9ba0d
				} else {
Packit e9ba0d
					event_debug(("Epoll MOD(%d) on %d retried as ADD; succeeded.",
Packit e9ba0d
						(int)epev.events,
Packit e9ba0d
						ch->fd));
Packit e9ba0d
				}
Packit e9ba0d
			} else if (op == EPOLL_CTL_ADD && errno == EEXIST) {
Packit e9ba0d
				/* If an ADD operation fails with EEXIST,
Packit e9ba0d
				 * either the operation was redundant (as with a
Packit e9ba0d
				 * precautionary add), or we ran into a fun
Packit e9ba0d
				 * kernel bug where using dup*() to duplicate the
Packit e9ba0d
				 * same file into the same fd gives you the same epitem
Packit e9ba0d
				 * rather than a fresh one.  For the second case,
Packit e9ba0d
				 * we must retry with MOD. */
Packit e9ba0d
				if (epoll_ctl(epollop->epfd, EPOLL_CTL_MOD, ch->fd, &epev) == -1) {
Packit e9ba0d
					event_warn("Epoll ADD(%d) on %d retried as MOD; that failed too",
Packit e9ba0d
					    (int)epev.events, ch->fd);
Packit e9ba0d
					return -1;
Packit e9ba0d
				} else {
Packit e9ba0d
					event_debug(("Epoll ADD(%d) on %d retried as MOD; succeeded.",
Packit e9ba0d
						(int)epev.events,
Packit e9ba0d
						ch->fd));
Packit e9ba0d
				}
Packit e9ba0d
			} else if (op == EPOLL_CTL_DEL &&
Packit e9ba0d
			    (errno == ENOENT || errno == EBADF ||
Packit e9ba0d
				errno == EPERM)) {
Packit e9ba0d
				/* If a delete fails with one of these errors,
Packit e9ba0d
				 * that's fine too: we closed the fd before we
Packit e9ba0d
				 * got around to calling epoll_dispatch. */
Packit e9ba0d
				event_debug(("Epoll DEL(%d) on fd %d gave %s: DEL was unnecessary.",
Packit e9ba0d
					(int)epev.events,
Packit e9ba0d
					ch->fd,
Packit e9ba0d
					strerror(errno)));
Packit e9ba0d
			} else {
Packit e9ba0d
				event_warn("Epoll %s(%d) on fd %d failed.  Old events were %d; read change was %d (%s); write change was %d (%s)",
Packit e9ba0d
				    epoll_op_to_string(op),
Packit e9ba0d
				    (int)epev.events,
Packit e9ba0d
				    ch->fd,
Packit e9ba0d
				    ch->old_events,
Packit e9ba0d
				    ch->read_change,
Packit e9ba0d
				    change_to_string(ch->read_change),
Packit e9ba0d
				    ch->write_change,
Packit e9ba0d
				    change_to_string(ch->write_change));
Packit e9ba0d
				return -1;
Packit e9ba0d
			}
Packit e9ba0d
		} else {
Packit e9ba0d
			event_debug(("Epoll %s(%d) on fd %d okay. [old events were %d; read change was %d; write change was %d]",
Packit e9ba0d
				epoll_op_to_string(op),
Packit e9ba0d
				(int)epev.events,
Packit e9ba0d
				(int)ch->fd,
Packit e9ba0d
				ch->old_events,
Packit e9ba0d
				ch->read_change,
Packit e9ba0d
				ch->write_change));
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
	return 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
epoll_apply_changes(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	struct event_changelist *changelist = &base->changelist;
Packit e9ba0d
	struct epollop *epollop = base->evbase;
Packit e9ba0d
	struct event_change *ch;
Packit e9ba0d
Packit e9ba0d
	int r = 0;
Packit e9ba0d
	int i;
Packit e9ba0d
Packit e9ba0d
	for (i = 0; i < changelist->n_changes; ++i) {
Packit e9ba0d
		ch = &changelist->changes[i];
Packit e9ba0d
		if (epoll_apply_one_change(base, epollop, ch) < 0)
Packit e9ba0d
			r = -1;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	return (r);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
Packit e9ba0d
    short old, short events, void *p)
Packit e9ba0d
{
Packit e9ba0d
	struct event_change ch;
Packit e9ba0d
	ch.fd = fd;
Packit e9ba0d
	ch.old_events = old;
Packit e9ba0d
	ch.read_change = ch.write_change = 0;
Packit e9ba0d
	if (events & EV_WRITE)
Packit e9ba0d
		ch.write_change = EV_CHANGE_ADD |
Packit e9ba0d
		    (events & EV_ET);
Packit e9ba0d
	if (events & EV_READ)
Packit e9ba0d
		ch.read_change = EV_CHANGE_ADD |
Packit e9ba0d
		    (events & EV_ET);
Packit e9ba0d
Packit e9ba0d
	return epoll_apply_one_change(base, base->evbase, &ch);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
Packit e9ba0d
    short old, short events, void *p)
Packit e9ba0d
{
Packit e9ba0d
	struct event_change ch;
Packit e9ba0d
	ch.fd = fd;
Packit e9ba0d
	ch.old_events = old;
Packit e9ba0d
	ch.read_change = ch.write_change = 0;
Packit e9ba0d
	if (events & EV_WRITE)
Packit e9ba0d
		ch.write_change = EV_CHANGE_DEL;
Packit e9ba0d
	if (events & EV_READ)
Packit e9ba0d
		ch.read_change = EV_CHANGE_DEL;
Packit e9ba0d
Packit e9ba0d
	return epoll_apply_one_change(base, base->evbase, &ch);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
epoll_dispatch(struct event_base *base, struct timeval *tv)
Packit e9ba0d
{
Packit e9ba0d
	struct epollop *epollop = base->evbase;
Packit e9ba0d
	struct epoll_event *events = epollop->events;
Packit e9ba0d
	int i, res;
Packit e9ba0d
	long timeout = -1;
Packit e9ba0d
Packit e9ba0d
	if (tv != NULL) {
Packit e9ba0d
		timeout = evutil_tv_to_msec(tv);
Packit e9ba0d
		if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
Packit e9ba0d
			/* Linux kernels can wait forever if the timeout is
Packit e9ba0d
			 * too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
Packit e9ba0d
			timeout = MAX_EPOLL_TIMEOUT_MSEC;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	epoll_apply_changes(base);
Packit e9ba0d
	event_changelist_remove_all(&base->changelist, base);
Packit e9ba0d
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
Packit e9ba0d
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	if (res == -1) {
Packit e9ba0d
		if (errno != EINTR) {
Packit e9ba0d
			event_warn("epoll_wait");
Packit e9ba0d
			return (-1);
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		return (0);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	event_debug(("%s: epoll_wait reports %d", __func__, res));
Packit e9ba0d
	EVUTIL_ASSERT(res <= epollop->nevents);
Packit e9ba0d
Packit e9ba0d
	for (i = 0; i < res; i++) {
Packit e9ba0d
		int what = events[i].events;
Packit e9ba0d
		short ev = 0;
Packit e9ba0d
Packit e9ba0d
		if (what & (EPOLLHUP|EPOLLERR)) {
Packit e9ba0d
			ev = EV_READ | EV_WRITE;
Packit e9ba0d
		} else {
Packit e9ba0d
			if (what & EPOLLIN)
Packit e9ba0d
				ev |= EV_READ;
Packit e9ba0d
			if (what & EPOLLOUT)
Packit e9ba0d
				ev |= EV_WRITE;
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		if (!ev)
Packit e9ba0d
			continue;
Packit e9ba0d
Packit e9ba0d
		evmap_io_active(base, events[i].data.fd, ev | EV_ET);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (res == epollop->nevents && epollop->nevents < MAX_NEVENT) {
Packit e9ba0d
		/* We used all of the event space this time.  We should
Packit e9ba0d
		   be ready for more events next time. */
Packit e9ba0d
		int new_nevents = epollop->nevents * 2;
Packit e9ba0d
		struct epoll_event *new_events;
Packit e9ba0d
Packit e9ba0d
		new_events = mm_realloc(epollop->events,
Packit e9ba0d
		    new_nevents * sizeof(struct epoll_event));
Packit e9ba0d
		if (new_events) {
Packit e9ba0d
			epollop->events = new_events;
Packit e9ba0d
			epollop->nevents = new_nevents;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	return (0);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
epoll_dealloc(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	struct epollop *epollop = base->evbase;
Packit e9ba0d
Packit e9ba0d
	evsig_dealloc(base);
Packit e9ba0d
	if (epollop->events)
Packit e9ba0d
		mm_free(epollop->events);
Packit e9ba0d
	if (epollop->epfd >= 0)
Packit e9ba0d
		close(epollop->epfd);
Packit e9ba0d
Packit e9ba0d
	memset(epollop, 0, sizeof(struct epollop));
Packit e9ba0d
	mm_free(epollop);
Packit e9ba0d
}