Blame libevent/event.c

Packit e9ba0d
/*
Packit e9ba0d
 * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
Packit e9ba0d
 * Copyright (c) 2007-2012 Niels Provos and 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
#ifdef WIN32
Packit e9ba0d
#include <winsock2.h>
Packit e9ba0d
#define WIN32_LEAN_AND_MEAN
Packit e9ba0d
#include <windows.h>
Packit e9ba0d
#undef WIN32_LEAN_AND_MEAN
Packit e9ba0d
#endif
Packit e9ba0d
#include <sys/types.h>
Packit e9ba0d
#if !defined(WIN32) && defined(_EVENT_HAVE_SYS_TIME_H)
Packit e9ba0d
#include <sys/time.h>
Packit e9ba0d
#endif
Packit e9ba0d
#include <sys/queue.h>
Packit e9ba0d
#ifdef _EVENT_HAVE_SYS_SOCKET_H
Packit e9ba0d
#include <sys/socket.h>
Packit e9ba0d
#endif
Packit e9ba0d
#include <stdio.h>
Packit e9ba0d
#include <stdlib.h>
Packit e9ba0d
#ifdef _EVENT_HAVE_UNISTD_H
Packit e9ba0d
#include <unistd.h>
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_SYS_EVENTFD_H
Packit e9ba0d
#include <sys/eventfd.h>
Packit e9ba0d
#endif
Packit e9ba0d
#include <ctype.h>
Packit e9ba0d
#include <errno.h>
Packit e9ba0d
#include <signal.h>
Packit e9ba0d
#include <string.h>
Packit e9ba0d
#include <time.h>
Packit e9ba0d
Packit e9ba0d
#include "event2/event.h"
Packit e9ba0d
#include "event2/event_struct.h"
Packit e9ba0d
#include "event2/event_compat.h"
Packit e9ba0d
#include "event-internal.h"
Packit e9ba0d
#include "defer-internal.h"
Packit e9ba0d
#include "evthread-internal.h"
Packit e9ba0d
#include "event2/thread.h"
Packit e9ba0d
#include "event2/util.h"
Packit e9ba0d
#include "log-internal.h"
Packit e9ba0d
#include "evmap-internal.h"
Packit e9ba0d
#include "iocp-internal.h"
Packit e9ba0d
#include "changelist-internal.h"
Packit e9ba0d
#include "ht-internal.h"
Packit e9ba0d
#include "util-internal.h"
Packit e9ba0d
Packit e9ba0d
#ifdef _EVENT_HAVE_EVENT_PORTS
Packit e9ba0d
extern const struct eventop evportops;
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_SELECT
Packit e9ba0d
extern const struct eventop selectops;
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_POLL
Packit e9ba0d
extern const struct eventop pollops;
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_EPOLL
Packit e9ba0d
extern const struct eventop epollops;
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_WORKING_KQUEUE
Packit e9ba0d
extern const struct eventop kqops;
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_DEVPOLL
Packit e9ba0d
extern const struct eventop devpollops;
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef WIN32
Packit e9ba0d
extern const struct eventop win32ops;
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
/* Array of backends in order of preference. */
Packit e9ba0d
static const struct eventop *eventops[] = {
Packit e9ba0d
#ifdef _EVENT_HAVE_EVENT_PORTS
Packit e9ba0d
	&evportops,
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_WORKING_KQUEUE
Packit e9ba0d
	&kqops,
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_EPOLL
Packit e9ba0d
	&epollops,
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_DEVPOLL
Packit e9ba0d
	&devpollops,
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_POLL
Packit e9ba0d
	&pollops,
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef _EVENT_HAVE_SELECT
Packit e9ba0d
	&selectops,
Packit e9ba0d
#endif
Packit e9ba0d
#ifdef WIN32
Packit e9ba0d
	&win32ops,
Packit e9ba0d
#endif
Packit e9ba0d
	NULL
Packit e9ba0d
};
Packit e9ba0d
Packit e9ba0d
/* Global state; deprecated */
Packit e9ba0d
struct event_base *event_global_current_base_ = NULL;
Packit e9ba0d
#define current_base event_global_current_base_
Packit e9ba0d
Packit e9ba0d
/* Global state */
Packit e9ba0d
Packit e9ba0d
static int use_monotonic;
Packit e9ba0d
Packit e9ba0d
/* Prototypes */
Packit e9ba0d
static inline int event_add_internal(struct event *ev,
Packit e9ba0d
    const struct timeval *tv, int tv_is_absolute);
Packit e9ba0d
static inline int event_del_internal(struct event *ev);
Packit e9ba0d
Packit e9ba0d
static void	event_queue_insert(struct event_base *, struct event *, int);
Packit e9ba0d
static void	event_queue_remove(struct event_base *, struct event *, int);
Packit e9ba0d
static int	event_haveevents(struct event_base *);
Packit e9ba0d
Packit e9ba0d
static int	event_process_active(struct event_base *);
Packit e9ba0d
Packit e9ba0d
static int	timeout_next(struct event_base *, struct timeval **);
Packit e9ba0d
static void	timeout_process(struct event_base *);
Packit e9ba0d
static void	timeout_correct(struct event_base *, struct timeval *);
Packit e9ba0d
Packit e9ba0d
static inline void	event_signal_closure(struct event_base *, struct event *ev);
Packit e9ba0d
static inline void	event_persist_closure(struct event_base *, struct event *ev);
Packit e9ba0d
Packit e9ba0d
static int	evthread_notify_base(struct event_base *base);
Packit e9ba0d
Packit e9ba0d
#ifndef _EVENT_DISABLE_DEBUG_MODE
Packit e9ba0d
/* These functions implement a hashtable of which 'struct event *' structures
Packit e9ba0d
 * have been setup or added.  We don't want to trust the content of the struct
Packit e9ba0d
 * event itself, since we're trying to work through cases where an event gets
Packit e9ba0d
 * clobbered or freed.  Instead, we keep a hashtable indexed by the pointer.
Packit e9ba0d
 */
Packit e9ba0d
Packit e9ba0d
struct event_debug_entry {
Packit e9ba0d
	HT_ENTRY(event_debug_entry) node;
Packit e9ba0d
	const struct event *ptr;
Packit e9ba0d
	unsigned added : 1;
Packit e9ba0d
};
Packit e9ba0d
Packit e9ba0d
static inline unsigned
Packit e9ba0d
hash_debug_entry(const struct event_debug_entry *e)
Packit e9ba0d
{
Packit e9ba0d
	/* We need to do this silliness to convince compilers that we
Packit e9ba0d
	 * honestly mean to cast e->ptr to an integer, and discard any
Packit e9ba0d
	 * part of it that doesn't fit in an unsigned.
Packit e9ba0d
	 */
Packit e9ba0d
	unsigned u = (unsigned) ((ev_uintptr_t) e->ptr);
Packit e9ba0d
	/* Our hashtable implementation is pretty sensitive to low bits,
Packit e9ba0d
	 * and every struct event is over 64 bytes in size, so we can
Packit e9ba0d
	 * just say >>6. */
Packit e9ba0d
	return (u >> 6);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static inline int
Packit e9ba0d
eq_debug_entry(const struct event_debug_entry *a,
Packit e9ba0d
    const struct event_debug_entry *b)
Packit e9ba0d
{
Packit e9ba0d
	return a->ptr == b->ptr;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int _event_debug_mode_on = 0;
Packit e9ba0d
/* Set if it's too late to enable event_debug_mode. */
Packit e9ba0d
static int event_debug_mode_too_late = 0;
Packit e9ba0d
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
Packit e9ba0d
static void *_event_debug_map_lock = NULL;
Packit e9ba0d
#endif
Packit e9ba0d
static HT_HEAD(event_debug_map, event_debug_entry) global_debug_map =
Packit e9ba0d
	HT_INITIALIZER();
Packit e9ba0d
Packit e9ba0d
HT_PROTOTYPE(event_debug_map, event_debug_entry, node, hash_debug_entry,
Packit e9ba0d
    eq_debug_entry)
Packit e9ba0d
HT_GENERATE(event_debug_map, event_debug_entry, node, hash_debug_entry,
Packit e9ba0d
    eq_debug_entry, 0.5, mm_malloc, mm_realloc, mm_free)
Packit e9ba0d
Packit e9ba0d
/* Macro: record that ev is now setup (that is, ready for an add) */
Packit e9ba0d
#define _event_debug_note_setup(ev) do {				\
Packit e9ba0d
	if (_event_debug_mode_on) {					\
Packit e9ba0d
		struct event_debug_entry *dent,find;			\
Packit e9ba0d
		find.ptr = (ev);					\
Packit e9ba0d
		EVLOCK_LOCK(_event_debug_map_lock, 0);			\
Packit e9ba0d
		dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
Packit e9ba0d
		if (dent) {						\
Packit e9ba0d
			dent->added = 0;				\
Packit e9ba0d
		} else {						\
Packit e9ba0d
			dent = mm_malloc(sizeof(*dent));		\
Packit e9ba0d
			if (!dent)					\
Packit e9ba0d
				event_err(1,				\
Packit e9ba0d
				    "Out of memory in debugging code");	\
Packit e9ba0d
			dent->ptr = (ev);				\
Packit e9ba0d
			dent->added = 0;				\
Packit e9ba0d
			HT_INSERT(event_debug_map, &global_debug_map, dent); \
Packit e9ba0d
		}							\
Packit e9ba0d
		EVLOCK_UNLOCK(_event_debug_map_lock, 0);		\
Packit e9ba0d
	}								\
Packit e9ba0d
	event_debug_mode_too_late = 1;					\
Packit e9ba0d
	} while (0)
Packit e9ba0d
/* Macro: record that ev is no longer setup */
Packit e9ba0d
#define _event_debug_note_teardown(ev) do {				\
Packit e9ba0d
	if (_event_debug_mode_on) {					\
Packit e9ba0d
		struct event_debug_entry *dent,find;			\
Packit e9ba0d
		find.ptr = (ev);					\
Packit e9ba0d
		EVLOCK_LOCK(_event_debug_map_lock, 0);			\
Packit e9ba0d
		dent = HT_REMOVE(event_debug_map, &global_debug_map, &find); \
Packit e9ba0d
		if (dent)						\
Packit e9ba0d
			mm_free(dent);					\
Packit e9ba0d
		EVLOCK_UNLOCK(_event_debug_map_lock, 0);		\
Packit e9ba0d
	}								\
Packit e9ba0d
	event_debug_mode_too_late = 1;					\
Packit e9ba0d
	} while (0)
Packit e9ba0d
/* Macro: record that ev is now added */
Packit e9ba0d
#define _event_debug_note_add(ev)	do {				\
Packit e9ba0d
	if (_event_debug_mode_on) {					\
Packit e9ba0d
		struct event_debug_entry *dent,find;			\
Packit e9ba0d
		find.ptr = (ev);					\
Packit e9ba0d
		EVLOCK_LOCK(_event_debug_map_lock, 0);			\
Packit e9ba0d
		dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
Packit e9ba0d
		if (dent) {						\
Packit e9ba0d
			dent->added = 1;				\
Packit e9ba0d
		} else {						\
Packit e9ba0d
			event_errx(_EVENT_ERR_ABORT,			\
Packit e9ba0d
			    "%s: noting an add on a non-setup event %p" \
Packit e9ba0d
			    " (events: 0x%x, fd: "EV_SOCK_FMT		\
Packit e9ba0d
			    ", flags: 0x%x)",				\
Packit e9ba0d
			    __func__, (ev), (ev)->ev_events,		\
Packit e9ba0d
			    EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags);	\
Packit e9ba0d
		}							\
Packit e9ba0d
		EVLOCK_UNLOCK(_event_debug_map_lock, 0);		\
Packit e9ba0d
	}								\
Packit e9ba0d
	event_debug_mode_too_late = 1;					\
Packit e9ba0d
	} while (0)
Packit e9ba0d
/* Macro: record that ev is no longer added */
Packit e9ba0d
#define _event_debug_note_del(ev) do {					\
Packit e9ba0d
	if (_event_debug_mode_on) {					\
Packit e9ba0d
		struct event_debug_entry *dent,find;			\
Packit e9ba0d
		find.ptr = (ev);					\
Packit e9ba0d
		EVLOCK_LOCK(_event_debug_map_lock, 0);			\
Packit e9ba0d
		dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
Packit e9ba0d
		if (dent) {						\
Packit e9ba0d
			dent->added = 0;				\
Packit e9ba0d
		} else {						\
Packit e9ba0d
			event_errx(_EVENT_ERR_ABORT,			\
Packit e9ba0d
			    "%s: noting a del on a non-setup event %p"	\
Packit e9ba0d
			    " (events: 0x%x, fd: "EV_SOCK_FMT		\
Packit e9ba0d
			    ", flags: 0x%x)",				\
Packit e9ba0d
			    __func__, (ev), (ev)->ev_events,		\
Packit e9ba0d
			    EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags);	\
Packit e9ba0d
		}							\
Packit e9ba0d
		EVLOCK_UNLOCK(_event_debug_map_lock, 0);		\
Packit e9ba0d
	}								\
Packit e9ba0d
	event_debug_mode_too_late = 1;					\
Packit e9ba0d
	} while (0)
Packit e9ba0d
/* Macro: assert that ev is setup (i.e., okay to add or inspect) */
Packit e9ba0d
#define _event_debug_assert_is_setup(ev) do {				\
Packit e9ba0d
	if (_event_debug_mode_on) {					\
Packit e9ba0d
		struct event_debug_entry *dent,find;			\
Packit e9ba0d
		find.ptr = (ev);					\
Packit e9ba0d
		EVLOCK_LOCK(_event_debug_map_lock, 0);			\
Packit e9ba0d
		dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
Packit e9ba0d
		if (!dent) {						\
Packit e9ba0d
			event_errx(_EVENT_ERR_ABORT,			\
Packit e9ba0d
			    "%s called on a non-initialized event %p"	\
Packit e9ba0d
			    " (events: 0x%x, fd: "EV_SOCK_FMT\
Packit e9ba0d
			    ", flags: 0x%x)",				\
Packit e9ba0d
			    __func__, (ev), (ev)->ev_events,		\
Packit e9ba0d
			    EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags);	\
Packit e9ba0d
		}							\
Packit e9ba0d
		EVLOCK_UNLOCK(_event_debug_map_lock, 0);		\
Packit e9ba0d
	}								\
Packit e9ba0d
	} while (0)
Packit e9ba0d
/* Macro: assert that ev is not added (i.e., okay to tear down or set
Packit e9ba0d
 * up again) */
Packit e9ba0d
#define _event_debug_assert_not_added(ev) do {				\
Packit e9ba0d
	if (_event_debug_mode_on) {					\
Packit e9ba0d
		struct event_debug_entry *dent,find;			\
Packit e9ba0d
		find.ptr = (ev);					\
Packit e9ba0d
		EVLOCK_LOCK(_event_debug_map_lock, 0);			\
Packit e9ba0d
		dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
Packit e9ba0d
		if (dent && dent->added) {				\
Packit e9ba0d
			event_errx(_EVENT_ERR_ABORT,			\
Packit e9ba0d
			    "%s called on an already added event %p"	\
Packit e9ba0d
			    " (events: 0x%x, fd: "EV_SOCK_FMT", "	\
Packit e9ba0d
			    "flags: 0x%x)",				\
Packit e9ba0d
			    __func__, (ev), (ev)->ev_events,		\
Packit e9ba0d
			    EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags);	\
Packit e9ba0d
		}							\
Packit e9ba0d
		EVLOCK_UNLOCK(_event_debug_map_lock, 0);		\
Packit e9ba0d
	}								\
Packit e9ba0d
	} while (0)
Packit e9ba0d
#else
Packit e9ba0d
#define _event_debug_note_setup(ev) \
Packit e9ba0d
	((void)0)
Packit e9ba0d
#define _event_debug_note_teardown(ev) \
Packit e9ba0d
	((void)0)
Packit e9ba0d
#define _event_debug_note_add(ev) \
Packit e9ba0d
	((void)0)
Packit e9ba0d
#define _event_debug_note_del(ev) \
Packit e9ba0d
	((void)0)
Packit e9ba0d
#define _event_debug_assert_is_setup(ev) \
Packit e9ba0d
	((void)0)
Packit e9ba0d
#define _event_debug_assert_not_added(ev) \
Packit e9ba0d
	((void)0)
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
#define EVENT_BASE_ASSERT_LOCKED(base)		\
Packit e9ba0d
	EVLOCK_ASSERT_LOCKED((base)->th_base_lock)
Packit e9ba0d
Packit e9ba0d
/* The first time this function is called, it sets use_monotonic to 1
Packit e9ba0d
 * if we have a clock function that supports monotonic time */
Packit e9ba0d
static void
Packit e9ba0d
detect_monotonic(void)
Packit e9ba0d
{
Packit e9ba0d
#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
Packit e9ba0d
	struct timespec	ts;
Packit e9ba0d
	static int use_monotonic_initialized = 0;
Packit e9ba0d
Packit e9ba0d
	if (use_monotonic_initialized)
Packit e9ba0d
		return;
Packit e9ba0d
Packit e9ba0d
	if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
Packit e9ba0d
		use_monotonic = 1;
Packit e9ba0d
Packit e9ba0d
	use_monotonic_initialized = 1;
Packit e9ba0d
#endif
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* How often (in seconds) do we check for changes in wall clock time relative
Packit e9ba0d
 * to monotonic time?  Set this to -1 for 'never.' */
Packit e9ba0d
#define CLOCK_SYNC_INTERVAL -1
Packit e9ba0d
Packit e9ba0d
/** Set 'tp' to the current time according to 'base'.  We must hold the lock
Packit e9ba0d
 * on 'base'.  If there is a cached time, return it.  Otherwise, use
Packit e9ba0d
 * clock_gettime or gettimeofday as appropriate to find out the right time.
Packit e9ba0d
 * Return 0 on success, -1 on failure.
Packit e9ba0d
 */
Packit e9ba0d
static int
Packit e9ba0d
gettime(struct event_base *base, struct timeval *tp)
Packit e9ba0d
{
Packit e9ba0d
	EVENT_BASE_ASSERT_LOCKED(base);
Packit e9ba0d
Packit e9ba0d
	if (base->tv_cache.tv_sec) {
Packit e9ba0d
		*tp = base->tv_cache;
Packit e9ba0d
		return (0);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
Packit e9ba0d
	if (use_monotonic) {
Packit e9ba0d
		struct timespec	ts;
Packit e9ba0d
Packit e9ba0d
		if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
Packit e9ba0d
			return (-1);
Packit e9ba0d
Packit e9ba0d
		tp->tv_sec = ts.tv_sec;
Packit e9ba0d
		tp->tv_usec = ts.tv_nsec / 1000;
Packit e9ba0d
		if (base->last_updated_clock_diff + CLOCK_SYNC_INTERVAL
Packit e9ba0d
		    < ts.tv_sec) {
Packit e9ba0d
			struct timeval tv;
Packit e9ba0d
			evutil_gettimeofday(&tv,NULL);
Packit e9ba0d
			evutil_timersub(&tv, tp, &base->tv_clock_diff);
Packit e9ba0d
			base->last_updated_clock_diff = ts.tv_sec;
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		return (0);
Packit e9ba0d
	}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
	return (evutil_gettimeofday(tp, NULL));
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv)
Packit e9ba0d
{
Packit e9ba0d
	int r;
Packit e9ba0d
	if (!base) {
Packit e9ba0d
		base = current_base;
Packit e9ba0d
		if (!current_base)
Packit e9ba0d
			return evutil_gettimeofday(tv, NULL);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
	if (base->tv_cache.tv_sec == 0) {
Packit e9ba0d
		r = evutil_gettimeofday(tv, NULL);
Packit e9ba0d
	} else {
Packit e9ba0d
#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
Packit e9ba0d
		evutil_timeradd(&base->tv_cache, &base->tv_clock_diff, tv);
Packit e9ba0d
#else
Packit e9ba0d
		*tv = base->tv_cache;
Packit e9ba0d
#endif
Packit e9ba0d
		r = 0;
Packit e9ba0d
	}
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
	return r;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/** Make 'base' have no current cached time. */
Packit e9ba0d
static inline void
Packit e9ba0d
clear_time_cache(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	base->tv_cache.tv_sec = 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/** Replace the cached time in 'base' with the current time. */
Packit e9ba0d
static inline void
Packit e9ba0d
update_time_cache(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	base->tv_cache.tv_sec = 0;
Packit e9ba0d
	if (!(base->flags & EVENT_BASE_FLAG_NO_CACHE_TIME))
Packit e9ba0d
	    gettime(base, &base->tv_cache);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
struct event_base *
Packit e9ba0d
event_init(void)
Packit e9ba0d
{
Packit e9ba0d
	struct event_base *base = event_base_new_with_config(NULL);
Packit e9ba0d
Packit e9ba0d
	if (base == NULL) {
Packit e9ba0d
		event_errx(1, "%s: Unable to construct event_base", __func__);
Packit e9ba0d
		return NULL;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	current_base = base;
Packit e9ba0d
Packit e9ba0d
	return (base);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
struct event_base *
Packit e9ba0d
event_base_new(void)
Packit e9ba0d
{
Packit e9ba0d
	struct event_base *base = NULL;
Packit e9ba0d
	struct event_config *cfg = event_config_new();
Packit e9ba0d
	if (cfg) {
Packit e9ba0d
		base = event_base_new_with_config(cfg);
Packit e9ba0d
		event_config_free(cfg);
Packit e9ba0d
	}
Packit e9ba0d
	return base;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/** Return true iff 'method' is the name of a method that 'cfg' tells us to
Packit e9ba0d
 * avoid. */
Packit e9ba0d
static int
Packit e9ba0d
event_config_is_avoided_method(const struct event_config *cfg,
Packit e9ba0d
    const char *method)
Packit e9ba0d
{
Packit e9ba0d
	struct event_config_entry *entry;
Packit e9ba0d
Packit e9ba0d
	TAILQ_FOREACH(entry, &cfg->entries, next) {
Packit e9ba0d
		if (entry->avoid_method != NULL &&
Packit e9ba0d
		    strcmp(entry->avoid_method, method) == 0)
Packit e9ba0d
			return (1);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	return (0);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/** Return true iff 'method' is disabled according to the environment. */
Packit e9ba0d
static int
Packit e9ba0d
event_is_method_disabled(const char *name)
Packit e9ba0d
{
Packit e9ba0d
	char environment[64];
Packit e9ba0d
	int i;
Packit e9ba0d
Packit e9ba0d
	evutil_snprintf(environment, sizeof(environment), "EVENT_NO%s", name);
Packit e9ba0d
	for (i = 8; environment[i] != '\0'; ++i)
Packit e9ba0d
		environment[i] = EVUTIL_TOUPPER(environment[i]);
Packit e9ba0d
	/* Note that evutil_getenv() ignores the environment entirely if
Packit e9ba0d
	 * we're setuid */
Packit e9ba0d
	return (evutil_getenv(environment) != NULL);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_base_get_features(const struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	return base->evsel->features;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_deferred_cb_queue_init(struct deferred_cb_queue *cb)
Packit e9ba0d
{
Packit e9ba0d
	memset(cb, 0, sizeof(struct deferred_cb_queue));
Packit e9ba0d
	TAILQ_INIT(&cb->deferred_cb_list);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/** Helper for the deferred_cb queue: wake up the event base. */
Packit e9ba0d
static void
Packit e9ba0d
notify_base_cbq_callback(struct deferred_cb_queue *cb, void *baseptr)
Packit e9ba0d
{
Packit e9ba0d
	struct event_base *base = baseptr;
Packit e9ba0d
	if (EVBASE_NEED_NOTIFY(base))
Packit e9ba0d
		evthread_notify_base(base);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
struct deferred_cb_queue *
Packit e9ba0d
event_base_get_deferred_cb_queue(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	return base ? &base->defer_queue : NULL;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_enable_debug_mode(void)
Packit e9ba0d
{
Packit e9ba0d
#ifndef _EVENT_DISABLE_DEBUG_MODE
Packit e9ba0d
	if (_event_debug_mode_on)
Packit e9ba0d
		event_errx(1, "%s was called twice!", __func__);
Packit e9ba0d
	if (event_debug_mode_too_late)
Packit e9ba0d
		event_errx(1, "%s must be called *before* creating any events "
Packit e9ba0d
		    "or event_bases",__func__);
Packit e9ba0d
Packit e9ba0d
	_event_debug_mode_on = 1;
Packit e9ba0d
Packit e9ba0d
	HT_INIT(event_debug_map, &global_debug_map);
Packit e9ba0d
#endif
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
#if 0
Packit e9ba0d
void
Packit e9ba0d
event_disable_debug_mode(void)
Packit e9ba0d
{
Packit e9ba0d
	struct event_debug_entry **ent, *victim;
Packit e9ba0d
Packit e9ba0d
	EVLOCK_LOCK(_event_debug_map_lock, 0);
Packit e9ba0d
	for (ent = HT_START(event_debug_map, &global_debug_map); ent; ) {
Packit e9ba0d
		victim = *ent;
Packit e9ba0d
		ent = HT_NEXT_RMV(event_debug_map,&global_debug_map, ent);
Packit e9ba0d
		mm_free(victim);
Packit e9ba0d
	}
Packit e9ba0d
	HT_CLEAR(event_debug_map, &global_debug_map);
Packit e9ba0d
	EVLOCK_UNLOCK(_event_debug_map_lock , 0);
Packit e9ba0d
}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
struct event_base *
Packit e9ba0d
event_base_new_with_config(const struct event_config *cfg)
Packit e9ba0d
{
Packit e9ba0d
	int i;
Packit e9ba0d
	struct event_base *base;
Packit e9ba0d
	int should_check_environment;
Packit e9ba0d
Packit e9ba0d
#ifndef _EVENT_DISABLE_DEBUG_MODE
Packit e9ba0d
	event_debug_mode_too_late = 1;
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
	if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) {
Packit e9ba0d
		event_warn("%s: calloc", __func__);
Packit e9ba0d
		return NULL;
Packit e9ba0d
	}
Packit e9ba0d
	detect_monotonic();
Packit e9ba0d
	gettime(base, &base->event_tv);
Packit e9ba0d
Packit e9ba0d
	min_heap_ctor(&base->timeheap);
Packit e9ba0d
	TAILQ_INIT(&base->eventqueue);
Packit e9ba0d
	base->sig.ev_signal_pair[0] = -1;
Packit e9ba0d
	base->sig.ev_signal_pair[1] = -1;
Packit e9ba0d
	base->th_notify_fd[0] = -1;
Packit e9ba0d
	base->th_notify_fd[1] = -1;
Packit e9ba0d
Packit e9ba0d
	event_deferred_cb_queue_init(&base->defer_queue);
Packit e9ba0d
	base->defer_queue.notify_fn = notify_base_cbq_callback;
Packit e9ba0d
	base->defer_queue.notify_arg = base;
Packit e9ba0d
	if (cfg)
Packit e9ba0d
		base->flags = cfg->flags;
Packit e9ba0d
Packit e9ba0d
	evmap_io_initmap(&base->io);
Packit e9ba0d
	evmap_signal_initmap(&base->sigmap);
Packit e9ba0d
	event_changelist_init(&base->changelist);
Packit e9ba0d
Packit e9ba0d
	base->evbase = NULL;
Packit e9ba0d
Packit e9ba0d
	should_check_environment =
Packit e9ba0d
	    !(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));
Packit e9ba0d
Packit e9ba0d
	for (i = 0; eventops[i] && !base->evbase; i++) {
Packit e9ba0d
		if (cfg != NULL) {
Packit e9ba0d
			/* determine if this backend should be avoided */
Packit e9ba0d
			if (event_config_is_avoided_method(cfg,
Packit e9ba0d
				eventops[i]->name))
Packit e9ba0d
				continue;
Packit e9ba0d
			if ((eventops[i]->features & cfg->require_features)
Packit e9ba0d
			    != cfg->require_features)
Packit e9ba0d
				continue;
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		/* also obey the environment variables */
Packit e9ba0d
		if (should_check_environment &&
Packit e9ba0d
		    event_is_method_disabled(eventops[i]->name))
Packit e9ba0d
			continue;
Packit e9ba0d
Packit e9ba0d
		base->evsel = eventops[i];
Packit e9ba0d
Packit e9ba0d
		base->evbase = base->evsel->init(base);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (base->evbase == NULL) {
Packit e9ba0d
		event_warnx("%s: no event mechanism available",
Packit e9ba0d
		    __func__);
Packit e9ba0d
		base->evsel = NULL;
Packit e9ba0d
		event_base_free(base);
Packit e9ba0d
		return NULL;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (evutil_getenv("EVENT_SHOW_METHOD"))
Packit e9ba0d
		event_msgx("libevent using: %s", base->evsel->name);
Packit e9ba0d
Packit e9ba0d
	/* allocate a single active event queue */
Packit e9ba0d
	if (event_base_priority_init(base, 1) < 0) {
Packit e9ba0d
		event_base_free(base);
Packit e9ba0d
		return NULL;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	/* prepare for threading */
Packit e9ba0d
Packit e9ba0d
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
Packit e9ba0d
	if (EVTHREAD_LOCKING_ENABLED() &&
Packit e9ba0d
	    (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) {
Packit e9ba0d
		int r;
Packit e9ba0d
		EVTHREAD_ALLOC_LOCK(base->th_base_lock,
Packit e9ba0d
		    EVTHREAD_LOCKTYPE_RECURSIVE);
Packit e9ba0d
		base->defer_queue.lock = base->th_base_lock;
Packit e9ba0d
		EVTHREAD_ALLOC_COND(base->current_event_cond);
Packit e9ba0d
		r = evthread_make_base_notifiable(base);
Packit e9ba0d
		if (r<0) {
Packit e9ba0d
			event_warnx("%s: Unable to make base notifiable.", __func__);
Packit e9ba0d
			event_base_free(base);
Packit e9ba0d
			return NULL;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
#ifdef WIN32
Packit e9ba0d
	if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))
Packit e9ba0d
		event_base_start_iocp(base, cfg->n_cpus_hint);
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
	return (base);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_base_start_iocp(struct event_base *base, int n_cpus)
Packit e9ba0d
{
Packit e9ba0d
#ifdef WIN32
Packit e9ba0d
	if (base->iocp)
Packit e9ba0d
		return 0;
Packit e9ba0d
	base->iocp = event_iocp_port_launch(n_cpus);
Packit e9ba0d
	if (!base->iocp) {
Packit e9ba0d
		event_warnx("%s: Couldn't launch IOCP", __func__);
Packit e9ba0d
		return -1;
Packit e9ba0d
	}
Packit e9ba0d
	return 0;
Packit e9ba0d
#else
Packit e9ba0d
	return -1;
Packit e9ba0d
#endif
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_base_stop_iocp(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
#ifdef WIN32
Packit e9ba0d
	int rv;
Packit e9ba0d
Packit e9ba0d
	if (!base->iocp)
Packit e9ba0d
		return;
Packit e9ba0d
	rv = event_iocp_shutdown(base->iocp, -1);
Packit e9ba0d
	EVUTIL_ASSERT(rv >= 0);
Packit e9ba0d
	base->iocp = NULL;
Packit e9ba0d
#endif
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_base_free(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	int i, n_deleted=0;
Packit e9ba0d
	struct event *ev;
Packit e9ba0d
	/* XXXX grab the lock? If there is contention when one thread frees
Packit e9ba0d
	 * the base, then the contending thread will be very sad soon. */
Packit e9ba0d
Packit e9ba0d
	/* event_base_free(NULL) is how to free the current_base if we
Packit e9ba0d
	 * made it with event_init and forgot to hold a reference to it. */
Packit e9ba0d
	if (base == NULL && current_base)
Packit e9ba0d
		base = current_base;
Packit e9ba0d
	/* If we're freeing current_base, there won't be a current_base. */
Packit e9ba0d
	if (base == current_base)
Packit e9ba0d
		current_base = NULL;
Packit e9ba0d
	/* Don't actually free NULL. */
Packit e9ba0d
	if (base == NULL) {
Packit e9ba0d
		event_warnx("%s: no base to free", __func__);
Packit e9ba0d
		return;
Packit e9ba0d
	}
Packit e9ba0d
	/* XXX(niels) - check for internal events first */
Packit e9ba0d
Packit e9ba0d
#ifdef WIN32
Packit e9ba0d
	event_base_stop_iocp(base);
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
	/* threading fds if we have them */
Packit e9ba0d
	if (base->th_notify_fd[0] != -1) {
Packit e9ba0d
		event_del(&base->th_notify);
Packit e9ba0d
		EVUTIL_CLOSESOCKET(base->th_notify_fd[0]);
Packit e9ba0d
		if (base->th_notify_fd[1] != -1)
Packit e9ba0d
			EVUTIL_CLOSESOCKET(base->th_notify_fd[1]);
Packit e9ba0d
		base->th_notify_fd[0] = -1;
Packit e9ba0d
		base->th_notify_fd[1] = -1;
Packit e9ba0d
		event_debug_unassign(&base->th_notify);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	/* Delete all non-internal events. */
Packit e9ba0d
	for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) {
Packit e9ba0d
		struct event *next = TAILQ_NEXT(ev, ev_next);
Packit e9ba0d
		if (!(ev->ev_flags & EVLIST_INTERNAL)) {
Packit e9ba0d
			event_del(ev);
Packit e9ba0d
			++n_deleted;
Packit e9ba0d
		}
Packit e9ba0d
		ev = next;
Packit e9ba0d
	}
Packit e9ba0d
	while ((ev = min_heap_top(&base->timeheap)) != NULL) {
Packit e9ba0d
		event_del(ev);
Packit e9ba0d
		++n_deleted;
Packit e9ba0d
	}
Packit e9ba0d
	for (i = 0; i < base->n_common_timeouts; ++i) {
Packit e9ba0d
		struct common_timeout_list *ctl =
Packit e9ba0d
		    base->common_timeout_queues[i];
Packit e9ba0d
		event_del(&ctl->timeout_event); /* Internal; doesn't count */
Packit e9ba0d
		event_debug_unassign(&ctl->timeout_event);
Packit e9ba0d
		for (ev = TAILQ_FIRST(&ctl->events); ev; ) {
Packit e9ba0d
			struct event *next = TAILQ_NEXT(ev,
Packit e9ba0d
			    ev_timeout_pos.ev_next_with_common_timeout);
Packit e9ba0d
			if (!(ev->ev_flags & EVLIST_INTERNAL)) {
Packit e9ba0d
				event_del(ev);
Packit e9ba0d
				++n_deleted;
Packit e9ba0d
			}
Packit e9ba0d
			ev = next;
Packit e9ba0d
		}
Packit e9ba0d
		mm_free(ctl);
Packit e9ba0d
	}
Packit e9ba0d
	if (base->common_timeout_queues)
Packit e9ba0d
		mm_free(base->common_timeout_queues);
Packit e9ba0d
Packit e9ba0d
	for (i = 0; i < base->nactivequeues; ++i) {
Packit e9ba0d
		for (ev = TAILQ_FIRST(&base->activequeues[i]); ev; ) {
Packit e9ba0d
			struct event *next = TAILQ_NEXT(ev, ev_active_next);
Packit e9ba0d
			if (!(ev->ev_flags & EVLIST_INTERNAL)) {
Packit e9ba0d
				event_del(ev);
Packit e9ba0d
				++n_deleted;
Packit e9ba0d
			}
Packit e9ba0d
			ev = next;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (n_deleted)
Packit e9ba0d
		event_debug(("%s: %d events were still set in base",
Packit e9ba0d
			__func__, n_deleted));
Packit e9ba0d
Packit e9ba0d
	if (base->evsel != NULL && base->evsel->dealloc != NULL)
Packit e9ba0d
		base->evsel->dealloc(base);
Packit e9ba0d
Packit e9ba0d
	for (i = 0; i < base->nactivequeues; ++i)
Packit e9ba0d
		EVUTIL_ASSERT(TAILQ_EMPTY(&base->activequeues[i]));
Packit e9ba0d
Packit e9ba0d
	EVUTIL_ASSERT(min_heap_empty(&base->timeheap));
Packit e9ba0d
	min_heap_dtor(&base->timeheap);
Packit e9ba0d
Packit e9ba0d
	mm_free(base->activequeues);
Packit e9ba0d
Packit e9ba0d
	EVUTIL_ASSERT(TAILQ_EMPTY(&base->eventqueue));
Packit e9ba0d
Packit e9ba0d
	evmap_io_clear(&base->io);
Packit e9ba0d
	evmap_signal_clear(&base->sigmap);
Packit e9ba0d
	event_changelist_freemem(&base->changelist);
Packit e9ba0d
Packit e9ba0d
	EVTHREAD_FREE_LOCK(base->th_base_lock, EVTHREAD_LOCKTYPE_RECURSIVE);
Packit e9ba0d
	EVTHREAD_FREE_COND(base->current_event_cond);
Packit e9ba0d
Packit e9ba0d
	mm_free(base);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* reinitialize the event base after a fork */
Packit e9ba0d
int
Packit e9ba0d
event_reinit(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	const struct eventop *evsel;
Packit e9ba0d
	int res = 0;
Packit e9ba0d
	struct event *ev;
Packit e9ba0d
	int was_notifiable = 0;
Packit e9ba0d
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	evsel = base->evsel;
Packit e9ba0d
Packit e9ba0d
#if 0
Packit e9ba0d
	/* Right now, reinit always takes effect, since even if the
Packit e9ba0d
	   backend doesn't require it, the signal socketpair code does.
Packit e9ba0d
Packit e9ba0d
	   XXX
Packit e9ba0d
	 */
Packit e9ba0d
	/* check if this event mechanism requires reinit */
Packit e9ba0d
	if (!evsel->need_reinit)
Packit e9ba0d
		goto done;
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
	/* prevent internal delete */
Packit e9ba0d
	if (base->sig.ev_signal_added) {
Packit e9ba0d
		/* we cannot call event_del here because the base has
Packit e9ba0d
		 * not been reinitialized yet. */
Packit e9ba0d
		event_queue_remove(base, &base->sig.ev_signal,
Packit e9ba0d
		    EVLIST_INSERTED);
Packit e9ba0d
		if (base->sig.ev_signal.ev_flags & EVLIST_ACTIVE)
Packit e9ba0d
			event_queue_remove(base, &base->sig.ev_signal,
Packit e9ba0d
			    EVLIST_ACTIVE);
Packit e9ba0d
		if (base->sig.ev_signal_pair[0] != -1)
Packit e9ba0d
			EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
Packit e9ba0d
		if (base->sig.ev_signal_pair[1] != -1)
Packit e9ba0d
			EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]);
Packit e9ba0d
		base->sig.ev_signal_added = 0;
Packit e9ba0d
	}
Packit e9ba0d
	if (base->th_notify_fd[0] != -1) {
Packit e9ba0d
		/* we cannot call event_del here because the base has
Packit e9ba0d
		 * not been reinitialized yet. */
Packit e9ba0d
		was_notifiable = 1;
Packit e9ba0d
		event_queue_remove(base, &base->th_notify,
Packit e9ba0d
		    EVLIST_INSERTED);
Packit e9ba0d
		if (base->th_notify.ev_flags & EVLIST_ACTIVE)
Packit e9ba0d
			event_queue_remove(base, &base->th_notify,
Packit e9ba0d
			    EVLIST_ACTIVE);
Packit e9ba0d
		base->sig.ev_signal_added = 0;
Packit e9ba0d
		EVUTIL_CLOSESOCKET(base->th_notify_fd[0]);
Packit e9ba0d
		if (base->th_notify_fd[1] != -1)
Packit e9ba0d
			EVUTIL_CLOSESOCKET(base->th_notify_fd[1]);
Packit e9ba0d
		base->th_notify_fd[0] = -1;
Packit e9ba0d
		base->th_notify_fd[1] = -1;
Packit e9ba0d
		event_debug_unassign(&base->th_notify);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (base->evsel->dealloc != NULL)
Packit e9ba0d
		base->evsel->dealloc(base);
Packit e9ba0d
	base->evbase = evsel->init(base);
Packit e9ba0d
	if (base->evbase == NULL) {
Packit e9ba0d
		event_errx(1, "%s: could not reinitialize event mechanism",
Packit e9ba0d
		    __func__);
Packit e9ba0d
		res = -1;
Packit e9ba0d
		goto done;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	event_changelist_freemem(&base->changelist); /* XXX */
Packit e9ba0d
	evmap_io_clear(&base->io);
Packit e9ba0d
	evmap_signal_clear(&base->sigmap);
Packit e9ba0d
Packit e9ba0d
	TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
Packit e9ba0d
		if (ev->ev_events & (EV_READ|EV_WRITE)) {
Packit e9ba0d
			if (ev == &base->sig.ev_signal) {
Packit e9ba0d
				/* If we run into the ev_signal event, it's only
Packit e9ba0d
				 * in eventqueue because some signal event was
Packit e9ba0d
				 * added, which made evsig_add re-add ev_signal.
Packit e9ba0d
				 * So don't double-add it. */
Packit e9ba0d
				continue;
Packit e9ba0d
			}
Packit e9ba0d
			if (evmap_io_add(base, ev->ev_fd, ev) == -1)
Packit e9ba0d
				res = -1;
Packit e9ba0d
		} else if (ev->ev_events & EV_SIGNAL) {
Packit e9ba0d
			if (evmap_signal_add(base, (int)ev->ev_fd, ev) == -1)
Packit e9ba0d
				res = -1;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (was_notifiable && res == 0)
Packit e9ba0d
		res = evthread_make_base_notifiable(base);
Packit e9ba0d
Packit e9ba0d
done:
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
	return (res);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
const char **
Packit e9ba0d
event_get_supported_methods(void)
Packit e9ba0d
{
Packit e9ba0d
	static const char **methods = NULL;
Packit e9ba0d
	const struct eventop **method;
Packit e9ba0d
	const char **tmp;
Packit e9ba0d
	int i = 0, k;
Packit e9ba0d
Packit e9ba0d
	/* count all methods */
Packit e9ba0d
	for (method = &eventops[0]; *method != NULL; ++method) {
Packit e9ba0d
		++i;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	/* allocate one more than we need for the NULL pointer */
Packit e9ba0d
	tmp = mm_calloc((i + 1), sizeof(char *));
Packit e9ba0d
	if (tmp == NULL)
Packit e9ba0d
		return (NULL);
Packit e9ba0d
Packit e9ba0d
	/* populate the array with the supported methods */
Packit e9ba0d
	for (k = 0, i = 0; eventops[k] != NULL; ++k) {
Packit e9ba0d
		tmp[i++] = eventops[k]->name;
Packit e9ba0d
	}
Packit e9ba0d
	tmp[i] = NULL;
Packit e9ba0d
Packit e9ba0d
	if (methods != NULL)
Packit e9ba0d
		mm_free((char**)methods);
Packit e9ba0d
Packit e9ba0d
	methods = tmp;
Packit e9ba0d
Packit e9ba0d
	return (methods);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
struct event_config *
Packit e9ba0d
event_config_new(void)
Packit e9ba0d
{
Packit e9ba0d
	struct event_config *cfg = mm_calloc(1, sizeof(*cfg));
Packit e9ba0d
Packit e9ba0d
	if (cfg == NULL)
Packit e9ba0d
		return (NULL);
Packit e9ba0d
Packit e9ba0d
	TAILQ_INIT(&cfg->entries);
Packit e9ba0d
Packit e9ba0d
	return (cfg);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
event_config_entry_free(struct event_config_entry *entry)
Packit e9ba0d
{
Packit e9ba0d
	if (entry->avoid_method != NULL)
Packit e9ba0d
		mm_free((char *)entry->avoid_method);
Packit e9ba0d
	mm_free(entry);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_config_free(struct event_config *cfg)
Packit e9ba0d
{
Packit e9ba0d
	struct event_config_entry *entry;
Packit e9ba0d
Packit e9ba0d
	while ((entry = TAILQ_FIRST(&cfg->entries)) != NULL) {
Packit e9ba0d
		TAILQ_REMOVE(&cfg->entries, entry, next);
Packit e9ba0d
		event_config_entry_free(entry);
Packit e9ba0d
	}
Packit e9ba0d
	mm_free(cfg);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_config_set_flag(struct event_config *cfg, int flag)
Packit e9ba0d
{
Packit e9ba0d
	if (!cfg)
Packit e9ba0d
		return -1;
Packit e9ba0d
	cfg->flags |= flag;
Packit e9ba0d
	return 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_config_avoid_method(struct event_config *cfg, const char *method)
Packit e9ba0d
{
Packit e9ba0d
	struct event_config_entry *entry = mm_malloc(sizeof(*entry));
Packit e9ba0d
	if (entry == NULL)
Packit e9ba0d
		return (-1);
Packit e9ba0d
Packit e9ba0d
	if ((entry->avoid_method = mm_strdup(method)) == NULL) {
Packit e9ba0d
		mm_free(entry);
Packit e9ba0d
		return (-1);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	TAILQ_INSERT_TAIL(&cfg->entries, entry, next);
Packit e9ba0d
Packit e9ba0d
	return (0);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_config_require_features(struct event_config *cfg,
Packit e9ba0d
    int features)
Packit e9ba0d
{
Packit e9ba0d
	if (!cfg)
Packit e9ba0d
		return (-1);
Packit e9ba0d
	cfg->require_features = features;
Packit e9ba0d
	return (0);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)
Packit e9ba0d
{
Packit e9ba0d
	if (!cfg)
Packit e9ba0d
		return (-1);
Packit e9ba0d
	cfg->n_cpus_hint = cpus;
Packit e9ba0d
	return (0);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_priority_init(int npriorities)
Packit e9ba0d
{
Packit e9ba0d
	return event_base_priority_init(current_base, npriorities);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_base_priority_init(struct event_base *base, int npriorities)
Packit e9ba0d
{
Packit e9ba0d
	int i;
Packit e9ba0d
Packit e9ba0d
	if (N_ACTIVE_CALLBACKS(base) || npriorities < 1
Packit e9ba0d
	    || npriorities >= EVENT_MAX_PRIORITIES)
Packit e9ba0d
		return (-1);
Packit e9ba0d
Packit e9ba0d
	if (npriorities == base->nactivequeues)
Packit e9ba0d
		return (0);
Packit e9ba0d
Packit e9ba0d
	if (base->nactivequeues) {
Packit e9ba0d
		mm_free(base->activequeues);
Packit e9ba0d
		base->nactivequeues = 0;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	/* Allocate our priority queues */
Packit e9ba0d
	base->activequeues = (struct event_list *)
Packit e9ba0d
	  mm_calloc(npriorities, sizeof(struct event_list));
Packit e9ba0d
	if (base->activequeues == NULL) {
Packit e9ba0d
		event_warn("%s: calloc", __func__);
Packit e9ba0d
		return (-1);
Packit e9ba0d
	}
Packit e9ba0d
	base->nactivequeues = npriorities;
Packit e9ba0d
Packit e9ba0d
	for (i = 0; i < base->nactivequeues; ++i) {
Packit e9ba0d
		TAILQ_INIT(&base->activequeues[i]);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	return (0);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Returns true iff we're currently watching any events. */
Packit e9ba0d
static int
Packit e9ba0d
event_haveevents(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	/* Caller must hold th_base_lock */
Packit e9ba0d
	return (base->virtual_event_count > 0 || base->event_count > 0);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* "closure" function called when processing active signal events */
Packit e9ba0d
static inline void
Packit e9ba0d
event_signal_closure(struct event_base *base, struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	short ncalls;
Packit e9ba0d
	int should_break;
Packit e9ba0d
Packit e9ba0d
	/* Allows deletes to work */
Packit e9ba0d
	ncalls = ev->ev_ncalls;
Packit e9ba0d
	if (ncalls != 0)
Packit e9ba0d
		ev->ev_pncalls = &ncalls;
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
	while (ncalls) {
Packit e9ba0d
		ncalls--;
Packit e9ba0d
		ev->ev_ncalls = ncalls;
Packit e9ba0d
		if (ncalls == 0)
Packit e9ba0d
			ev->ev_pncalls = NULL;
Packit e9ba0d
		(*ev->ev_callback)(ev->ev_fd, ev->ev_res, ev->ev_arg);
Packit e9ba0d
Packit e9ba0d
		EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
		should_break = base->event_break;
Packit e9ba0d
		EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
		if (should_break) {
Packit e9ba0d
			if (ncalls != 0)
Packit e9ba0d
				ev->ev_pncalls = NULL;
Packit e9ba0d
			return;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Common timeouts are special timeouts that are handled as queues rather than
Packit e9ba0d
 * in the minheap.  This is more efficient than the minheap if we happen to
Packit e9ba0d
 * know that we're going to get several thousands of timeout events all with
Packit e9ba0d
 * the same timeout value.
Packit e9ba0d
 *
Packit e9ba0d
 * Since all our timeout handling code assumes timevals can be copied,
Packit e9ba0d
 * assigned, etc, we can't use "magic pointer" to encode these common
Packit e9ba0d
 * timeouts.  Searching through a list to see if every timeout is common could
Packit e9ba0d
 * also get inefficient.  Instead, we take advantage of the fact that tv_usec
Packit e9ba0d
 * is 32 bits long, but only uses 20 of those bits (since it can never be over
Packit e9ba0d
 * 999999.)  We use the top bits to encode 4 bites of magic number, and 8 bits
Packit e9ba0d
 * of index into the event_base's aray of common timeouts.
Packit e9ba0d
 */
Packit e9ba0d
Packit e9ba0d
#define MICROSECONDS_MASK       COMMON_TIMEOUT_MICROSECONDS_MASK
Packit e9ba0d
#define COMMON_TIMEOUT_IDX_MASK 0x0ff00000
Packit e9ba0d
#define COMMON_TIMEOUT_IDX_SHIFT 20
Packit e9ba0d
#define COMMON_TIMEOUT_MASK     0xf0000000
Packit e9ba0d
#define COMMON_TIMEOUT_MAGIC    0x50000000
Packit e9ba0d
Packit e9ba0d
#define COMMON_TIMEOUT_IDX(tv) \
Packit e9ba0d
	(((tv)->tv_usec & COMMON_TIMEOUT_IDX_MASK)>>COMMON_TIMEOUT_IDX_SHIFT)
Packit e9ba0d
Packit e9ba0d
/** Return true iff if 'tv' is a common timeout in 'base' */
Packit e9ba0d
static inline int
Packit e9ba0d
is_common_timeout(const struct timeval *tv,
Packit e9ba0d
    const struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	int idx;
Packit e9ba0d
	if ((tv->tv_usec & COMMON_TIMEOUT_MASK) != COMMON_TIMEOUT_MAGIC)
Packit e9ba0d
		return 0;
Packit e9ba0d
	idx = COMMON_TIMEOUT_IDX(tv);
Packit e9ba0d
	return idx < base->n_common_timeouts;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* True iff tv1 and tv2 have the same common-timeout index, or if neither
Packit e9ba0d
 * one is a common timeout. */
Packit e9ba0d
static inline int
Packit e9ba0d
is_same_common_timeout(const struct timeval *tv1, const struct timeval *tv2)
Packit e9ba0d
{
Packit e9ba0d
	return (tv1->tv_usec & ~MICROSECONDS_MASK) ==
Packit e9ba0d
	    (tv2->tv_usec & ~MICROSECONDS_MASK);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/** Requires that 'tv' is a common timeout.  Return the corresponding
Packit e9ba0d
 * common_timeout_list. */
Packit e9ba0d
static inline struct common_timeout_list *
Packit e9ba0d
get_common_timeout_list(struct event_base *base, const struct timeval *tv)
Packit e9ba0d
{
Packit e9ba0d
	return base->common_timeout_queues[COMMON_TIMEOUT_IDX(tv)];
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
#if 0
Packit e9ba0d
static inline int
Packit e9ba0d
common_timeout_ok(const struct timeval *tv,
Packit e9ba0d
    struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	const struct timeval *expect =
Packit e9ba0d
	    &get_common_timeout_list(base, tv)->duration;
Packit e9ba0d
	return tv->tv_sec == expect->tv_sec &&
Packit e9ba0d
	    tv->tv_usec == expect->tv_usec;
Packit e9ba0d
}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
/* Add the timeout for the first event in given common timeout list to the
Packit e9ba0d
 * event_base's minheap. */
Packit e9ba0d
static void
Packit e9ba0d
common_timeout_schedule(struct common_timeout_list *ctl,
Packit e9ba0d
    const struct timeval *now, struct event *head)
Packit e9ba0d
{
Packit e9ba0d
	struct timeval timeout = head->ev_timeout;
Packit e9ba0d
	timeout.tv_usec &= MICROSECONDS_MASK;
Packit e9ba0d
	event_add_internal(&ctl->timeout_event, &timeout, 1);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Callback: invoked when the timeout for a common timeout queue triggers.
Packit e9ba0d
 * This means that (at least) the first event in that queue should be run,
Packit e9ba0d
 * and the timeout should be rescheduled if there are more events. */
Packit e9ba0d
static void
Packit e9ba0d
common_timeout_callback(evutil_socket_t fd, short what, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	struct timeval now;
Packit e9ba0d
	struct common_timeout_list *ctl = arg;
Packit e9ba0d
	struct event_base *base = ctl->base;
Packit e9ba0d
	struct event *ev = NULL;
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
	gettime(base, &now;;
Packit e9ba0d
	while (1) {
Packit e9ba0d
		ev = TAILQ_FIRST(&ctl->events);
Packit e9ba0d
		if (!ev || ev->ev_timeout.tv_sec > now.tv_sec ||
Packit e9ba0d
		    (ev->ev_timeout.tv_sec == now.tv_sec &&
Packit e9ba0d
			(ev->ev_timeout.tv_usec&MICROSECONDS_MASK) > now.tv_usec))
Packit e9ba0d
			break;
Packit e9ba0d
		event_del_internal(ev);
Packit e9ba0d
		event_active_nolock(ev, EV_TIMEOUT, 1);
Packit e9ba0d
	}
Packit e9ba0d
	if (ev)
Packit e9ba0d
		common_timeout_schedule(ctl, &now, ev);
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
#define MAX_COMMON_TIMEOUTS 256
Packit e9ba0d
Packit e9ba0d
const struct timeval *
Packit e9ba0d
event_base_init_common_timeout(struct event_base *base,
Packit e9ba0d
    const struct timeval *duration)
Packit e9ba0d
{
Packit e9ba0d
	int i;
Packit e9ba0d
	struct timeval tv;
Packit e9ba0d
	const struct timeval *result=NULL;
Packit e9ba0d
	struct common_timeout_list *new_ctl;
Packit e9ba0d
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
	if (duration->tv_usec > 1000000) {
Packit e9ba0d
		memcpy(&tv, duration, sizeof(struct timeval));
Packit e9ba0d
		if (is_common_timeout(duration, base))
Packit e9ba0d
			tv.tv_usec &= MICROSECONDS_MASK;
Packit e9ba0d
		tv.tv_sec += tv.tv_usec / 1000000;
Packit e9ba0d
		tv.tv_usec %= 1000000;
Packit e9ba0d
		duration = &tv;
Packit e9ba0d
	}
Packit e9ba0d
	for (i = 0; i < base->n_common_timeouts; ++i) {
Packit e9ba0d
		const struct common_timeout_list *ctl =
Packit e9ba0d
		    base->common_timeout_queues[i];
Packit e9ba0d
		if (duration->tv_sec == ctl->duration.tv_sec &&
Packit e9ba0d
		    duration->tv_usec ==
Packit e9ba0d
		    (ctl->duration.tv_usec & MICROSECONDS_MASK)) {
Packit e9ba0d
			EVUTIL_ASSERT(is_common_timeout(&ctl->duration, base));
Packit e9ba0d
			result = &ctl->duration;
Packit e9ba0d
			goto done;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
	if (base->n_common_timeouts == MAX_COMMON_TIMEOUTS) {
Packit e9ba0d
		event_warnx("%s: Too many common timeouts already in use; "
Packit e9ba0d
		    "we only support %d per event_base", __func__,
Packit e9ba0d
		    MAX_COMMON_TIMEOUTS);
Packit e9ba0d
		goto done;
Packit e9ba0d
	}
Packit e9ba0d
	if (base->n_common_timeouts_allocated == base->n_common_timeouts) {
Packit e9ba0d
		int n = base->n_common_timeouts < 16 ? 16 :
Packit e9ba0d
		    base->n_common_timeouts*2;
Packit e9ba0d
		struct common_timeout_list **newqueues =
Packit e9ba0d
		    mm_realloc(base->common_timeout_queues,
Packit e9ba0d
			n*sizeof(struct common_timeout_queue *));
Packit e9ba0d
		if (!newqueues) {
Packit e9ba0d
			event_warn("%s: realloc",__func__);
Packit e9ba0d
			goto done;
Packit e9ba0d
		}
Packit e9ba0d
		base->n_common_timeouts_allocated = n;
Packit e9ba0d
		base->common_timeout_queues = newqueues;
Packit e9ba0d
	}
Packit e9ba0d
	new_ctl = mm_calloc(1, sizeof(struct common_timeout_list));
Packit e9ba0d
	if (!new_ctl) {
Packit e9ba0d
		event_warn("%s: calloc",__func__);
Packit e9ba0d
		goto done;
Packit e9ba0d
	}
Packit e9ba0d
	TAILQ_INIT(&new_ctl->events);
Packit e9ba0d
	new_ctl->duration.tv_sec = duration->tv_sec;
Packit e9ba0d
	new_ctl->duration.tv_usec =
Packit e9ba0d
	    duration->tv_usec | COMMON_TIMEOUT_MAGIC |
Packit e9ba0d
	    (base->n_common_timeouts << COMMON_TIMEOUT_IDX_SHIFT);
Packit e9ba0d
	evtimer_assign(&new_ctl->timeout_event, base,
Packit e9ba0d
	    common_timeout_callback, new_ctl);
Packit e9ba0d
	new_ctl->timeout_event.ev_flags |= EVLIST_INTERNAL;
Packit e9ba0d
	event_priority_set(&new_ctl->timeout_event, 0);
Packit e9ba0d
	new_ctl->base = base;
Packit e9ba0d
	base->common_timeout_queues[base->n_common_timeouts++] = new_ctl;
Packit e9ba0d
	result = &new_ctl->duration;
Packit e9ba0d
Packit e9ba0d
done:
Packit e9ba0d
	if (result)
Packit e9ba0d
		EVUTIL_ASSERT(is_common_timeout(result, base));
Packit e9ba0d
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
	return result;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Closure function invoked when we're activating a persistent event. */
Packit e9ba0d
static inline void
Packit e9ba0d
event_persist_closure(struct event_base *base, struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	// Define our callback, we use this to store our callback before it's executed
Packit e9ba0d
	void (*evcb_callback)(evutil_socket_t, short, void *);
Packit e9ba0d
Packit e9ba0d
        // Other fields of *ev that must be stored before executing
Packit e9ba0d
        evutil_socket_t evcb_fd;
Packit e9ba0d
        short evcb_res;
Packit e9ba0d
        void *evcb_arg;
Packit e9ba0d
Packit e9ba0d
	/* reschedule the persistent event if we have a timeout. */
Packit e9ba0d
	if (ev->ev_io_timeout.tv_sec || ev->ev_io_timeout.tv_usec) {
Packit e9ba0d
		/* If there was a timeout, we want it to run at an interval of
Packit e9ba0d
		 * ev_io_timeout after the last time it was _scheduled_ for,
Packit e9ba0d
		 * not ev_io_timeout after _now_.  If it fired for another
Packit e9ba0d
		 * reason, though, the timeout ought to start ticking _now_. */
Packit e9ba0d
		struct timeval run_at, relative_to, delay, now;
Packit e9ba0d
		ev_uint32_t usec_mask = 0;
Packit e9ba0d
		EVUTIL_ASSERT(is_same_common_timeout(&ev->ev_timeout,
Packit e9ba0d
			&ev->ev_io_timeout));
Packit e9ba0d
		gettime(base, &now;;
Packit e9ba0d
		if (is_common_timeout(&ev->ev_timeout, base)) {
Packit e9ba0d
			delay = ev->ev_io_timeout;
Packit e9ba0d
			usec_mask = delay.tv_usec & ~MICROSECONDS_MASK;
Packit e9ba0d
			delay.tv_usec &= MICROSECONDS_MASK;
Packit e9ba0d
			if (ev->ev_res & EV_TIMEOUT) {
Packit e9ba0d
				relative_to = ev->ev_timeout;
Packit e9ba0d
				relative_to.tv_usec &= MICROSECONDS_MASK;
Packit e9ba0d
			} else {
Packit e9ba0d
				relative_to = now;
Packit e9ba0d
			}
Packit e9ba0d
		} else {
Packit e9ba0d
			delay = ev->ev_io_timeout;
Packit e9ba0d
			if (ev->ev_res & EV_TIMEOUT) {
Packit e9ba0d
				relative_to = ev->ev_timeout;
Packit e9ba0d
			} else {
Packit e9ba0d
				relative_to = now;
Packit e9ba0d
			}
Packit e9ba0d
		}
Packit e9ba0d
		evutil_timeradd(&relative_to, &delay, &run_at);
Packit e9ba0d
		if (evutil_timercmp(&run_at, &now, <)) {
Packit e9ba0d
			/* Looks like we missed at least one invocation due to
Packit e9ba0d
			 * a clock jump, not running the event loop for a
Packit e9ba0d
			 * while, really slow callbacks, or
Packit e9ba0d
			 * something. Reschedule relative to now.
Packit e9ba0d
			 */
Packit e9ba0d
			evutil_timeradd(&now, &delay, &run_at);
Packit e9ba0d
		}
Packit e9ba0d
		run_at.tv_usec |= usec_mask;
Packit e9ba0d
		event_add_internal(ev, &run_at, 1);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	// Save our callback before we release the lock
Packit e9ba0d
	evcb_callback = ev->ev_callback;
Packit e9ba0d
        evcb_fd = ev->ev_fd;
Packit e9ba0d
        evcb_res = ev->ev_res;
Packit e9ba0d
        evcb_arg = ev->ev_arg;
Packit e9ba0d
Packit e9ba0d
	// Release the lock
Packit e9ba0d
 	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	// Execute the callback
Packit e9ba0d
        (evcb_callback)(evcb_fd, evcb_res, evcb_arg);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/*
Packit e9ba0d
  Helper for event_process_active to process all the events in a single queue,
Packit e9ba0d
  releasing the lock as we go.  This function requires that the lock be held
Packit e9ba0d
  when it's invoked.  Returns -1 if we get a signal or an event_break that
Packit e9ba0d
  means we should stop processing any active events now.  Otherwise returns
Packit e9ba0d
  the number of non-internal events that we processed.
Packit e9ba0d
*/
Packit e9ba0d
static int
Packit e9ba0d
event_process_active_single_queue(struct event_base *base,
Packit e9ba0d
    struct event_list *activeq)
Packit e9ba0d
{
Packit e9ba0d
	struct event *ev;
Packit e9ba0d
	int count = 0;
Packit e9ba0d
Packit e9ba0d
	EVUTIL_ASSERT(activeq != NULL);
Packit e9ba0d
Packit e9ba0d
	for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
Packit e9ba0d
		if (ev->ev_events & EV_PERSIST)
Packit e9ba0d
			event_queue_remove(base, ev, EVLIST_ACTIVE);
Packit e9ba0d
		else
Packit e9ba0d
			event_del_internal(ev);
Packit e9ba0d
		if (!(ev->ev_flags & EVLIST_INTERNAL))
Packit e9ba0d
			++count;
Packit e9ba0d
Packit e9ba0d
		event_debug((
Packit e9ba0d
			 "event_process_active: event: %p, %s%scall %p",
Packit e9ba0d
			ev,
Packit e9ba0d
			ev->ev_res & EV_READ ? "EV_READ " : " ",
Packit e9ba0d
			ev->ev_res & EV_WRITE ? "EV_WRITE " : " ",
Packit e9ba0d
			ev->ev_callback));
Packit e9ba0d
Packit e9ba0d
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
Packit e9ba0d
		base->current_event = ev;
Packit e9ba0d
		base->current_event_waiters = 0;
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
		switch (ev->ev_closure) {
Packit e9ba0d
		case EV_CLOSURE_SIGNAL:
Packit e9ba0d
			event_signal_closure(base, ev);
Packit e9ba0d
			break;
Packit e9ba0d
		case EV_CLOSURE_PERSIST:
Packit e9ba0d
			event_persist_closure(base, ev);
Packit e9ba0d
			break;
Packit e9ba0d
		default:
Packit e9ba0d
		case EV_CLOSURE_NONE:
Packit e9ba0d
			EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
			(*ev->ev_callback)(
Packit e9ba0d
				ev->ev_fd, ev->ev_res, ev->ev_arg);
Packit e9ba0d
			break;
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
Packit e9ba0d
		base->current_event = NULL;
Packit e9ba0d
		if (base->current_event_waiters) {
Packit e9ba0d
			base->current_event_waiters = 0;
Packit e9ba0d
			EVTHREAD_COND_BROADCAST(base->current_event_cond);
Packit e9ba0d
		}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
		if (base->event_break)
Packit e9ba0d
			return -1;
Packit e9ba0d
		if (base->event_continue)
Packit e9ba0d
			break;
Packit e9ba0d
	}
Packit e9ba0d
	return count;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/*
Packit e9ba0d
   Process up to MAX_DEFERRED of the defered_cb entries in 'queue'.  If
Packit e9ba0d
   *breakptr becomes set to 1, stop.  Requires that we start out holding
Packit e9ba0d
   the lock on 'queue'; releases the lock around 'queue' for each deferred_cb
Packit e9ba0d
   we process.
Packit e9ba0d
 */
Packit e9ba0d
static int
Packit e9ba0d
event_process_deferred_callbacks(struct deferred_cb_queue *queue, int *breakptr)
Packit e9ba0d
{
Packit e9ba0d
	int count = 0;
Packit e9ba0d
	struct deferred_cb *cb;
Packit e9ba0d
Packit e9ba0d
#define MAX_DEFERRED 16
Packit e9ba0d
	while ((cb = TAILQ_FIRST(&queue->deferred_cb_list))) {
Packit e9ba0d
		cb->queued = 0;
Packit e9ba0d
		TAILQ_REMOVE(&queue->deferred_cb_list, cb, cb_next);
Packit e9ba0d
		--queue->active_count;
Packit e9ba0d
		UNLOCK_DEFERRED_QUEUE(queue);
Packit e9ba0d
Packit e9ba0d
		cb->cb(cb, cb->arg);
Packit e9ba0d
Packit e9ba0d
		LOCK_DEFERRED_QUEUE(queue);
Packit e9ba0d
		if (*breakptr)
Packit e9ba0d
			return -1;
Packit e9ba0d
		if (++count == MAX_DEFERRED)
Packit e9ba0d
			break;
Packit e9ba0d
	}
Packit e9ba0d
#undef MAX_DEFERRED
Packit e9ba0d
	return count;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/*
Packit e9ba0d
 * Active events are stored in priority queues.  Lower priorities are always
Packit e9ba0d
 * process before higher priorities.  Low priority events can starve high
Packit e9ba0d
 * priority ones.
Packit e9ba0d
 */
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
event_process_active(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	/* Caller must hold th_base_lock */
Packit e9ba0d
	struct event_list *activeq = NULL;
Packit e9ba0d
	int i, c = 0;
Packit e9ba0d
Packit e9ba0d
	for (i = 0; i < base->nactivequeues; ++i) {
Packit e9ba0d
		if (TAILQ_FIRST(&base->activequeues[i]) != NULL) {
Packit e9ba0d
			base->event_running_priority = i;
Packit e9ba0d
			activeq = &base->activequeues[i];
Packit e9ba0d
			c = event_process_active_single_queue(base, activeq);
Packit e9ba0d
			if (c < 0) {
Packit e9ba0d
				base->event_running_priority = -1;
Packit e9ba0d
				return -1;
Packit e9ba0d
			} else if (c > 0)
Packit e9ba0d
				break; /* Processed a real event; do not
Packit e9ba0d
					* consider lower-priority events */
Packit e9ba0d
			/* If we get here, all of the events we processed
Packit e9ba0d
			 * were internal.  Continue. */
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	event_process_deferred_callbacks(&base->defer_queue,&base->event_break);
Packit e9ba0d
	base->event_running_priority = -1;
Packit e9ba0d
	return c;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/*
Packit e9ba0d
 * Wait continuously for events.  We exit only if no events are left.
Packit e9ba0d
 */
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_dispatch(void)
Packit e9ba0d
{
Packit e9ba0d
	return (event_loop(0));
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_base_dispatch(struct event_base *event_base)
Packit e9ba0d
{
Packit e9ba0d
	return (event_base_loop(event_base, 0));
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
const char *
Packit e9ba0d
event_base_get_method(const struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	EVUTIL_ASSERT(base);
Packit e9ba0d
	return (base->evsel->name);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/** Callback: used to implement event_base_loopexit by telling the event_base
Packit e9ba0d
 * that it's time to exit its loop. */
Packit e9ba0d
static void
Packit e9ba0d
event_loopexit_cb(evutil_socket_t fd, short what, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	struct event_base *base = arg;
Packit e9ba0d
	base->event_gotterm = 1;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_loopexit(const struct timeval *tv)
Packit e9ba0d
{
Packit e9ba0d
	return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
Packit e9ba0d
		    current_base, tv));
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_base_loopexit(struct event_base *event_base, const struct timeval *tv)
Packit e9ba0d
{
Packit e9ba0d
	return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb,
Packit e9ba0d
		    event_base, tv));
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_loopbreak(void)
Packit e9ba0d
{
Packit e9ba0d
	return (event_base_loopbreak(current_base));
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_base_loopbreak(struct event_base *event_base)
Packit e9ba0d
{
Packit e9ba0d
	int r = 0;
Packit e9ba0d
	if (event_base == NULL)
Packit e9ba0d
		return (-1);
Packit e9ba0d
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(event_base, th_base_lock);
Packit e9ba0d
	event_base->event_break = 1;
Packit e9ba0d
Packit e9ba0d
	if (EVBASE_NEED_NOTIFY(event_base)) {
Packit e9ba0d
		r = evthread_notify_base(event_base);
Packit e9ba0d
	} else {
Packit e9ba0d
		r = (0);
Packit e9ba0d
	}
Packit e9ba0d
	EVBASE_RELEASE_LOCK(event_base, th_base_lock);
Packit e9ba0d
	return r;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_base_got_break(struct event_base *event_base)
Packit e9ba0d
{
Packit e9ba0d
	int res;
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(event_base, th_base_lock);
Packit e9ba0d
	res = event_base->event_break;
Packit e9ba0d
	EVBASE_RELEASE_LOCK(event_base, th_base_lock);
Packit e9ba0d
	return res;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_base_got_exit(struct event_base *event_base)
Packit e9ba0d
{
Packit e9ba0d
	int res;
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(event_base, th_base_lock);
Packit e9ba0d
	res = event_base->event_gotterm;
Packit e9ba0d
	EVBASE_RELEASE_LOCK(event_base, th_base_lock);
Packit e9ba0d
	return res;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* not thread safe */
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_loop(int flags)
Packit e9ba0d
{
Packit e9ba0d
	return event_base_loop(current_base, flags);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_base_loop(struct event_base *base, int flags)
Packit e9ba0d
{
Packit e9ba0d
	const struct eventop *evsel = base->evsel;
Packit e9ba0d
	struct timeval tv;
Packit e9ba0d
	struct timeval *tv_p;
Packit e9ba0d
	int res, done, retval = 0;
Packit e9ba0d
Packit e9ba0d
	/* Grab the lock.  We will release it inside evsel.dispatch, and again
Packit e9ba0d
	 * as we invoke user callbacks. */
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	if (base->running_loop) {
Packit e9ba0d
		event_warnx("%s: reentrant invocation.  Only one event_base_loop"
Packit e9ba0d
		    " can run on each event_base at once.", __func__);
Packit e9ba0d
		EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
		return -1;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	base->running_loop = 1;
Packit e9ba0d
Packit e9ba0d
	clear_time_cache(base);
Packit e9ba0d
Packit e9ba0d
	if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)
Packit e9ba0d
		evsig_set_base(base);
Packit e9ba0d
Packit e9ba0d
	done = 0;
Packit e9ba0d
Packit e9ba0d
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
Packit e9ba0d
	base->th_owner_id = EVTHREAD_GET_ID();
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
	base->event_gotterm = base->event_break = 0;
Packit e9ba0d
Packit e9ba0d
	while (!done) {
Packit e9ba0d
		base->event_continue = 0;
Packit e9ba0d
Packit e9ba0d
		/* Terminate the loop if we have been asked to */
Packit e9ba0d
		if (base->event_gotterm) {
Packit e9ba0d
			break;
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		if (base->event_break) {
Packit e9ba0d
			break;
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		timeout_correct(base, &tv;;
Packit e9ba0d
Packit e9ba0d
		tv_p = &tv;
Packit e9ba0d
		if (!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK)) {
Packit e9ba0d
			timeout_next(base, &tv_p);
Packit e9ba0d
		} else {
Packit e9ba0d
			/*
Packit e9ba0d
			 * if we have active events, we just poll new events
Packit e9ba0d
			 * without waiting.
Packit e9ba0d
			 */
Packit e9ba0d
			evutil_timerclear(&tv;;
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		/* If we have no events, we just exit */
Packit e9ba0d
		if (!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
Packit e9ba0d
			event_debug(("%s: no events registered.", __func__));
Packit e9ba0d
			retval = 1;
Packit e9ba0d
			goto done;
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		/* update last old time */
Packit e9ba0d
		gettime(base, &base->event_tv);
Packit e9ba0d
Packit e9ba0d
		clear_time_cache(base);
Packit e9ba0d
Packit e9ba0d
		res = evsel->dispatch(base, tv_p);
Packit e9ba0d
Packit e9ba0d
		if (res == -1) {
Packit e9ba0d
			event_debug(("%s: dispatch returned unsuccessfully.",
Packit e9ba0d
				__func__));
Packit e9ba0d
			retval = -1;
Packit e9ba0d
			goto done;
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		update_time_cache(base);
Packit e9ba0d
Packit e9ba0d
		timeout_process(base);
Packit e9ba0d
Packit e9ba0d
		if (N_ACTIVE_CALLBACKS(base)) {
Packit e9ba0d
			int n = event_process_active(base);
Packit e9ba0d
			if ((flags & EVLOOP_ONCE)
Packit e9ba0d
			    && N_ACTIVE_CALLBACKS(base) == 0
Packit e9ba0d
			    && n != 0)
Packit e9ba0d
				done = 1;
Packit e9ba0d
		} else if (flags & EVLOOP_NONBLOCK)
Packit e9ba0d
			done = 1;
Packit e9ba0d
	}
Packit e9ba0d
	event_debug(("%s: asked to terminate loop.", __func__));
Packit e9ba0d
Packit e9ba0d
done:
Packit e9ba0d
	clear_time_cache(base);
Packit e9ba0d
	base->running_loop = 0;
Packit e9ba0d
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	return (retval);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Sets up an event for processing once */
Packit e9ba0d
struct event_once {
Packit e9ba0d
	struct event ev;
Packit e9ba0d
Packit e9ba0d
	void (*cb)(evutil_socket_t, short, void *);
Packit e9ba0d
	void *arg;
Packit e9ba0d
};
Packit e9ba0d
Packit e9ba0d
/* One-time callback to implement event_base_once: invokes the user callback,
Packit e9ba0d
 * then deletes the allocated storage */
Packit e9ba0d
static void
Packit e9ba0d
event_once_cb(evutil_socket_t fd, short events, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	struct event_once *eonce = arg;
Packit e9ba0d
Packit e9ba0d
	(*eonce->cb)(fd, events, eonce->arg);
Packit e9ba0d
	event_debug_unassign(&eonce->ev);
Packit e9ba0d
	mm_free(eonce);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* not threadsafe, event scheduled once. */
Packit e9ba0d
int
Packit e9ba0d
event_once(evutil_socket_t fd, short events,
Packit e9ba0d
    void (*callback)(evutil_socket_t, short, void *),
Packit e9ba0d
    void *arg, const struct timeval *tv)
Packit e9ba0d
{
Packit e9ba0d
	return event_base_once(current_base, fd, events, callback, arg, tv);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Schedules an event once */
Packit e9ba0d
int
Packit e9ba0d
event_base_once(struct event_base *base, evutil_socket_t fd, short events,
Packit e9ba0d
    void (*callback)(evutil_socket_t, short, void *),
Packit e9ba0d
    void *arg, const struct timeval *tv)
Packit e9ba0d
{
Packit e9ba0d
	struct event_once *eonce;
Packit e9ba0d
	struct timeval etv;
Packit e9ba0d
	int res = 0;
Packit e9ba0d
Packit e9ba0d
	/* We cannot support signals that just fire once, or persistent
Packit e9ba0d
	 * events. */
Packit e9ba0d
	if (events & (EV_SIGNAL|EV_PERSIST))
Packit e9ba0d
		return (-1);
Packit e9ba0d
Packit e9ba0d
	if ((eonce = mm_calloc(1, sizeof(struct event_once))) == NULL)
Packit e9ba0d
		return (-1);
Packit e9ba0d
Packit e9ba0d
	eonce->cb = callback;
Packit e9ba0d
	eonce->arg = arg;
Packit e9ba0d
Packit e9ba0d
	if (events == EV_TIMEOUT) {
Packit e9ba0d
		if (tv == NULL) {
Packit e9ba0d
			evutil_timerclear(&etv;;
Packit e9ba0d
			tv = &etv;
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		evtimer_assign(&eonce->ev, base, event_once_cb, eonce);
Packit e9ba0d
	} else if (events & (EV_READ|EV_WRITE)) {
Packit e9ba0d
		events &= EV_READ|EV_WRITE;
Packit e9ba0d
Packit e9ba0d
		event_assign(&eonce->ev, base, fd, events, event_once_cb, eonce);
Packit e9ba0d
	} else {
Packit e9ba0d
		/* Bad event combination */
Packit e9ba0d
		mm_free(eonce);
Packit e9ba0d
		return (-1);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (res == 0)
Packit e9ba0d
		res = event_add(&eonce->ev, tv);
Packit e9ba0d
	if (res != 0) {
Packit e9ba0d
		mm_free(eonce);
Packit e9ba0d
		return (res);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	return (0);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
Packit e9ba0d
{
Packit e9ba0d
	if (!base)
Packit e9ba0d
		base = current_base;
Packit e9ba0d
Packit e9ba0d
	_event_debug_assert_not_added(ev);
Packit e9ba0d
Packit e9ba0d
	ev->ev_base = base;
Packit e9ba0d
Packit e9ba0d
	ev->ev_callback = callback;
Packit e9ba0d
	ev->ev_arg = arg;
Packit e9ba0d
	ev->ev_fd = fd;
Packit e9ba0d
	ev->ev_events = events;
Packit e9ba0d
	ev->ev_res = 0;
Packit e9ba0d
	ev->ev_flags = EVLIST_INIT;
Packit e9ba0d
	ev->ev_ncalls = 0;
Packit e9ba0d
	ev->ev_pncalls = NULL;
Packit e9ba0d
Packit e9ba0d
	if (events & EV_SIGNAL) {
Packit e9ba0d
		if ((events & (EV_READ|EV_WRITE)) != 0) {
Packit e9ba0d
			event_warnx("%s: EV_SIGNAL is not compatible with "
Packit e9ba0d
			    "EV_READ or EV_WRITE", __func__);
Packit e9ba0d
			return -1;
Packit e9ba0d
		}
Packit e9ba0d
		ev->ev_closure = EV_CLOSURE_SIGNAL;
Packit e9ba0d
	} else {
Packit e9ba0d
		if (events & EV_PERSIST) {
Packit e9ba0d
			evutil_timerclear(&ev->ev_io_timeout);
Packit e9ba0d
			ev->ev_closure = EV_CLOSURE_PERSIST;
Packit e9ba0d
		} else {
Packit e9ba0d
			ev->ev_closure = EV_CLOSURE_NONE;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	min_heap_elem_init(ev);
Packit e9ba0d
Packit e9ba0d
	if (base != NULL) {
Packit e9ba0d
		/* by default, we put new events into the middle priority */
Packit e9ba0d
		ev->ev_pri = base->nactivequeues / 2;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	_event_debug_note_setup(ev);
Packit e9ba0d
Packit e9ba0d
	return 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_base_set(struct event_base *base, struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	/* Only innocent events may be assigned to a different base */
Packit e9ba0d
	if (ev->ev_flags != EVLIST_INIT)
Packit e9ba0d
		return (-1);
Packit e9ba0d
Packit e9ba0d
	_event_debug_assert_is_setup(ev);
Packit e9ba0d
Packit e9ba0d
	ev->ev_base = base;
Packit e9ba0d
	ev->ev_pri = base->nactivequeues/2;
Packit e9ba0d
Packit e9ba0d
	return (0);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_set(struct event *ev, evutil_socket_t fd, short events,
Packit e9ba0d
	  void (*callback)(evutil_socket_t, short, void *), void *arg)
Packit e9ba0d
{
Packit e9ba0d
	int r;
Packit e9ba0d
	r = event_assign(ev, current_base, fd, events, callback, arg);
Packit e9ba0d
	EVUTIL_ASSERT(r == 0);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
struct event *
Packit e9ba0d
event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)
Packit e9ba0d
{
Packit e9ba0d
	struct event *ev;
Packit e9ba0d
	ev = mm_malloc(sizeof(struct event));
Packit e9ba0d
	if (ev == NULL)
Packit e9ba0d
		return (NULL);
Packit e9ba0d
	if (event_assign(ev, base, fd, events, cb, arg) < 0) {
Packit e9ba0d
		mm_free(ev);
Packit e9ba0d
		return (NULL);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	return (ev);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_free(struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	_event_debug_assert_is_setup(ev);
Packit e9ba0d
Packit e9ba0d
	/* make sure that this event won't be coming back to haunt us. */
Packit e9ba0d
	event_del(ev);
Packit e9ba0d
	_event_debug_note_teardown(ev);
Packit e9ba0d
	mm_free(ev);
Packit e9ba0d
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_debug_unassign(struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	_event_debug_assert_not_added(ev);
Packit e9ba0d
	_event_debug_note_teardown(ev);
Packit e9ba0d
Packit e9ba0d
	ev->ev_flags &= ~EVLIST_INIT;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/*
Packit e9ba0d
 * Set's the priority of an event - if an event is already scheduled
Packit e9ba0d
 * changing the priority is going to fail.
Packit e9ba0d
 */
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_priority_set(struct event *ev, int pri)
Packit e9ba0d
{
Packit e9ba0d
	_event_debug_assert_is_setup(ev);
Packit e9ba0d
Packit e9ba0d
	if (ev->ev_flags & EVLIST_ACTIVE)
Packit e9ba0d
		return (-1);
Packit e9ba0d
	if (pri < 0 || pri >= ev->ev_base->nactivequeues)
Packit e9ba0d
		return (-1);
Packit e9ba0d
Packit e9ba0d
	ev->ev_pri = pri;
Packit e9ba0d
Packit e9ba0d
	return (0);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/*
Packit e9ba0d
 * Checks if a specific event is pending or scheduled.
Packit e9ba0d
 */
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_pending(const struct event *ev, short event, struct timeval *tv)
Packit e9ba0d
{
Packit e9ba0d
	int flags = 0;
Packit e9ba0d
Packit e9ba0d
	if (EVUTIL_FAILURE_CHECK(ev->ev_base == NULL)) {
Packit e9ba0d
		event_warnx("%s: event has no event_base set.", __func__);
Packit e9ba0d
		return 0;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
Packit e9ba0d
	_event_debug_assert_is_setup(ev);
Packit e9ba0d
Packit e9ba0d
	if (ev->ev_flags & EVLIST_INSERTED)
Packit e9ba0d
		flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL));
Packit e9ba0d
	if (ev->ev_flags & EVLIST_ACTIVE)
Packit e9ba0d
		flags |= ev->ev_res;
Packit e9ba0d
	if (ev->ev_flags & EVLIST_TIMEOUT)
Packit e9ba0d
		flags |= EV_TIMEOUT;
Packit e9ba0d
Packit e9ba0d
	event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL);
Packit e9ba0d
Packit e9ba0d
	/* See if there is a timeout that we should report */
Packit e9ba0d
	if (tv != NULL && (flags & event & EV_TIMEOUT)) {
Packit e9ba0d
		struct timeval tmp = ev->ev_timeout;
Packit e9ba0d
		tmp.tv_usec &= MICROSECONDS_MASK;
Packit e9ba0d
#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
Packit e9ba0d
		/* correctly remamp to real time */
Packit e9ba0d
		evutil_timeradd(&ev->ev_base->tv_clock_diff, &tmp, tv);
Packit e9ba0d
#else
Packit e9ba0d
		*tv = tmp;
Packit e9ba0d
#endif
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	return (flags & event);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_initialized(const struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	if (!(ev->ev_flags & EVLIST_INIT))
Packit e9ba0d
		return 0;
Packit e9ba0d
Packit e9ba0d
	return 1;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_get_assignment(const struct event *event, struct event_base **base_out, evutil_socket_t *fd_out, short *events_out, event_callback_fn *callback_out, void **arg_out)
Packit e9ba0d
{
Packit e9ba0d
	_event_debug_assert_is_setup(event);
Packit e9ba0d
Packit e9ba0d
	if (base_out)
Packit e9ba0d
		*base_out = event->ev_base;
Packit e9ba0d
	if (fd_out)
Packit e9ba0d
		*fd_out = event->ev_fd;
Packit e9ba0d
	if (events_out)
Packit e9ba0d
		*events_out = event->ev_events;
Packit e9ba0d
	if (callback_out)
Packit e9ba0d
		*callback_out = event->ev_callback;
Packit e9ba0d
	if (arg_out)
Packit e9ba0d
		*arg_out = event->ev_arg;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
size_t
Packit e9ba0d
event_get_struct_event_size(void)
Packit e9ba0d
{
Packit e9ba0d
	return sizeof(struct event);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
evutil_socket_t
Packit e9ba0d
event_get_fd(const struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	_event_debug_assert_is_setup(ev);
Packit e9ba0d
	return ev->ev_fd;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
struct event_base *
Packit e9ba0d
event_get_base(const struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	_event_debug_assert_is_setup(ev);
Packit e9ba0d
	return ev->ev_base;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
short
Packit e9ba0d
event_get_events(const struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	_event_debug_assert_is_setup(ev);
Packit e9ba0d
	return ev->ev_events;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
event_callback_fn
Packit e9ba0d
event_get_callback(const struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	_event_debug_assert_is_setup(ev);
Packit e9ba0d
	return ev->ev_callback;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void *
Packit e9ba0d
event_get_callback_arg(const struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	_event_debug_assert_is_setup(ev);
Packit e9ba0d
	return ev->ev_arg;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_add(struct event *ev, const struct timeval *tv)
Packit e9ba0d
{
Packit e9ba0d
	int res;
Packit e9ba0d
Packit e9ba0d
	if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
Packit e9ba0d
		event_warnx("%s: event has no event_base set.", __func__);
Packit e9ba0d
		return -1;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	res = event_add_internal(ev, tv, 0);
Packit e9ba0d
Packit e9ba0d
	EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	return (res);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Helper callback: wake an event_base from another thread.  This version
Packit e9ba0d
 * works by writing a byte to one end of a socketpair, so that the event_base
Packit e9ba0d
 * listening on the other end will wake up as the corresponding event
Packit e9ba0d
 * triggers */
Packit e9ba0d
static int
Packit e9ba0d
evthread_notify_base_default(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	char buf[1];
Packit e9ba0d
	int r;
Packit e9ba0d
	buf[0] = (char) 0;
Packit e9ba0d
#ifdef WIN32
Packit e9ba0d
	r = send(base->th_notify_fd[1], buf, 1, 0);
Packit e9ba0d
#else
Packit e9ba0d
	r = write(base->th_notify_fd[1], buf, 1);
Packit e9ba0d
#endif
Packit e9ba0d
	return (r < 0 && errno != EAGAIN) ? -1 : 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
#if defined(_EVENT_HAVE_EVENTFD) && defined(_EVENT_HAVE_SYS_EVENTFD_H)
Packit e9ba0d
/* Helper callback: wake an event_base from another thread.  This version
Packit e9ba0d
 * assumes that you have a working eventfd() implementation. */
Packit e9ba0d
static int
Packit e9ba0d
evthread_notify_base_eventfd(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	ev_uint64_t msg = 1;
Packit e9ba0d
	int r;
Packit e9ba0d
	do {
Packit e9ba0d
		r = write(base->th_notify_fd[0], (void*) &msg, sizeof(msg));
Packit e9ba0d
	} while (r < 0 && errno == EAGAIN);
Packit e9ba0d
Packit e9ba0d
	return (r < 0) ? -1 : 0;
Packit e9ba0d
}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
/** Tell the thread currently running the event_loop for base (if any) that it
Packit e9ba0d
 * needs to stop waiting in its dispatch function (if it is) and process all
Packit e9ba0d
 * active events and deferred callbacks (if there are any).  */
Packit e9ba0d
static int
Packit e9ba0d
evthread_notify_base(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	EVENT_BASE_ASSERT_LOCKED(base);
Packit e9ba0d
	if (!base->th_notify_fn)
Packit e9ba0d
		return -1;
Packit e9ba0d
	if (base->is_notify_pending)
Packit e9ba0d
		return 0;
Packit e9ba0d
	base->is_notify_pending = 1;
Packit e9ba0d
	return base->th_notify_fn(base);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Implementation function to add an event.  Works just like event_add,
Packit e9ba0d
 * except: 1) it requires that we have the lock.  2) if tv_is_absolute is set,
Packit e9ba0d
 * we treat tv as an absolute time, not as an interval to add to the current
Packit e9ba0d
 * time */
Packit e9ba0d
static inline int
Packit e9ba0d
event_add_internal(struct event *ev, const struct timeval *tv,
Packit e9ba0d
    int tv_is_absolute)
Packit e9ba0d
{
Packit e9ba0d
	struct event_base *base = ev->ev_base;
Packit e9ba0d
	int res = 0;
Packit e9ba0d
	int notify = 0;
Packit e9ba0d
Packit e9ba0d
	EVENT_BASE_ASSERT_LOCKED(base);
Packit e9ba0d
	_event_debug_assert_is_setup(ev);
Packit e9ba0d
Packit e9ba0d
	event_debug((
Packit e9ba0d
		 "event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%scall %p",
Packit e9ba0d
		 ev,
Packit e9ba0d
		 EV_SOCK_ARG(ev->ev_fd),
Packit e9ba0d
		 ev->ev_events & EV_READ ? "EV_READ " : " ",
Packit e9ba0d
		 ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
Packit e9ba0d
		 tv ? "EV_TIMEOUT " : " ",
Packit e9ba0d
		 ev->ev_callback));
Packit e9ba0d
Packit e9ba0d
	EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
Packit e9ba0d
Packit e9ba0d
	/*
Packit e9ba0d
	 * prepare for timeout insertion further below, if we get a
Packit e9ba0d
	 * failure on any step, we should not change any state.
Packit e9ba0d
	 */
Packit e9ba0d
	if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
Packit e9ba0d
		if (min_heap_reserve(&base->timeheap,
Packit e9ba0d
			1 + min_heap_size(&base->timeheap)) == -1)
Packit e9ba0d
			return (-1);  /* ENOMEM == errno */
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	/* If the main thread is currently executing a signal event's
Packit e9ba0d
	 * callback, and we are not the main thread, then we want to wait
Packit e9ba0d
	 * until the callback is done before we mess with the event, or else
Packit e9ba0d
	 * we can race on ev_ncalls and ev_pncalls below. */
Packit e9ba0d
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
Packit e9ba0d
	if (base->current_event == ev && (ev->ev_events & EV_SIGNAL)
Packit e9ba0d
	    && !EVBASE_IN_THREAD(base)) {
Packit e9ba0d
		++base->current_event_waiters;
Packit e9ba0d
		EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
Packit e9ba0d
	}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
	if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
Packit e9ba0d
	    !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
Packit e9ba0d
		if (ev->ev_events & (EV_READ|EV_WRITE))
Packit e9ba0d
			res = evmap_io_add(base, ev->ev_fd, ev);
Packit e9ba0d
		else if (ev->ev_events & EV_SIGNAL)
Packit e9ba0d
			res = evmap_signal_add(base, (int)ev->ev_fd, ev);
Packit e9ba0d
		if (res != -1)
Packit e9ba0d
			event_queue_insert(base, ev, EVLIST_INSERTED);
Packit e9ba0d
		if (res == 1) {
Packit e9ba0d
			/* evmap says we need to notify the main thread. */
Packit e9ba0d
			notify = 1;
Packit e9ba0d
			res = 0;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	/*
Packit e9ba0d
	 * we should change the timeout state only if the previous event
Packit e9ba0d
	 * addition succeeded.
Packit e9ba0d
	 */
Packit e9ba0d
	if (res != -1 && tv != NULL) {
Packit e9ba0d
		struct timeval now;
Packit e9ba0d
		int common_timeout;
Packit e9ba0d
Packit e9ba0d
		/*
Packit e9ba0d
		 * for persistent timeout events, we remember the
Packit e9ba0d
		 * timeout value and re-add the event.
Packit e9ba0d
		 *
Packit e9ba0d
		 * If tv_is_absolute, this was already set.
Packit e9ba0d
		 */
Packit e9ba0d
		if (ev->ev_closure == EV_CLOSURE_PERSIST && !tv_is_absolute)
Packit e9ba0d
			ev->ev_io_timeout = *tv;
Packit e9ba0d
Packit e9ba0d
		/*
Packit e9ba0d
		 * we already reserved memory above for the case where we
Packit e9ba0d
		 * are not replacing an existing timeout.
Packit e9ba0d
		 */
Packit e9ba0d
		if (ev->ev_flags & EVLIST_TIMEOUT) {
Packit e9ba0d
			/* XXX I believe this is needless. */
Packit e9ba0d
			if (min_heap_elt_is_top(ev))
Packit e9ba0d
				notify = 1;
Packit e9ba0d
			event_queue_remove(base, ev, EVLIST_TIMEOUT);
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		/* Check if it is active due to a timeout.  Rescheduling
Packit e9ba0d
		 * this timeout before the callback can be executed
Packit e9ba0d
		 * removes it from the active list. */
Packit e9ba0d
		if ((ev->ev_flags & EVLIST_ACTIVE) &&
Packit e9ba0d
		    (ev->ev_res & EV_TIMEOUT)) {
Packit e9ba0d
			if (ev->ev_events & EV_SIGNAL) {
Packit e9ba0d
				/* See if we are just active executing
Packit e9ba0d
				 * this event in a loop
Packit e9ba0d
				 */
Packit e9ba0d
				if (ev->ev_ncalls && ev->ev_pncalls) {
Packit e9ba0d
					/* Abort loop */
Packit e9ba0d
					*ev->ev_pncalls = 0;
Packit e9ba0d
				}
Packit e9ba0d
			}
Packit e9ba0d
Packit e9ba0d
			event_queue_remove(base, ev, EVLIST_ACTIVE);
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		gettime(base, &now;;
Packit e9ba0d
Packit e9ba0d
		common_timeout = is_common_timeout(tv, base);
Packit e9ba0d
		if (tv_is_absolute) {
Packit e9ba0d
			ev->ev_timeout = *tv;
Packit e9ba0d
		} else if (common_timeout) {
Packit e9ba0d
			struct timeval tmp = *tv;
Packit e9ba0d
			tmp.tv_usec &= MICROSECONDS_MASK;
Packit e9ba0d
			evutil_timeradd(&now, &tmp, &ev->ev_timeout);
Packit e9ba0d
			ev->ev_timeout.tv_usec |=
Packit e9ba0d
			    (tv->tv_usec & ~MICROSECONDS_MASK);
Packit e9ba0d
		} else {
Packit e9ba0d
			evutil_timeradd(&now, tv, &ev->ev_timeout);
Packit e9ba0d
		}
Packit e9ba0d
Packit e9ba0d
		event_debug((
Packit e9ba0d
			 "event_add: timeout in %d seconds, call %p",
Packit e9ba0d
			 (int)tv->tv_sec, ev->ev_callback));
Packit e9ba0d
Packit e9ba0d
		event_queue_insert(base, ev, EVLIST_TIMEOUT);
Packit e9ba0d
		if (common_timeout) {
Packit e9ba0d
			struct common_timeout_list *ctl =
Packit e9ba0d
			    get_common_timeout_list(base, &ev->ev_timeout);
Packit e9ba0d
			if (ev == TAILQ_FIRST(&ctl->events)) {
Packit e9ba0d
				common_timeout_schedule(ctl, &now, ev);
Packit e9ba0d
			}
Packit e9ba0d
		} else {
Packit e9ba0d
			/* See if the earliest timeout is now earlier than it
Packit e9ba0d
			 * was before: if so, we will need to tell the main
Packit e9ba0d
			 * thread to wake up earlier than it would
Packit e9ba0d
			 * otherwise. */
Packit e9ba0d
			if (min_heap_elt_is_top(ev))
Packit e9ba0d
				notify = 1;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	/* if we are not in the right thread, we need to wake up the loop */
Packit e9ba0d
	if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
Packit e9ba0d
		evthread_notify_base(base);
Packit e9ba0d
Packit e9ba0d
	_event_debug_note_add(ev);
Packit e9ba0d
Packit e9ba0d
	return (res);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
event_del(struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	int res;
Packit e9ba0d
Packit e9ba0d
	if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
Packit e9ba0d
		event_warnx("%s: event has no event_base set.", __func__);
Packit e9ba0d
		return -1;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	res = event_del_internal(ev);
Packit e9ba0d
Packit e9ba0d
	EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	return (res);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Helper for event_del: always called with th_base_lock held. */
Packit e9ba0d
static inline int
Packit e9ba0d
event_del_internal(struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	struct event_base *base;
Packit e9ba0d
	int res = 0, notify = 0;
Packit e9ba0d
Packit e9ba0d
	event_debug(("event_del: %p (fd "EV_SOCK_FMT"), callback %p",
Packit e9ba0d
		ev, EV_SOCK_ARG(ev->ev_fd), ev->ev_callback));
Packit e9ba0d
Packit e9ba0d
	/* An event without a base has not been added */
Packit e9ba0d
	if (ev->ev_base == NULL)
Packit e9ba0d
		return (-1);
Packit e9ba0d
Packit e9ba0d
	EVENT_BASE_ASSERT_LOCKED(ev->ev_base);
Packit e9ba0d
Packit e9ba0d
	/* If the main thread is currently executing this event's callback,
Packit e9ba0d
	 * and we are not the main thread, then we want to wait until the
Packit e9ba0d
	 * callback is done before we start removing the event.  That way,
Packit e9ba0d
	 * when this function returns, it will be safe to free the
Packit e9ba0d
	 * user-supplied argument. */
Packit e9ba0d
	base = ev->ev_base;
Packit e9ba0d
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
Packit e9ba0d
	if (base->current_event == ev && !EVBASE_IN_THREAD(base)) {
Packit e9ba0d
		++base->current_event_waiters;
Packit e9ba0d
		EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
Packit e9ba0d
	}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
	EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
Packit e9ba0d
Packit e9ba0d
	/* See if we are just active executing this event in a loop */
Packit e9ba0d
	if (ev->ev_events & EV_SIGNAL) {
Packit e9ba0d
		if (ev->ev_ncalls && ev->ev_pncalls) {
Packit e9ba0d
			/* Abort loop */
Packit e9ba0d
			*ev->ev_pncalls = 0;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (ev->ev_flags & EVLIST_TIMEOUT) {
Packit e9ba0d
		/* NOTE: We never need to notify the main thread because of a
Packit e9ba0d
		 * deleted timeout event: all that could happen if we don't is
Packit e9ba0d
		 * that the dispatch loop might wake up too early.  But the
Packit e9ba0d
		 * point of notifying the main thread _is_ to wake up the
Packit e9ba0d
		 * dispatch loop early anyway, so we wouldn't gain anything by
Packit e9ba0d
		 * doing it.
Packit e9ba0d
		 */
Packit e9ba0d
		event_queue_remove(base, ev, EVLIST_TIMEOUT);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (ev->ev_flags & EVLIST_ACTIVE)
Packit e9ba0d
		event_queue_remove(base, ev, EVLIST_ACTIVE);
Packit e9ba0d
Packit e9ba0d
	if (ev->ev_flags & EVLIST_INSERTED) {
Packit e9ba0d
		event_queue_remove(base, ev, EVLIST_INSERTED);
Packit e9ba0d
		if (ev->ev_events & (EV_READ|EV_WRITE))
Packit e9ba0d
			res = evmap_io_del(base, ev->ev_fd, ev);
Packit e9ba0d
		else
Packit e9ba0d
			res = evmap_signal_del(base, (int)ev->ev_fd, ev);
Packit e9ba0d
		if (res == 1) {
Packit e9ba0d
			/* evmap says we need to notify the main thread. */
Packit e9ba0d
			notify = 1;
Packit e9ba0d
			res = 0;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	/* if we are not in the right thread, we need to wake up the loop */
Packit e9ba0d
	if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
Packit e9ba0d
		evthread_notify_base(base);
Packit e9ba0d
Packit e9ba0d
	_event_debug_note_del(ev);
Packit e9ba0d
Packit e9ba0d
	return (res);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_active(struct event *ev, int res, short ncalls)
Packit e9ba0d
{
Packit e9ba0d
	if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
Packit e9ba0d
		event_warnx("%s: event has no event_base set.", __func__);
Packit e9ba0d
		return;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
Packit e9ba0d
Packit e9ba0d
	_event_debug_assert_is_setup(ev);
Packit e9ba0d
Packit e9ba0d
	event_active_nolock(ev, res, ncalls);
Packit e9ba0d
Packit e9ba0d
	EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_active_nolock(struct event *ev, int res, short ncalls)
Packit e9ba0d
{
Packit e9ba0d
	struct event_base *base;
Packit e9ba0d
Packit e9ba0d
	event_debug(("event_active: %p (fd "EV_SOCK_FMT"), res %d, callback %p",
Packit e9ba0d
		ev, EV_SOCK_ARG(ev->ev_fd), (int)res, ev->ev_callback));
Packit e9ba0d
Packit e9ba0d
Packit e9ba0d
	/* We get different kinds of events, add them together */
Packit e9ba0d
	if (ev->ev_flags & EVLIST_ACTIVE) {
Packit e9ba0d
		ev->ev_res |= res;
Packit e9ba0d
		return;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	base = ev->ev_base;
Packit e9ba0d
Packit e9ba0d
	EVENT_BASE_ASSERT_LOCKED(base);
Packit e9ba0d
Packit e9ba0d
	ev->ev_res = res;
Packit e9ba0d
Packit e9ba0d
	if (ev->ev_pri < base->event_running_priority)
Packit e9ba0d
		base->event_continue = 1;
Packit e9ba0d
Packit e9ba0d
	if (ev->ev_events & EV_SIGNAL) {
Packit e9ba0d
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
Packit e9ba0d
		if (base->current_event == ev && !EVBASE_IN_THREAD(base)) {
Packit e9ba0d
			++base->current_event_waiters;
Packit e9ba0d
			EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
Packit e9ba0d
		}
Packit e9ba0d
#endif
Packit e9ba0d
		ev->ev_ncalls = ncalls;
Packit e9ba0d
		ev->ev_pncalls = NULL;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	event_queue_insert(base, ev, EVLIST_ACTIVE);
Packit e9ba0d
Packit e9ba0d
	if (EVBASE_NEED_NOTIFY(base))
Packit e9ba0d
		evthread_notify_base(base);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_deferred_cb_init(struct deferred_cb *cb, deferred_cb_fn fn, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	memset(cb, 0, sizeof(struct deferred_cb));
Packit e9ba0d
	cb->cb = fn;
Packit e9ba0d
	cb->arg = arg;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_deferred_cb_cancel(struct deferred_cb_queue *queue,
Packit e9ba0d
    struct deferred_cb *cb)
Packit e9ba0d
{
Packit e9ba0d
	if (!queue) {
Packit e9ba0d
		if (current_base)
Packit e9ba0d
			queue = &current_base->defer_queue;
Packit e9ba0d
		else
Packit e9ba0d
			return;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	LOCK_DEFERRED_QUEUE(queue);
Packit e9ba0d
	if (cb->queued) {
Packit e9ba0d
		TAILQ_REMOVE(&queue->deferred_cb_list, cb, cb_next);
Packit e9ba0d
		--queue->active_count;
Packit e9ba0d
		cb->queued = 0;
Packit e9ba0d
	}
Packit e9ba0d
	UNLOCK_DEFERRED_QUEUE(queue);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_deferred_cb_schedule(struct deferred_cb_queue *queue,
Packit e9ba0d
    struct deferred_cb *cb)
Packit e9ba0d
{
Packit e9ba0d
	if (!queue) {
Packit e9ba0d
		if (current_base)
Packit e9ba0d
			queue = &current_base->defer_queue;
Packit e9ba0d
		else
Packit e9ba0d
			return;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	LOCK_DEFERRED_QUEUE(queue);
Packit e9ba0d
	if (!cb->queued) {
Packit e9ba0d
		cb->queued = 1;
Packit e9ba0d
		TAILQ_INSERT_TAIL(&queue->deferred_cb_list, cb, cb_next);
Packit e9ba0d
		++queue->active_count;
Packit e9ba0d
		if (queue->notify_fn)
Packit e9ba0d
			queue->notify_fn(queue, queue->notify_arg);
Packit e9ba0d
	}
Packit e9ba0d
	UNLOCK_DEFERRED_QUEUE(queue);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
timeout_next(struct event_base *base, struct timeval **tv_p)
Packit e9ba0d
{
Packit e9ba0d
	/* Caller must hold th_base_lock */
Packit e9ba0d
	struct timeval now;
Packit e9ba0d
	struct event *ev;
Packit e9ba0d
	struct timeval *tv = *tv_p;
Packit e9ba0d
	int res = 0;
Packit e9ba0d
Packit e9ba0d
	ev = min_heap_top(&base->timeheap);
Packit e9ba0d
Packit e9ba0d
	if (ev == NULL) {
Packit e9ba0d
		/* if no time-based events are active wait for I/O */
Packit e9ba0d
		*tv_p = NULL;
Packit e9ba0d
		goto out;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (gettime(base, &now) == -1) {
Packit e9ba0d
		res = -1;
Packit e9ba0d
		goto out;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (evutil_timercmp(&ev->ev_timeout, &now, <=)) {
Packit e9ba0d
		evutil_timerclear(tv);
Packit e9ba0d
		goto out;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	evutil_timersub(&ev->ev_timeout, &now, tv);
Packit e9ba0d
Packit e9ba0d
	EVUTIL_ASSERT(tv->tv_sec >= 0);
Packit e9ba0d
	EVUTIL_ASSERT(tv->tv_usec >= 0);
Packit e9ba0d
	event_debug(("timeout_next: in %d seconds", (int)tv->tv_sec));
Packit e9ba0d
Packit e9ba0d
out:
Packit e9ba0d
	return (res);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/*
Packit e9ba0d
 * Determines if the time is running backwards by comparing the current time
Packit e9ba0d
 * against the last time we checked.  Not needed when using clock monotonic.
Packit e9ba0d
 * If time is running backwards, we adjust the firing time of every event by
Packit e9ba0d
 * the amount that time seems to have jumped.
Packit e9ba0d
 */
Packit e9ba0d
static void
Packit e9ba0d
timeout_correct(struct event_base *base, struct timeval *tv)
Packit e9ba0d
{
Packit e9ba0d
	/* Caller must hold th_base_lock. */
Packit e9ba0d
	struct event **pev;
Packit e9ba0d
	unsigned int size;
Packit e9ba0d
	struct timeval off;
Packit e9ba0d
	int i;
Packit e9ba0d
Packit e9ba0d
	if (use_monotonic)
Packit e9ba0d
		return;
Packit e9ba0d
Packit e9ba0d
	/* Check if time is running backwards */
Packit e9ba0d
	gettime(base, tv);
Packit e9ba0d
Packit e9ba0d
	if (evutil_timercmp(tv, &base->event_tv, >=)) {
Packit e9ba0d
		base->event_tv = *tv;
Packit e9ba0d
		return;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	event_debug(("%s: time is running backwards, corrected",
Packit e9ba0d
		    __func__));
Packit e9ba0d
	evutil_timersub(&base->event_tv, tv, &off;;
Packit e9ba0d
Packit e9ba0d
	/*
Packit e9ba0d
	 * We can modify the key element of the node without destroying
Packit e9ba0d
	 * the minheap property, because we change every element.
Packit e9ba0d
	 */
Packit e9ba0d
	pev = base->timeheap.p;
Packit e9ba0d
	size = base->timeheap.n;
Packit e9ba0d
	for (; size-- > 0; ++pev) {
Packit e9ba0d
		struct timeval *ev_tv = &(**pev).ev_timeout;
Packit e9ba0d
		evutil_timersub(ev_tv, &off, ev_tv);
Packit e9ba0d
	}
Packit e9ba0d
	for (i=0; i<base->n_common_timeouts; ++i) {
Packit e9ba0d
		struct event *ev;
Packit e9ba0d
		struct common_timeout_list *ctl =
Packit e9ba0d
		    base->common_timeout_queues[i];
Packit e9ba0d
		TAILQ_FOREACH(ev, &ctl->events,
Packit e9ba0d
		    ev_timeout_pos.ev_next_with_common_timeout) {
Packit e9ba0d
			struct timeval *ev_tv = &ev->ev_timeout;
Packit e9ba0d
			ev_tv->tv_usec &= MICROSECONDS_MASK;
Packit e9ba0d
			evutil_timersub(ev_tv, &off, ev_tv);
Packit e9ba0d
			ev_tv->tv_usec |= COMMON_TIMEOUT_MAGIC |
Packit e9ba0d
			    (i<
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	/* Now remember what the new time turned out to be. */
Packit e9ba0d
	base->event_tv = *tv;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Activate every event whose timeout has elapsed. */
Packit e9ba0d
static void
Packit e9ba0d
timeout_process(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	/* Caller must hold lock. */
Packit e9ba0d
	struct timeval now;
Packit e9ba0d
	struct event *ev;
Packit e9ba0d
Packit e9ba0d
	if (min_heap_empty(&base->timeheap)) {
Packit e9ba0d
		return;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	gettime(base, &now;;
Packit e9ba0d
Packit e9ba0d
	while ((ev = min_heap_top(&base->timeheap))) {
Packit e9ba0d
		if (evutil_timercmp(&ev->ev_timeout, &now, >))
Packit e9ba0d
			break;
Packit e9ba0d
Packit e9ba0d
		/* delete this event from the I/O queues */
Packit e9ba0d
		event_del_internal(ev);
Packit e9ba0d
Packit e9ba0d
		event_debug(("timeout_process: call %p",
Packit e9ba0d
			 ev->ev_callback));
Packit e9ba0d
		event_active_nolock(ev, EV_TIMEOUT, 1);
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Remove 'ev' from 'queue' (EVLIST_...) in base. */
Packit e9ba0d
static void
Packit e9ba0d
event_queue_remove(struct event_base *base, struct event *ev, int queue)
Packit e9ba0d
{
Packit e9ba0d
	EVENT_BASE_ASSERT_LOCKED(base);
Packit e9ba0d
Packit e9ba0d
	if (!(ev->ev_flags & queue)) {
Packit e9ba0d
		event_errx(1, "%s: %p(fd "EV_SOCK_FMT") not on queue %x", __func__,
Packit e9ba0d
		    ev, EV_SOCK_ARG(ev->ev_fd), queue);
Packit e9ba0d
		return;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (~ev->ev_flags & EVLIST_INTERNAL)
Packit e9ba0d
		base->event_count--;
Packit e9ba0d
Packit e9ba0d
	ev->ev_flags &= ~queue;
Packit e9ba0d
	switch (queue) {
Packit e9ba0d
	case EVLIST_INSERTED:
Packit e9ba0d
		TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
Packit e9ba0d
		break;
Packit e9ba0d
	case EVLIST_ACTIVE:
Packit e9ba0d
		base->event_count_active--;
Packit e9ba0d
		TAILQ_REMOVE(&base->activequeues[ev->ev_pri],
Packit e9ba0d
		    ev, ev_active_next);
Packit e9ba0d
		break;
Packit e9ba0d
	case EVLIST_TIMEOUT:
Packit e9ba0d
		if (is_common_timeout(&ev->ev_timeout, base)) {
Packit e9ba0d
			struct common_timeout_list *ctl =
Packit e9ba0d
			    get_common_timeout_list(base, &ev->ev_timeout);
Packit e9ba0d
			TAILQ_REMOVE(&ctl->events, ev,
Packit e9ba0d
			    ev_timeout_pos.ev_next_with_common_timeout);
Packit e9ba0d
		} else {
Packit e9ba0d
			min_heap_erase(&base->timeheap, ev);
Packit e9ba0d
		}
Packit e9ba0d
		break;
Packit e9ba0d
	default:
Packit e9ba0d
		event_errx(1, "%s: unknown queue %x", __func__, queue);
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Add 'ev' to the common timeout list in 'ev'. */
Packit e9ba0d
static void
Packit e9ba0d
insert_common_timeout_inorder(struct common_timeout_list *ctl,
Packit e9ba0d
    struct event *ev)
Packit e9ba0d
{
Packit e9ba0d
	struct event *e;
Packit e9ba0d
	/* By all logic, we should just be able to append 'ev' to the end of
Packit e9ba0d
	 * ctl->events, since the timeout on each 'ev' is set to {the common
Packit e9ba0d
	 * timeout} + {the time when we add the event}, and so the events
Packit e9ba0d
	 * should arrive in order of their timeeouts.  But just in case
Packit e9ba0d
	 * there's some wacky threading issue going on, we do a search from
Packit e9ba0d
	 * the end of 'ev' to find the right insertion point.
Packit e9ba0d
	 */
Packit e9ba0d
	TAILQ_FOREACH_REVERSE(e, &ctl->events,
Packit e9ba0d
	    event_list, ev_timeout_pos.ev_next_with_common_timeout) {
Packit e9ba0d
		/* This timercmp is a little sneaky, since both ev and e have
Packit e9ba0d
		 * magic values in tv_usec.  Fortunately, they ought to have
Packit e9ba0d
		 * the _same_ magic values in tv_usec.  Let's assert for that.
Packit e9ba0d
		 */
Packit e9ba0d
		EVUTIL_ASSERT(
Packit e9ba0d
			is_same_common_timeout(&e->ev_timeout, &ev->ev_timeout));
Packit e9ba0d
		if (evutil_timercmp(&ev->ev_timeout, &e->ev_timeout, >=)) {
Packit e9ba0d
			TAILQ_INSERT_AFTER(&ctl->events, e, ev,
Packit e9ba0d
			    ev_timeout_pos.ev_next_with_common_timeout);
Packit e9ba0d
			return;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
	TAILQ_INSERT_HEAD(&ctl->events, ev,
Packit e9ba0d
	    ev_timeout_pos.ev_next_with_common_timeout);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
event_queue_insert(struct event_base *base, struct event *ev, int queue)
Packit e9ba0d
{
Packit e9ba0d
	EVENT_BASE_ASSERT_LOCKED(base);
Packit e9ba0d
Packit e9ba0d
	if (ev->ev_flags & queue) {
Packit e9ba0d
		/* Double insertion is possible for active events */
Packit e9ba0d
		if (queue & EVLIST_ACTIVE)
Packit e9ba0d
			return;
Packit e9ba0d
Packit e9ba0d
		event_errx(1, "%s: %p(fd "EV_SOCK_FMT") already on queue %x", __func__,
Packit e9ba0d
		    ev, EV_SOCK_ARG(ev->ev_fd), queue);
Packit e9ba0d
		return;
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	if (~ev->ev_flags & EVLIST_INTERNAL)
Packit e9ba0d
		base->event_count++;
Packit e9ba0d
Packit e9ba0d
	ev->ev_flags |= queue;
Packit e9ba0d
	switch (queue) {
Packit e9ba0d
	case EVLIST_INSERTED:
Packit e9ba0d
		TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
Packit e9ba0d
		break;
Packit e9ba0d
	case EVLIST_ACTIVE:
Packit e9ba0d
		base->event_count_active++;
Packit e9ba0d
		TAILQ_INSERT_TAIL(&base->activequeues[ev->ev_pri],
Packit e9ba0d
		    ev,ev_active_next);
Packit e9ba0d
		break;
Packit e9ba0d
	case EVLIST_TIMEOUT: {
Packit e9ba0d
		if (is_common_timeout(&ev->ev_timeout, base)) {
Packit e9ba0d
			struct common_timeout_list *ctl =
Packit e9ba0d
			    get_common_timeout_list(base, &ev->ev_timeout);
Packit e9ba0d
			insert_common_timeout_inorder(ctl, ev);
Packit e9ba0d
		} else
Packit e9ba0d
			min_heap_push(&base->timeheap, ev);
Packit e9ba0d
		break;
Packit e9ba0d
	}
Packit e9ba0d
	default:
Packit e9ba0d
		event_errx(1, "%s: unknown queue %x", __func__, queue);
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/* Functions for debugging */
Packit e9ba0d
Packit e9ba0d
const char *
Packit e9ba0d
event_get_version(void)
Packit e9ba0d
{
Packit e9ba0d
	return (_EVENT_VERSION);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
ev_uint32_t
Packit e9ba0d
event_get_version_number(void)
Packit e9ba0d
{
Packit e9ba0d
	return (_EVENT_NUMERIC_VERSION);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/*
Packit e9ba0d
 * No thread-safe interface needed - the information should be the same
Packit e9ba0d
 * for all threads.
Packit e9ba0d
 */
Packit e9ba0d
Packit e9ba0d
const char *
Packit e9ba0d
event_get_method(void)
Packit e9ba0d
{
Packit e9ba0d
	return (current_base->evsel->name);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
#ifndef _EVENT_DISABLE_MM_REPLACEMENT
Packit e9ba0d
static void *(*_mm_malloc_fn)(size_t sz) = NULL;
Packit e9ba0d
static void *(*_mm_realloc_fn)(void *p, size_t sz) = NULL;
Packit e9ba0d
static void (*_mm_free_fn)(void *p) = NULL;
Packit e9ba0d
Packit e9ba0d
void *
Packit e9ba0d
event_mm_malloc_(size_t sz)
Packit e9ba0d
{
Packit e9ba0d
	if (_mm_malloc_fn)
Packit e9ba0d
		return _mm_malloc_fn(sz);
Packit e9ba0d
	else
Packit e9ba0d
		return malloc(sz);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void *
Packit e9ba0d
event_mm_calloc_(size_t count, size_t size)
Packit e9ba0d
{
Packit e9ba0d
	if (_mm_malloc_fn) {
Packit e9ba0d
		size_t sz = count * size;
Packit e9ba0d
		void *p = _mm_malloc_fn(sz);
Packit e9ba0d
		if (p)
Packit e9ba0d
			memset(p, 0, sz);
Packit e9ba0d
		return p;
Packit e9ba0d
	} else
Packit e9ba0d
		return calloc(count, size);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
char *
Packit e9ba0d
event_mm_strdup_(const char *str)
Packit e9ba0d
{
Packit e9ba0d
	if (_mm_malloc_fn) {
Packit e9ba0d
		size_t ln = strlen(str);
Packit e9ba0d
		void *p = _mm_malloc_fn(ln+1);
Packit e9ba0d
		if (p)
Packit e9ba0d
			memcpy(p, str, ln+1);
Packit e9ba0d
		return p;
Packit e9ba0d
	} else
Packit e9ba0d
#ifdef WIN32
Packit e9ba0d
		return _strdup(str);
Packit e9ba0d
#else
Packit e9ba0d
		return strdup(str);
Packit e9ba0d
#endif
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void *
Packit e9ba0d
event_mm_realloc_(void *ptr, size_t sz)
Packit e9ba0d
{
Packit e9ba0d
	if (_mm_realloc_fn)
Packit e9ba0d
		return _mm_realloc_fn(ptr, sz);
Packit e9ba0d
	else
Packit e9ba0d
		return realloc(ptr, sz);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_mm_free_(void *ptr)
Packit e9ba0d
{
Packit e9ba0d
	if (_mm_free_fn)
Packit e9ba0d
		_mm_free_fn(ptr);
Packit e9ba0d
	else
Packit e9ba0d
		free(ptr);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_set_mem_functions(void *(*malloc_fn)(size_t sz),
Packit e9ba0d
			void *(*realloc_fn)(void *ptr, size_t sz),
Packit e9ba0d
			void (*free_fn)(void *ptr))
Packit e9ba0d
{
Packit e9ba0d
	_mm_malloc_fn = malloc_fn;
Packit e9ba0d
	_mm_realloc_fn = realloc_fn;
Packit e9ba0d
	_mm_free_fn = free_fn;
Packit e9ba0d
}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
#if defined(_EVENT_HAVE_EVENTFD) && defined(_EVENT_HAVE_SYS_EVENTFD_H)
Packit e9ba0d
static void
Packit e9ba0d
evthread_notify_drain_eventfd(evutil_socket_t fd, short what, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	ev_uint64_t msg;
Packit e9ba0d
	ev_ssize_t r;
Packit e9ba0d
	struct event_base *base = arg;
Packit e9ba0d
Packit e9ba0d
	r = read(fd, (void*) &msg, sizeof(msg));
Packit e9ba0d
	if (r<0 && errno != EAGAIN) {
Packit e9ba0d
		event_sock_warn(fd, "Error reading from eventfd");
Packit e9ba0d
	}
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
	base->is_notify_pending = 0;
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
static void
Packit e9ba0d
evthread_notify_drain_default(evutil_socket_t fd, short what, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	unsigned char buf[1024];
Packit e9ba0d
	struct event_base *base = arg;
Packit e9ba0d
#ifdef WIN32
Packit e9ba0d
	while (recv(fd, (char*)buf, sizeof(buf), 0) > 0)
Packit e9ba0d
		;
Packit e9ba0d
#else
Packit e9ba0d
	while (read(fd, (char*)buf, sizeof(buf)) > 0)
Packit e9ba0d
		;
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
	base->is_notify_pending = 0;
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
int
Packit e9ba0d
evthread_make_base_notifiable(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	void (*cb)(evutil_socket_t, short, void *) = evthread_notify_drain_default;
Packit e9ba0d
	int (*notify)(struct event_base *) = evthread_notify_base_default;
Packit e9ba0d
Packit e9ba0d
	/* XXXX grab the lock here? */
Packit e9ba0d
	if (!base)
Packit e9ba0d
		return -1;
Packit e9ba0d
Packit e9ba0d
	if (base->th_notify_fd[0] >= 0)
Packit e9ba0d
		return 0;
Packit e9ba0d
Packit e9ba0d
#if defined(_EVENT_HAVE_EVENTFD) && defined(_EVENT_HAVE_SYS_EVENTFD_H)
Packit e9ba0d
#ifndef EFD_CLOEXEC
Packit e9ba0d
#define EFD_CLOEXEC 0
Packit e9ba0d
#endif
Packit e9ba0d
	base->th_notify_fd[0] = eventfd(0, EFD_CLOEXEC);
Packit e9ba0d
	if (base->th_notify_fd[0] >= 0) {
Packit e9ba0d
		evutil_make_socket_closeonexec(base->th_notify_fd[0]);
Packit e9ba0d
		notify = evthread_notify_base_eventfd;
Packit e9ba0d
		cb = evthread_notify_drain_eventfd;
Packit e9ba0d
	}
Packit e9ba0d
#endif
Packit e9ba0d
#if defined(_EVENT_HAVE_PIPE)
Packit e9ba0d
	if (base->th_notify_fd[0] < 0) {
Packit e9ba0d
		if ((base->evsel->features & EV_FEATURE_FDS)) {
Packit e9ba0d
			if (pipe(base->th_notify_fd) < 0) {
Packit e9ba0d
				event_warn("%s: pipe", __func__);
Packit e9ba0d
			} else {
Packit e9ba0d
				evutil_make_socket_closeonexec(base->th_notify_fd[0]);
Packit e9ba0d
				evutil_make_socket_closeonexec(base->th_notify_fd[1]);
Packit e9ba0d
			}
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
#ifdef WIN32
Packit e9ba0d
#define LOCAL_SOCKETPAIR_AF AF_INET
Packit e9ba0d
#else
Packit e9ba0d
#define LOCAL_SOCKETPAIR_AF AF_UNIX
Packit e9ba0d
#endif
Packit e9ba0d
	if (base->th_notify_fd[0] < 0) {
Packit e9ba0d
		if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0,
Packit e9ba0d
			base->th_notify_fd) == -1) {
Packit e9ba0d
			event_sock_warn(-1, "%s: socketpair", __func__);
Packit e9ba0d
			return (-1);
Packit e9ba0d
		} else {
Packit e9ba0d
			evutil_make_socket_closeonexec(base->th_notify_fd[0]);
Packit e9ba0d
			evutil_make_socket_closeonexec(base->th_notify_fd[1]);
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	evutil_make_socket_nonblocking(base->th_notify_fd[0]);
Packit e9ba0d
Packit e9ba0d
	base->th_notify_fn = notify;
Packit e9ba0d
Packit e9ba0d
	/*
Packit e9ba0d
	  Making the second socket nonblocking is a bit subtle, given that we
Packit e9ba0d
	  ignore any EAGAIN returns when writing to it, and you don't usally
Packit e9ba0d
	  do that for a nonblocking socket. But if the kernel gives us EAGAIN,
Packit e9ba0d
	  then there's no need to add any more data to the buffer, since
Packit e9ba0d
	  the main thread is already either about to wake up and drain it,
Packit e9ba0d
	  or woken up and in the process of draining it.
Packit e9ba0d
	*/
Packit e9ba0d
	if (base->th_notify_fd[1] > 0)
Packit e9ba0d
		evutil_make_socket_nonblocking(base->th_notify_fd[1]);
Packit e9ba0d
Packit e9ba0d
	/* prepare an event that we can use for wakeup */
Packit e9ba0d
	event_assign(&base->th_notify, base, base->th_notify_fd[0],
Packit e9ba0d
				 EV_READ|EV_PERSIST, cb, base);
Packit e9ba0d
Packit e9ba0d
	/* we need to mark this as internal event */
Packit e9ba0d
	base->th_notify.ev_flags |= EVLIST_INTERNAL;
Packit e9ba0d
	event_priority_set(&base->th_notify, 0);
Packit e9ba0d
Packit e9ba0d
	return event_add(&base->th_notify, NULL);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_base_dump_events(struct event_base *base, FILE *output)
Packit e9ba0d
{
Packit e9ba0d
	struct event *e;
Packit e9ba0d
	int i;
Packit e9ba0d
	fprintf(output, "Inserted events:\n");
Packit e9ba0d
	TAILQ_FOREACH(e, &base->eventqueue, ev_next) {
Packit e9ba0d
		fprintf(output, "  %p [fd "EV_SOCK_FMT"]%s%s%s%s%s\n",
Packit e9ba0d
				(void*)e, EV_SOCK_ARG(e->ev_fd),
Packit e9ba0d
				(e->ev_events&EV_READ)?" Read":"",
Packit e9ba0d
				(e->ev_events&EV_WRITE)?" Write":"",
Packit e9ba0d
				(e->ev_events&EV_SIGNAL)?" Signal":"",
Packit e9ba0d
				(e->ev_events&EV_TIMEOUT)?" Timeout":"",
Packit e9ba0d
				(e->ev_events&EV_PERSIST)?" Persist":"");
Packit e9ba0d
Packit e9ba0d
	}
Packit e9ba0d
	for (i = 0; i < base->nactivequeues; ++i) {
Packit e9ba0d
		if (TAILQ_EMPTY(&base->activequeues[i]))
Packit e9ba0d
			continue;
Packit e9ba0d
		fprintf(output, "Active events [priority %d]:\n", i);
Packit e9ba0d
		TAILQ_FOREACH(e, &base->eventqueue, ev_next) {
Packit e9ba0d
			fprintf(output, "  %p [fd "EV_SOCK_FMT"]%s%s%s%s\n",
Packit e9ba0d
					(void*)e, EV_SOCK_ARG(e->ev_fd),
Packit e9ba0d
					(e->ev_res&EV_READ)?" Read active":"",
Packit e9ba0d
					(e->ev_res&EV_WRITE)?" Write active":"",
Packit e9ba0d
					(e->ev_res&EV_SIGNAL)?" Signal active":"",
Packit e9ba0d
					(e->ev_res&EV_TIMEOUT)?" Timeout active":"");
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_base_add_virtual(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
	base->virtual_event_count++;
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_base_del_virtual(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
	EVUTIL_ASSERT(base->virtual_event_count > 0);
Packit e9ba0d
	base->virtual_event_count--;
Packit e9ba0d
	if (base->virtual_event_count == 0 && EVBASE_NEED_NOTIFY(base))
Packit e9ba0d
		evthread_notify_base(base);
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
Packit e9ba0d
int
Packit e9ba0d
event_global_setup_locks_(const int enable_locks)
Packit e9ba0d
{
Packit e9ba0d
#ifndef _EVENT_DISABLE_DEBUG_MODE
Packit e9ba0d
	EVTHREAD_SETUP_GLOBAL_LOCK(_event_debug_map_lock, 0);
Packit e9ba0d
#endif
Packit e9ba0d
	if (evsig_global_setup_locks_(enable_locks) < 0)
Packit e9ba0d
		return -1;
Packit e9ba0d
	if (evutil_secure_rng_global_setup_locks_(enable_locks) < 0)
Packit e9ba0d
		return -1;
Packit e9ba0d
	return 0;
Packit e9ba0d
}
Packit e9ba0d
#endif
Packit e9ba0d
Packit e9ba0d
void
Packit e9ba0d
event_base_assert_ok(struct event_base *base)
Packit e9ba0d
{
Packit e9ba0d
	int i;
Packit e9ba0d
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
Packit e9ba0d
	evmap_check_integrity(base);
Packit e9ba0d
Packit e9ba0d
	/* Check the heap property */
Packit e9ba0d
	for (i = 1; i < (int)base->timeheap.n; ++i) {
Packit e9ba0d
		int parent = (i - 1) / 2;
Packit e9ba0d
		struct event *ev, *p_ev;
Packit e9ba0d
		ev = base->timeheap.p[i];
Packit e9ba0d
		p_ev = base->timeheap.p[parent];
Packit e9ba0d
		EVUTIL_ASSERT(ev->ev_flags & EV_TIMEOUT);
Packit e9ba0d
		EVUTIL_ASSERT(evutil_timercmp(&p_ev->ev_timeout, &ev->ev_timeout, <=));
Packit e9ba0d
		EVUTIL_ASSERT(ev->ev_timeout_pos.min_heap_idx == i);
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	/* Check that the common timeouts are fine */
Packit e9ba0d
	for (i = 0; i < base->n_common_timeouts; ++i) {
Packit e9ba0d
		struct common_timeout_list *ctl = base->common_timeout_queues[i];
Packit e9ba0d
		struct event *last=NULL, *ev;
Packit e9ba0d
		TAILQ_FOREACH(ev, &ctl->events, ev_timeout_pos.ev_next_with_common_timeout) {
Packit e9ba0d
			if (last)
Packit e9ba0d
				EVUTIL_ASSERT(evutil_timercmp(&last->ev_timeout, &ev->ev_timeout, <=));
Packit e9ba0d
			EVUTIL_ASSERT(ev->ev_flags & EV_TIMEOUT);
Packit e9ba0d
			EVUTIL_ASSERT(is_common_timeout(&ev->ev_timeout,base));
Packit e9ba0d
			EVUTIL_ASSERT(COMMON_TIMEOUT_IDX(&ev->ev_timeout) == i);
Packit e9ba0d
			last = ev;
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	EVBASE_RELEASE_LOCK(base, th_base_lock);
Packit e9ba0d
}