Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

import of libevent; an event abstraction library that supports kqueue…

… and

poll on NetBSD.
  • Loading branch information...
commit d2054c574d62ec1a86ca29c324d42bba1fa844fd 1 parent 461d39d
provos authored
32 lib/libevent/Makefile
View
@@ -0,0 +1,32 @@
+# $NetBSD: Makefile,v 1.1.1.1 2003/06/12 22:54:25 provos Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/4/93
+
+NOLINT= # Until someone explains to me how to avoid lint stupidity
+USE_SHLIBDIR= yes
+
+CPPFLAGS+=-DHAVE_CONFIG_H
+.include <bsd.own.mk>
+
+LIB= event
+SRCS= event.c kqueue.c poll.c signal.c
+
+INCS= event.h
+INCSDIR=/usr/include
+
+MAN= event.3
+
+MLINKS+=event.3 event_init.3
+MLINKS+=event.3 event_dispatch.3
+MLINKS+=event.3 event_loop.3
+MLINKS+=event.3 event_set.3
+MLINKS+=event.3 event_add.3
+MLINKS+=event.3 event_del.3
+MLINKS+=event.3 event_pending.3
+MLINKS+=event.3 event_initialized.3
+MLINKS+=event.3 signal_set.3
+MLINKS+=event.3 signal_add.3
+MLINKS+=event.3 signal_del.3
+MLINKS+=event.3 signal_pending.3
+MLINKS+=event.3 signal_initialized.3
+
+.include <bsd.lib.mk>
150 lib/libevent/config.h
View
@@ -0,0 +1,150 @@
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+/* Define if kqueue works correctly with pipes */
+#define HAVE_WORKING_KQUEUE 1
+
+/* Define to `unsigned long long' if <sys/types.h> doesn't define. */
+/* #undef u_int64_t */
+
+/* Define to `unsigned int' if <sys/types.h> doesn't define. */
+/* #undef u_int32_t */
+
+/* Define to `unsigned short' if <sys/types.h> doesn't define. */
+/* #undef u_int16_t */
+
+/* Define to `unsigned char' if <sys/types.h> doesn't define. */
+/* #undef u_int8_t */
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+#ifndef HAVE_TIMERADD
+#define timeradd(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
+ if ((vvp)->tv_usec >= 1000000) { \
+ (vvp)->tv_sec++; \
+ (vvp)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#define timersub(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif /* !HAVE_TIMERADD */
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+#ifndef HAVE_TAILQFOREACH
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) NULL
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+#endif /* TAILQ_FOREACH */
+
+/* Define to 1 if you have the `err' function. */
+#define HAVE_ERR 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#define HAVE_KQUEUE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `select' function. */
+#undef HAVE_SELECT
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#define HAVE_SYS_EVENT_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if kqueue works correctly with pipes */
+#define HAVE_WORKING_KQUEUE 1
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
+
+/* Define to `unsigned short' if <sys/types.h> does not define. */
+/* #undef u_int16_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef u_int32_t */
+
+/* Define to `unsigned long long' if <sys/types.h> does not define. */
+/* #undef u_int64_t */
+
+/* Define to `unsigned char' if <sys/types.h> does not define. */
+/* #undef u_int8_t */
316 lib/libevent/event.3
View
@@ -0,0 +1,316 @@
+.\" $OpenBSD: event.3,v 1.4 2002/07/12 18:50:48 provos Exp $
+.\"
+.\" Copyright (c) 2000 Artur Grabowski <art@openbsd.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd August 8, 2000
+.Dt EVENT 3
+.Os
+.Sh NAME
+.Nm event_init ,
+.Nm event_dispatch ,
+.Nm event_loop ,
+.Nm event_set ,
+.Nm event_add ,
+.Nm event_del ,
+.Nm event_pending ,
+.Nm event_initialized ,
+.Nm evtimer_set ,
+.Nm evtimer_add ,
+.Nm evtimer_del
+.Nm evtimer_pending ,
+.Nm evtimer_initialized ,
+.Nm signal_set ,
+.Nm signal_add ,
+.Nm signal_del
+.Nm signal_pending ,
+.Nm signal_initialized
+.Nd execute a function when a specific event occurs
+.Sh SYNOPSIS
+.Fd #include <sys/time.h>
+.Fd #include <event.h>
+.Ft void
+.Fn "event_init"
+.Ft int
+.Fn "event_dispatch"
+.Ft int
+.Fn "event_loop" "int flags"
+.Ft void
+.Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
+.Ft int
+.Fn "event_add" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "event_del" "struct event *ev"
+.Ft int
+.Fn "event_pending" "struct event *ev" "short event" "struct timeval *tv"
+.Ft int
+.Fn "event_initialized" "struct event *ev"
+.Ft void
+.Fn "evtimer_set" "struct event *ev" "void (*fn)(int, short, void *)" "void *arg"
+.Ft void
+.Fn "evtimer_add" "struct event *ev" "struct timeval *"
+.Ft void
+.Fn "evtimer_del" "struct event *ev"
+.Ft int
+.Fn "evtimer_pending" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "evtimer_initialized" "struct event *ev"
+.Ft void
+.Fn "signal_set" "struct event *ev" "int signal" "void (*fn)(int, short, void *)" "void *arg"
+.Ft void
+.Fn "signal_add" "struct event *ev" "struct timeval *"
+.Ft void
+.Fn "signal_del" "struct event *ev"
+.Ft int
+.Fn "signal_pending" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "signal_initialized" "struct event *ev"
+.Ft int
+.Fa (*event_sigcb)(void) ;
+.Ft int
+.Fa event_gotsig ;
+.Sh DESCRIPTION
+The
+.Nm event
+API provides a mechanism to execute a function when a specific event
+on a file descriptor occurs or after a given time has passed.
+.Pp
+The
+.Nm event
+API needs to be initialized with
+.Fn event_init
+before it can be used.
+.Pp
+In order to process events, an application needs to call
+.Fn event_dispatch .
+This function only returns on error, and should replace the event core
+of the application program.
+.Pp
+In order to avoid races in signal handlers, the
+.Nm event
+API provides two variables:
+.Va event_sigcb
+and
+.Va event_gotsig .
+A signal handler
+sets
+.Va event_gotsig
+to indicate that a signal has been received.
+The application sets
+.Va event_sigcb
+to a callback function. After the signal handler sets
+.Va event_gotsig ,
+.Nm event_dispatch
+will execute the callback function to process received signals. The
+callback returns 1 when no events are registered any more. It can
+return -1 to indicate an error to the
+.Nm event
+library, causing
+.Fn event_dispatch
+to terminate with
+.Va errno
+set to
+.Er EINTR.
+.Pp
+The
+.Nm event_loop
+function provides an interface for single pass execution of pending
+events. The flags
+.Va EVLOOP_ONCE
+and
+.Va EVLOOP_NONBLOCK
+are recognized.
+.Pp
+It is the responsibility of the caller to provide these functions with
+pre-allocated event structures.
+.Pp
+The function
+.Fn event_set
+prepares the event structure
+.Fa ev
+to be used in future calls to
+.Fn event_add
+and
+.Fn event_del .
+The event will be prepared to call the function specified by the
+.Fa fn
+argument with an
+.Fa int
+argument indicating the file descriptor, a
+.Fa short
+argument indicating the type of event, and a
+.Fa void *
+argument given in the
+.Fa arg
+argument.
+The
+.Fa fd
+indicates the file descriptor that should be monitored for events.
+The events can be either
+.Va EV_READ ,
+.Va EV_WRITE ,
+or both.
+Indicating that an application can read or write from the file descriptor
+respectively without blocking.
+.Pp
+The function
+.Fa fn
+will be called with the file descriptor that triggered the event and
+the type of event which will be either
+.Va EV_TIMEOUT ,
+.Va EV_SIGNAL ,
+.Va EV_READ ,
+or
+.Va EV_WRITE .
+The additional flag
+.Va EV_PERSIST
+makes an
+.Fn event_add
+persistent until
+.Fn event_del
+has been called.
+.Pp
+Once initialized, the
+.Fa ev
+structure can be used repeatedly with
+.Fn event_add
+and
+.Fn event_del
+and does not need to be reinitialized unless the function called and/or
+the argument to it are to be changed.
+.Pp
+The function
+.Fn event_add
+schedules the execution of the
+.Fa ev
+event when the event specified in
+.Fn event_set
+occurs or in at least the time specified in the
+.Fa tv .
+If
+.Fa tv
+is NULL, no timeout occurs and the function will only be called
+if a matching event occurs on the file descriptor.
+The event in the
+.Fa ev
+argument must be already initialized by
+.Fn event_set
+and may not be used in calls to
+.Fn event_set
+until it has timed out or been removed with
+.Fn event_del .
+If the event in the
+.Fa ev
+argument already has a scheduled timeout, the old timeout will be
+replaced by the new one.
+.Pp
+The function
+.Fn event_del
+will cancel the event in the argument
+.Fa ev .
+If the event has already executed or has never been added
+the call will have no effect.
+.Pp
+The
+.Fn event_pending
+function can be used to check if the event specified by
+.Fa event
+is pending to run.
+If
+.Va EV_TIMEOUT
+was specified and
+.Fa tv
+is not
+.Va NULL ,
+the expiration time of the event will be returned in
+.Fa tv .
+.Pp
+The
+.Fn event_initialized
+macro can be used to check if an event has been initialized.
+.Pp
+The functions
+.Fn evtimer_set ,
+.Fn evtimer_add ,
+.Fn evtimer_del ,
+.Fn evtimer_initialized ,
+and
+.Fn evtimer_pending
+are abbreviations for common situations where only a timeout is required.
+The file descriptor passed will be 0, and the event type will be
+.Va EV_TIMEOUT .
+.Pp
+.Pp
+The functions
+.Fn signal_set ,
+.Fn signal_add ,
+.Fn signal_del ,
+.Fn signal_initialized ,
+and
+.Fn signal_pending
+are abbreviations.
+The event type will be a persistent
+.Va EV_SIGNAL .
+That means
+.Fn signal_set
+adds
+.Va EV_PERSIST .
+.Pp
+It is possible to disable support for
+.Va epoll , kqueue , poll
+or
+.Va select
+by setting the environment variable
+.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NOPOLL
+or
+.Va EVENT_NOSELECT .
+By setting the environment variable
+.Va EVENT_SHOW_METHOD ,
+.Nm libevent
+displays the kernel notification method that it uses.
+.Pp
+.Sh RETURN VALUES
+Upon successful completion
+.Fn event_add
+and
+.Fn event_del
+return 0.
+Otherwise, -1 is returned and the global variable errno is
+set to indicate the error.
+.Sh SEE ALSO
+.Xr timeout 9 ,
+.Xr select 2 ,
+.Xr kqueue 2
+.Sh HISTORY
+The
+.Nm event
+API manpage is based on the
+.Xr timeout 9
+manpage by Artur Grabowski.
+.Sh AUTHORS
+The
+.Nm event
+library was written by Niels Provos.
538 lib/libevent/event.c
View
@@ -0,0 +1,538 @@
+/* $OpenBSD: event.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
+
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niels Provos.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/tree.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_time.h>
+#endif
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <err.h>
+#include <assert.h>
+
+#ifdef USE_LOG
+#include "log.h"
+#else
+#define LOG_DBG(x)
+#define log_error(x) perror(x)
+#endif
+
+#include "event.h"
+
+#ifdef HAVE_SELECT
+extern struct eventop selectops;
+#endif
+#ifdef HAVE_POLL
+extern struct eventop pollops;
+#endif
+#ifdef HAVE_EPOLL
+extern struct eventop epollops;
+#endif
+#ifdef HAVE_WORKING_KQUEUE
+extern struct eventop kqops;
+#endif
+
+/* In order of preference */
+struct eventop *eventops[] = {
+#ifdef HAVE_WORKING_KQUEUE
+ &kqops,
+#endif
+#ifdef HAVE_EPOLL
+ &epollops,
+#endif
+#ifdef HAVE_POLL
+ &pollops,
+#endif
+#ifdef HAVE_SELECT
+ &selectops,
+#endif
+ NULL
+};
+
+struct eventop *evsel;
+void *evbase;
+
+/* Handle signals */
+int (*event_sigcb)(void); /* Signal callback when gotsig is set */
+int event_gotsig; /* Set in signal handler */
+
+/* Prototypes */
+void event_queue_insert(struct event *, int);
+void event_queue_remove(struct event *, int);
+
+static RB_HEAD(event_tree, event) timetree;
+static struct event_list activequeue;
+struct event_list signalqueue;
+struct event_list eventqueue;
+static struct timeval event_tv;
+
+static int
+compare(struct event *a, struct event *b)
+{
+ if (timercmp(&a->ev_timeout, &b->ev_timeout, <))
+ return (-1);
+ else if (timercmp(&a->ev_timeout, &b->ev_timeout, >))
+ return (1);
+ return (0);
+}
+
+RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare);
+
+RB_GENERATE(event_tree, event, ev_timeout_node, compare);
+
+
+void
+event_init(void)
+{
+ int i;
+
+ event_sigcb = NULL;
+ event_gotsig = 0;
+ gettimeofday(&event_tv, NULL);
+
+ RB_INIT(&timetree);
+ TAILQ_INIT(&eventqueue);
+ TAILQ_INIT(&activequeue);
+ TAILQ_INIT(&signalqueue);
+
+ evbase = NULL;
+ for (i = 0; eventops[i] && !evbase; i++) {
+ evsel = eventops[i];
+
+ evbase = evsel->init();
+ }
+
+ if (evbase == NULL)
+ errx(1, "%s: no event mechanism available", __func__);
+
+ if (!issetugid() && getenv("EVENT_SHOW_METHOD"))
+ fprintf(stderr, "libevent using: %s\n", evsel->name);
+
+#if defined(USE_LOG) && defined(USE_DEBUG)
+ log_to(stderr);
+ log_debug_cmd(LOG_MISC, 80);
+#endif
+}
+
+int
+event_haveevents(void)
+{
+ return (RB_ROOT(&timetree) || TAILQ_FIRST(&eventqueue) ||
+ TAILQ_FIRST(&signalqueue) || TAILQ_FIRST(&activequeue));
+}
+
+void
+event_process_active(void)
+{
+ struct event *ev;
+ short ncalls;
+
+ for (ev = TAILQ_FIRST(&activequeue); ev;
+ ev = TAILQ_FIRST(&activequeue)) {
+ event_queue_remove(ev, EVLIST_ACTIVE);
+
+ /* Allows deletes to work */
+ ncalls = ev->ev_ncalls;
+ ev->ev_pncalls = &ncalls;
+ while (ncalls) {
+ ncalls--;
+ ev->ev_ncalls = ncalls;
+ (*ev->ev_callback)(ev->ev_fd, ev->ev_res, ev->ev_arg);
+ }
+ }
+}
+
+int
+event_dispatch(void)
+{
+ return (event_loop(0));
+}
+
+int
+event_loop(int flags)
+{
+ struct timeval tv;
+ int res, done;
+
+ /* Calculate the initial events that we are waiting for */
+ if (evsel->recalc(evbase, 0) == -1)
+ return (-1);
+
+ done = 0;
+ while (!done) {
+ while (event_gotsig) {
+ event_gotsig = 0;
+ if (event_sigcb) {
+ res = (*event_sigcb)();
+ if (res == -1) {
+ errno = EINTR;
+ return (-1);
+ }
+ }
+ }
+
+ /* Check if time is running backwards */
+ gettimeofday(&tv, NULL);
+ if (timercmp(&tv, &event_tv, <)) {
+ struct timeval off;
+ LOG_DBG((LOG_MIST, 10,
+ "%s: time is running backwards, corrected",
+ __func__));
+
+ timersub(&event_tv, &tv, &off);
+ timeout_correct(&off);
+ }
+ event_tv = tv;
+
+ if (!(flags & EVLOOP_NONBLOCK))
+ timeout_next(&tv);
+ else
+ timerclear(&tv);
+
+ /* If we have no events, we just exit */
+ if (!event_haveevents())
+ return (1);
+
+ res = evsel->dispatch(evbase, &tv);
+
+ if (res == -1)
+ return (-1);
+
+ timeout_process();
+
+ if (TAILQ_FIRST(&activequeue)) {
+ event_process_active();
+ if (flags & EVLOOP_ONCE)
+ done = 1;
+ } else if (flags & EVLOOP_NONBLOCK)
+ done = 1;
+
+ if (evsel->recalc(evbase, 0) == -1)
+ return (-1);
+ }
+
+ return (0);
+}
+
+void
+event_set(struct event *ev, int fd, short events,
+ void (*callback)(int, short, void *), void *arg)
+{
+ ev->ev_callback = callback;
+ ev->ev_arg = arg;
+ ev->ev_fd = fd;
+ ev->ev_events = events;
+ ev->ev_flags = EVLIST_INIT;
+ ev->ev_ncalls = 0;
+ ev->ev_pncalls = NULL;
+}
+
+/*
+ * Checks if a specific event is pending or scheduled.
+ */
+
+int
+event_pending(struct event *ev, short event, struct timeval *tv)
+{
+ int flags = 0;
+
+ if (ev->ev_flags & EVLIST_INSERTED)
+ flags |= (ev->ev_events & (EV_READ|EV_WRITE));
+ if (ev->ev_flags & EVLIST_ACTIVE)
+ flags |= ev->ev_res;
+ if (ev->ev_flags & EVLIST_TIMEOUT)
+ flags |= EV_TIMEOUT;
+
+ event &= (EV_TIMEOUT|EV_READ|EV_WRITE);
+
+ /* See if there is a timeout that we should report */
+ if (tv != NULL && (flags & event & EV_TIMEOUT))
+ *tv = ev->ev_timeout;
+
+ return (flags & event);
+}
+
+int
+event_add(struct event *ev, struct timeval *tv)
+{
+ LOG_DBG((LOG_MISC, 55,
+ "event_add: event: %p, %s%s%scall %p",
+ ev,
+ ev->ev_events & EV_READ ? "EV_READ " : " ",
+ ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
+ tv ? "EV_TIMEOUT " : " ",
+ ev->ev_callback));
+
+ assert(!(ev->ev_flags & ~EVLIST_ALL));
+
+ if (tv != NULL) {
+ struct timeval now;
+
+ if (ev->ev_flags & EVLIST_TIMEOUT)
+ event_queue_remove(ev, EVLIST_TIMEOUT);
+
+ /* Check if it is active due to a timeout. Rescheduling
+ * this timeout before the callback can be executed
+ * removes it from the active list. */
+ if ((ev->ev_flags & EVLIST_ACTIVE) &&
+ (ev->ev_res & EV_TIMEOUT)) {
+ /* See if we are just active executing this
+ * event in a loop
+ */
+ if (ev->ev_ncalls && ev->ev_pncalls) {
+ /* Abort loop */
+ *ev->ev_pncalls = 0;
+ }
+
+ event_queue_remove(ev, EVLIST_ACTIVE);
+ }
+
+ gettimeofday(&now, NULL);
+ timeradd(&now, tv, &ev->ev_timeout);
+
+ LOG_DBG((LOG_MISC, 55,
+ "event_add: timeout in %d seconds, call %p",
+ tv->tv_sec, ev->ev_callback));
+
+ event_queue_insert(ev, EVLIST_TIMEOUT);
+ }
+
+ if ((ev->ev_events & (EV_READ|EV_WRITE)) &&
+ !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
+ event_queue_insert(ev, EVLIST_INSERTED);
+
+ return (evsel->add(evbase, ev));
+ } else if ((ev->ev_events & EV_SIGNAL) &&
+ !(ev->ev_flags & EVLIST_SIGNAL)) {
+ event_queue_insert(ev, EVLIST_SIGNAL);
+
+ return (evsel->add(evbase, ev));
+ }
+
+ return (0);
+}
+
+int
+event_del(struct event *ev)
+{
+ LOG_DBG((LOG_MISC, 80, "event_del: %p, callback %p",
+ ev, ev->ev_callback));
+
+ assert(!(ev->ev_flags & ~EVLIST_ALL));
+
+ /* See if we are just active executing this event in a loop */
+ if (ev->ev_ncalls && ev->ev_pncalls) {
+ /* Abort loop */
+ *ev->ev_pncalls = 0;
+ }
+
+ if (ev->ev_flags & EVLIST_TIMEOUT)
+ event_queue_remove(ev, EVLIST_TIMEOUT);
+
+ if (ev->ev_flags & EVLIST_ACTIVE)
+ event_queue_remove(ev, EVLIST_ACTIVE);
+
+ if (ev->ev_flags & EVLIST_INSERTED) {
+ event_queue_remove(ev, EVLIST_INSERTED);
+ return (evsel->del(evbase, ev));
+ } else if (ev->ev_flags & EVLIST_SIGNAL) {
+ event_queue_remove(ev, EVLIST_SIGNAL);
+ return (evsel->del(evbase, ev));
+ }
+
+ return (0);
+}
+
+void
+event_active(struct event *ev, int res, short ncalls)
+{
+ /* We get different kinds of events, add them together */
+ if (ev->ev_flags & EVLIST_ACTIVE) {
+ ev->ev_res |= res;
+ return;
+ }
+
+ ev->ev_res = res;
+ ev->ev_ncalls = ncalls;
+ ev->ev_pncalls = NULL;
+ event_queue_insert(ev, EVLIST_ACTIVE);
+}
+
+int
+timeout_next(struct timeval *tv)
+{
+ struct timeval dflt = TIMEOUT_DEFAULT;
+
+ struct timeval now;
+ struct event *ev;
+
+ if ((ev = RB_MIN(event_tree, &timetree)) == NULL) {
+ *tv = dflt;
+ return (0);
+ }
+
+ if (gettimeofday(&now, NULL) == -1)
+ return (-1);
+
+ if (timercmp(&ev->ev_timeout, &now, <=)) {
+ timerclear(tv);
+ return (0);
+ }
+
+ timersub(&ev->ev_timeout, &now, tv);
+
+ LOG_DBG((LOG_MISC, 60, "timeout_next: in %d seconds", tv->tv_sec));
+ return (0);
+}
+
+void
+timeout_correct(struct timeval *off)
+{
+ struct event *ev;
+
+ /* We can modify the key element of the node without destroying
+ * the key, beause we apply it to all in the right order.
+ */
+ RB_FOREACH(ev, event_tree, &timetree)
+ timersub(&ev->ev_timeout, off, &ev->ev_timeout);
+}
+
+void
+timeout_process(void)
+{
+ struct timeval now;
+ struct event *ev, *next;
+
+ gettimeofday(&now, NULL);
+
+ for (ev = RB_MIN(event_tree, &timetree); ev; ev = next) {
+ if (timercmp(&ev->ev_timeout, &now, >))
+ break;
+ next = RB_NEXT(event_tree, &timetree, ev);
+
+ event_queue_remove(ev, EVLIST_TIMEOUT);
+
+ /* delete this event from the I/O queues */
+ event_del(ev);
+
+ LOG_DBG((LOG_MISC, 60, "timeout_process: call %p",
+ ev->ev_callback));
+ event_active(ev, EV_TIMEOUT, 1);
+ }
+}
+
+void
+timeout_insert(struct event *ev)
+{
+ struct event *tmp;
+
+ tmp = RB_FIND(event_tree, &timetree, ev);
+
+ if (tmp != NULL) {
+ struct timeval tv;
+ struct timeval add = {0,1};
+
+ /* Find unique time */
+ tv = ev->ev_timeout;
+ do {
+ timeradd(&tv, &add, &tv);
+ tmp = RB_NEXT(event_tree, &timetree, tmp);
+ } while (tmp != NULL && timercmp(&tmp->ev_timeout, &tv, ==));
+
+ ev->ev_timeout = tv;
+ }
+
+ tmp = RB_INSERT(event_tree, &timetree, ev);
+ assert(tmp == NULL);
+}
+
+void
+event_queue_remove(struct event *ev, int queue)
+{
+ if (!(ev->ev_flags & queue))
+ errx(1, "%s: %p(fd %d) not on queue %x", __func__,
+ ev, ev->ev_fd, queue);
+
+ ev->ev_flags &= ~queue;
+ switch (queue) {
+ case EVLIST_ACTIVE:
+ TAILQ_REMOVE(&activequeue, ev, ev_active_next);
+ break;
+ case EVLIST_SIGNAL:
+ TAILQ_REMOVE(&signalqueue, ev, ev_signal_next);
+ break;
+ case EVLIST_TIMEOUT:
+ RB_REMOVE(event_tree, &timetree, ev);
+ break;
+ case EVLIST_INSERTED:
+ TAILQ_REMOVE(&eventqueue, ev, ev_next);
+ break;
+ default:
+ errx(1, "%s: unknown queue %x", __func__, queue);
+ }
+}
+
+void
+event_queue_insert(struct event *ev, int queue)
+{
+ if (ev->ev_flags & queue)
+ errx(1, "%s: %p(fd %d) already on queue %x", __func__,
+ ev, ev->ev_fd, queue);
+
+ ev->ev_flags |= queue;
+ switch (queue) {
+ case EVLIST_ACTIVE:
+ TAILQ_INSERT_TAIL(&activequeue, ev, ev_active_next);
+ break;
+ case EVLIST_SIGNAL:
+ TAILQ_INSERT_TAIL(&signalqueue, ev, ev_signal_next);
+ break;
+ case EVLIST_TIMEOUT:
+ timeout_insert(ev);
+ break;
+ case EVLIST_INSERTED:
+ TAILQ_INSERT_TAIL(&eventqueue, ev, ev_next);
+ break;
+ default:
+ errx(1, "%s: unknown queue %x", __func__, queue);
+ }
+}
162 lib/libevent/event.h
View
@@ -0,0 +1,162 @@
+/* $OpenBSD: event.h,v 1.4 2002/07/12 18:50:48 provos Exp $ */
+
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niels Provos.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVENT_H_
+#define _EVENT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EVLIST_TIMEOUT 0x01
+#define EVLIST_INSERTED 0x02
+#define EVLIST_SIGNAL 0x04
+#define EVLIST_ACTIVE 0x08
+#define EVLIST_INIT 0x80
+
+/* EVLIST_X_ Private space: 0x1000-0xf000 */
+#define EVLIST_ALL (0xf000 | 0x8f)
+
+#define EV_TIMEOUT 0x01
+#define EV_READ 0x02
+#define EV_WRITE 0x04
+#define EV_SIGNAL 0x08
+#define EV_PERSIST 0x10 /* Persistant event */
+
+/* Fix so that ppl dont have to run with <sys/queue.h> */
+#ifndef TAILQ_ENTRY
+#define _EVENT_DEFINED_TQENTRY
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+#endif /* !TAILQ_ENTRY */
+#ifndef RB_ENTRY
+#define _EVENT_DEFINED_RBENTRY
+#define RB_ENTRY(type) \
+struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+}
+#endif /* !RB_ENTRY */
+
+struct event {
+ TAILQ_ENTRY (event) ev_next;
+ TAILQ_ENTRY (event) ev_active_next;
+ TAILQ_ENTRY (event) ev_signal_next;
+ RB_ENTRY (event) ev_timeout_node;
+
+ int ev_fd;
+ short ev_events;
+ short ev_ncalls;
+ short *ev_pncalls; /* Allows deletes in callback */
+
+ struct timeval ev_timeout;
+
+ void (*ev_callback)(int, short, void *arg);
+ void *ev_arg;
+
+ int ev_res; /* result passed to event callback */
+ int ev_flags;
+};
+
+#define EVENT_SIGNAL(ev) ev->ev_fd
+#define EVENT_FD(ev) ev->ev_fd
+
+#ifdef _EVENT_DEFINED_TQENTRY
+#undef TAILQ_ENTRY
+#undef _EVENT_DEFINED_TQENTRY
+#else
+TAILQ_HEAD (event_list, event);
+#endif /* _EVENT_DEFINED_TQENTRY */
+#ifdef _EVENT_DEFINED_RBENTRY
+#undef RB_ENTRY
+#undef _EVENT_DEFINED_RBENTRY
+#endif /* _EVENT_DEFINED_RBENTRY */
+
+struct eventop {
+ char *name;
+ void *(*init)(void);
+ int (*add)(void *, struct event *);
+ int (*del)(void *, struct event *);
+ int (*recalc)(void *, int);
+ int (*dispatch)(void *, struct timeval *);
+};
+
+#define TIMEOUT_DEFAULT {5, 0}
+
+void event_init(void);
+int event_dispatch(void);
+
+#define EVLOOP_ONCE 0x01
+#define EVLOOP_NONBLOCK 0x02
+int event_loop(int);
+
+int timeout_next(struct timeval *);
+void timeout_correct(struct timeval *);
+void timeout_process(void);
+
+#define evtimer_add(ev, tv) event_add(ev, tv)
+#define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
+#define evtimer_del(ev) event_del(ev)
+#define evtimer_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv)
+#define evtimer_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+
+#define timeout_add(ev, tv) event_add(ev, tv)
+#define timeout_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
+#define timeout_del(ev) event_del(ev)
+#define timeout_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv)
+#define timeout_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+
+#define signal_add(ev, tv) event_add(ev, tv)
+#define signal_set(ev, x, cb, arg) \
+ event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
+#define signal_del(ev) event_del(ev)
+#define signal_pending(ev, tv) event_pending(ev, EV_SIGNAL, tv)
+#define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+
+void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
+int event_add(struct event *, struct timeval *);
+int event_del(struct event *);
+void event_active(struct event *, int, short);
+
+int event_pending(struct event *, short, struct timeval *);
+
+#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVENT_H_ */
40 lib/libevent/evsignal.h
View
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niels Provos.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVSIGNAL_H_
+#define _EVSIGNAL_H_
+
+void evsignal_init(sigset_t *);
+void evsignal_process(void);
+int evsignal_recalc(sigset_t *);
+int evsignal_deliver(sigset_t *);
+int evsignal_add(sigset_t *, struct event *);
+int evsignal_del(sigset_t *, struct event *);
+
+#endif /* _EVSIGNAL_H_ */
376 lib/libevent/kqueue.c
View
@@ -0,0 +1,376 @@
+/* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */
+
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niels Provos.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_time.h>
+#endif
+#include <sys/queue.h>
+#include <sys/event.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <err.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef USE_LOG
+#include "log.h"
+#else
+#define LOG_DBG(x)
+#define log_error warn
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#define INTPTR(x) (intptr_t)x
+#else
+#define INTPTR(x) x
+#endif
+
+#include "event.h"
+
+extern struct event_list timequeue;
+extern struct event_list eventqueue;
+extern struct event_list addqueue;
+
+#define EVLIST_X_KQINKERNEL 0x1000
+
+#define NEVENT 64
+
+struct kqop {
+ struct kevent *changes;
+ int nchanges;
+ struct kevent *events;
+ int nevents;
+ int kq;
+} kqop;
+
+void *kq_init (void);
+int kq_add (void *, struct event *);
+int kq_del (void *, struct event *);
+int kq_recalc (void *, int);
+int kq_dispatch (void *, struct timeval *);
+
+struct eventop kqops = {
+ "kqueue",
+ kq_init,
+ kq_add,
+ kq_del,
+ kq_recalc,
+ kq_dispatch
+};
+
+void *
+kq_init(void)
+{
+ int kq;
+
+ /* Disable kqueue when this environment variable is set */
+ if (!issetugid() && getenv("EVENT_NOKQUEUE"))
+ return (NULL);
+
+ memset(&kqop, 0, sizeof(kqop));
+
+ /* Initalize the kernel queue */
+
+ if ((kq = kqueue()) == -1) {
+ log_error("kqueue");
+ return (NULL);
+ }
+
+ kqop.kq = kq;
+
+ /* Initalize fields */
+ kqop.changes = malloc(NEVENT * sizeof(struct kevent));
+ if (kqop.changes == NULL)
+ return (NULL);
+ kqop.events = malloc(NEVENT * sizeof(struct kevent));
+ if (kqop.events == NULL) {
+ free (kqop.changes);
+ return (NULL);
+ }
+ kqop.nevents = NEVENT;
+
+ return (&kqop);
+}
+
+int
+kq_recalc(void *arg, int max)
+{
+ return (0);
+}
+
+int
+kq_insert(struct kqop *kqop, struct kevent *kev)
+{
+ int nevents = kqop->nevents;
+
+ if (kqop->nchanges == nevents) {
+ struct kevent *newchange;
+ struct kevent *newresult;
+
+ nevents *= 2;
+
+ newchange = realloc(kqop->changes,
+ nevents * sizeof(struct kevent));
+ if (newchange == NULL) {
+ log_error("%s: malloc", __func__);
+ return (-1);
+ }
+ kqop->changes = newchange;
+
+ newresult = realloc(kqop->changes,
+ nevents * sizeof(struct kevent));
+
+ /*
+ * If we fail, we don't have to worry about freeing,
+ * the next realloc will pick it up.
+ */
+ if (newresult == NULL) {
+ log_error("%s: malloc", __func__);
+ return (-1);
+ }
+ kqop->events = newchange;
+
+ kqop->nevents = nevents;
+ }
+
+ memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
+
+ LOG_DBG((LOG_MISC, 70, "%s: fd %d %s%s",
+ __func__, kev->ident,
+ kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
+ kev->flags == EV_DELETE ? " (del)" : ""));
+
+ return (0);
+}
+
+static void
+kq_sighandler(int sig)
+{
+ /* Do nothing here */
+}
+
+int
+kq_dispatch(void *arg, struct timeval *tv)
+{
+ struct kqop *kqop = arg;
+ struct kevent *changes = kqop->changes;
+ struct kevent *events = kqop->events;
+ struct event *ev;
+ struct timespec ts;
+ int i, res;
+
+ TIMEVAL_TO_TIMESPEC(tv, &ts);
+
+ res = kevent(kqop->kq, changes, kqop->nchanges,
+ events, kqop->nevents, &ts);
+ kqop->nchanges = 0;
+ if (res == -1) {
+ if (errno != EINTR) {
+ log_error("kevent");
+ return (-1);
+ }
+
+ return (0);
+ }
+
+ LOG_DBG((LOG_MISC, 80, "%s: kevent reports %d", __func__, res));
+
+ for (i = 0; i < res; i++) {
+ int which = 0;
+
+ if (events[i].flags & EV_ERROR) {
+ /*
+ * Error messages that can happen, when a delete fails.
+ * EBADF happens when the file discriptor has been
+ * closed,
+ * ENOENT when the file discriptor was closed and
+ * then reopened.
+ * An error is also indicated when a callback deletes
+ * an event we are still processing. In that case
+ * the data field is set to ENOENT.
+ */
+ if (events[i].data == EBADF ||
+ events[i].data == ENOENT)
+ continue;
+ return (-1);
+ }
+
+ ev = (struct event *)events[i].udata;
+
+ if (events[i].filter == EVFILT_READ) {
+ which |= EV_READ;
+ } else if (events[i].filter == EVFILT_WRITE) {
+ which |= EV_WRITE;
+ } else if (events[i].filter == EVFILT_SIGNAL) {
+ which |= EV_SIGNAL;
+ }
+
+ if (!which)
+ continue;
+
+ if (!(ev->ev_events & EV_PERSIST)) {
+ ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+ event_del(ev);
+ }
+
+ event_active(ev, which,
+ ev->ev_events & EV_SIGNAL ? events[i].data : 1);
+ }
+
+ return (0);
+}
+
+
+int
+kq_add(void *arg, struct event *ev)
+{
+ struct kqop *kqop = arg;
+ struct kevent kev;
+
+ if (ev->ev_events & EV_SIGNAL) {
+ int nsignal = EVENT_SIGNAL(ev);
+
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = nsignal;
+ kev.filter = EVFILT_SIGNAL;
+ kev.flags = EV_ADD;
+ if (!(ev->ev_events & EV_PERSIST))
+ kev.flags |= EV_ONESHOT;
+ kev.udata = INTPTR(ev);
+
+ if (kq_insert(kqop, &kev) == -1)
+ return (-1);
+
+ if (signal(nsignal, kq_sighandler) == SIG_ERR)
+ return (-1);
+
+ ev->ev_flags |= EVLIST_X_KQINKERNEL;
+ return (0);
+ }
+
+ if (ev->ev_events & EV_READ) {
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = ev->ev_fd;
+ kev.filter = EVFILT_READ;
+ kev.flags = EV_ADD;
+ if (!(ev->ev_events & EV_PERSIST))
+ kev.flags |= EV_ONESHOT;
+ kev.udata = INTPTR(ev);
+
+ if (kq_insert(kqop, &kev) == -1)
+ return (-1);
+
+ ev->ev_flags |= EVLIST_X_KQINKERNEL;
+ }
+
+ if (ev->ev_events & EV_WRITE) {
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = ev->ev_fd;
+ kev.filter = EVFILT_WRITE;
+ kev.flags = EV_ADD;
+ if (!(ev->ev_events & EV_PERSIST))
+ kev.flags |= EV_ONESHOT;
+ kev.udata = INTPTR(ev);
+
+ if (kq_insert(kqop, &kev) == -1)
+ return (-1);
+
+ ev->ev_flags |= EVLIST_X_KQINKERNEL;
+ }
+
+ return (0);
+}
+
+int
+kq_del(void *arg, struct event *ev)
+{
+ struct kqop *kqop = arg;
+ struct kevent kev;
+
+ if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
+ return (0);
+
+ if (ev->ev_events & EV_SIGNAL) {
+ int nsignal = EVENT_SIGNAL(ev);
+
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = (int)signal;
+ kev.filter = EVFILT_SIGNAL;
+ kev.flags = EV_DELETE;
+
+ if (kq_insert(kqop, &kev) == -1)
+ return (-1);
+
+ if (signal(nsignal, SIG_DFL) == SIG_ERR)
+ return (-1);
+
+ ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+ return (0);
+ }
+
+ if (ev->ev_events & EV_READ) {
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = ev->ev_fd;
+ kev.filter = EVFILT_READ;
+ kev.flags = EV_DELETE;
+
+ if (kq_insert(kqop, &kev) == -1)
+ return (-1);
+
+ ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+ }
+
+ if (ev->ev_events & EV_WRITE) {
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = ev->ev_fd;
+ kev.filter = EVFILT_WRITE;
+ kev.flags = EV_DELETE;
+
+ if (kq_insert(kqop, &kev) == -1)
+ return (-1);
+
+ ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+ }
+
+ return (0);
+}
240 lib/libevent/poll.c
View
@@ -0,0 +1,240 @@
+/* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
+
+/*
+ * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niels Provos.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_time.h>
+#endif
+#include <sys/queue.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <err.h>
+
+#ifdef USE_LOG
+#include "log.h"
+#else
+#define LOG_DBG(x)
+#define log_error(x) perror(x)
+#endif
+
+#include "event.h"
+#include "evsignal.h"
+
+extern struct event_list eventqueue;
+
+extern volatile sig_atomic_t evsignal_caught;
+
+struct pollop {
+ int event_count; /* Highest number alloc */
+ struct pollfd *event_set;
+ struct event **event_back;
+ sigset_t evsigmask;
+} pop;
+
+void *poll_init (void);
+int poll_add (void *, struct event *);
+int poll_del (void *, struct event *);
+int poll_recalc (void *, int);
+int poll_dispatch (void *, struct timeval *);
+
+struct eventop pollops = {
+ "poll",
+ poll_init,
+ poll_add,
+ poll_del,
+ poll_recalc,
+ poll_dispatch
+};
+
+void *
+poll_init(void)
+{
+ /* Disable kqueue when this environment variable is set */
+ if (!issetugid() && getenv("EVENT_NOPOLL"))
+ return (NULL);
+
+ memset(&pop, 0, sizeof(pop));
+
+ evsignal_init(&pop.evsigmask);
+
+ return (&pop);
+}
+
+/*
+ * Called with the highest fd that we know about. If it is 0, completely
+ * recalculate everything.
+ */
+
+int
+poll_recalc(void *arg, int max)
+{
+ struct pollop *pop = arg;
+
+ return (evsignal_recalc(&pop->evsigmask));
+}
+
+int
+poll_dispatch(void *arg, struct timeval *tv)
+{
+ int res, i, count, sec, nfds;
+ struct event *ev;
+ struct pollop *pop = arg;
+
+ count = pop->event_count;
+ nfds = 0;
+ TAILQ_FOREACH(ev, &eventqueue, ev_next) {
+ if (nfds + 1 >= count) {
+ if (count < 32)
+ count = 32;
+ else
+ count *= 2;
+
+ /* We need more file descriptors */
+ pop->event_set = realloc(pop->event_set,
+ count * sizeof(struct pollfd));
+ if (pop->event_set == NULL) {
+ log_error("realloc");
+ return (-1);
+ }
+ pop->event_back = realloc(pop->event_back,
+ count * sizeof(struct event *));
+ if (pop->event_back == NULL) {
+ log_error("realloc");
+ return (-1);
+ }
+ pop->event_count = count;
+ }
+ if (ev->ev_events & EV_WRITE) {
+ struct pollfd *pfd = &pop->event_set[nfds];
+ pfd->fd = ev->ev_fd;
+ pfd->events = POLLOUT;
+ pfd->revents = 0;
+
+ pop->event_back[nfds] = ev;
+
+ nfds++;
+ }
+ if (ev->ev_events & EV_READ) {
+ struct pollfd *pfd = &pop->event_set[nfds];
+
+ pfd->fd = ev->ev_fd;
+ pfd->events = POLLIN;
+ pfd->revents = 0;
+
+ pop->event_back[nfds] = ev;
+
+ nfds++;
+ }
+ }
+
+ if (evsignal_deliver(&pop->evsigmask) == -1)
+ return (-1);
+
+ sec = tv->tv_sec * 1000 + tv->tv_usec / 1000;
+ res = poll(pop->event_set, nfds, sec);
+
+ if (evsignal_recalc(&pop->evsigmask) == -1)
+ return (-1);
+
+ if (res == -1) {
+ if (errno != EINTR) {
+ log_error("poll");
+ return (-1);
+ }
+
+ evsignal_process();
+ return (0);
+ } else if (evsignal_caught)
+ evsignal_process();
+
+ LOG_DBG((LOG_MISC, 80, "%s: poll reports %d", __func__, res));
+
+ if (res == 0)
+ return (0);
+
+ for (i = 0; i < nfds; i++) {
+ res = 0;
+ if (pop->event_set[i].revents & POLLIN)
+ res = EV_READ;
+ else if (pop->event_set[i].revents & POLLOUT)
+ res = EV_WRITE;
+ if (res == 0)
+ continue;
+
+ ev = pop->event_back[i];
+ res &= ev->ev_events;
+
+ if (res) {
+ if (!(ev->ev_events & EV_PERSIST))
+ event_del(ev);
+ event_active(ev, res, 1);
+ }
+ }
+
+ return (0);
+}
+
+int
+poll_add(void *arg, struct event *ev)
+{
+ struct pollop *pop = arg;
+
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_add(&pop->evsigmask, ev));
+
+ return (0);
+}
+
+/*
+ * Nothing to be done here.
+ */
+
+int
+poll_del(void *arg, struct event *ev)
+{
+ struct pollop *pop = arg;
+
+ if (!(ev->ev_events & EV_SIGNAL))
+ return (0);
+
+ return (evsignal_del(&pop->evsigmask, ev));
+}
5 lib/libevent/shlib_version
View
@@ -0,0 +1,5 @@
+# $NetBSD: shlib_version,v 1.1.1.1 2003/06/12 22:54:26 provos Exp $
+# Remember to update distrib/sets/lists/base/shl.* when changing
+#
+major=0
+minor=1
164 lib/libevent/signal.c
View
@@ -0,0 +1,164 @@
+/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
+
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niels Provos.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_time.h>
+#endif
+#include <sys/queue.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <err.h>
+
+#ifdef USE_LOG
+#include "log.h"
+#else
+#define LOG_DBG(x)
+#define log_error(x) perror(x)
+#endif
+
+#include "event.h"
+
+extern struct event_list signalqueue;
+
+static short evsigcaught[NSIG];
+static int needrecalc;
+volatile sig_atomic_t evsignal_caught = 0;
+
+void evsignal_process(void);
+int evsignal_recalc(sigset_t *);
+int evsignal_deliver(sigset_t *);
+
+void
+evsignal_init(sigset_t *evsigmask)
+{
+ sigemptyset(evsigmask);
+}
+
+int
+evsignal_add(sigset_t *evsigmask, struct event *ev)
+{
+ int signal;
+
+ if (ev->ev_events & (EV_READ|EV_WRITE))
+ errx(1, "%s: EV_SIGNAL incompatible use", __func__);
+ signal = EVENT_SIGNAL(ev);
+ sigaddset(evsigmask, signal);
+
+ return (0);
+}
+
+/*
+ * Nothing to be done here.
+ */
+
+int
+evsignal_del(sigset_t *evsigmask, struct event *ev)
+{
+ int signal;
+
+ signal = EVENT_SIGNAL(ev);
+ sigdelset(evsigmask, signal);
+ needrecalc = 1;
+
+ return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL));
+}
+
+static void
+evsignal_handler(int sig)
+{
+ evsigcaught[sig]++;
+ evsignal_caught = 1;
+}
+
+int
+evsignal_recalc(sigset_t *evsigmask)
+{
+ struct sigaction sa;
+ struct event *ev;
+
+ if (TAILQ_FIRST(&signalqueue) == NULL && !needrecalc)
+ return (0);
+ needrecalc = 0;
+
+ if (sigprocmask(SIG_BLOCK, evsigmask, NULL) == -1)
+ return (-1);
+
+ /* Reinstall our signal handler. */
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = evsignal_handler;
+ sa.sa_mask = *evsigmask;
+ sa.sa_flags |= SA_RESTART;
+
+ TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
+ if (sigaction(EVENT_SIGNAL(ev), &sa, NULL) == -1)
+ return (-1);
+ }
+ return (0);
+}
+
+int
+evsignal_deliver(sigset_t *evsigmask)
+{
+ if (TAILQ_FIRST(&signalqueue) == NULL)
+ return (0);
+
+ return (sigprocmask(SIG_UNBLOCK, evsigmask, NULL));
+ /* XXX - pending signals handled here */
+}
+
+void
+evsignal_process(void)
+{
+ struct event *ev;
+ short ncalls;
+
+ TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
+ ncalls = evsigcaught[EVENT_SIGNAL(ev)];
+ if (ncalls) {
+ if (!(ev->ev_events & EV_PERSIST))
+ event_del(ev);
+ event_active(ev, EV_SIGNAL, ncalls);
+ }
+ }
+
+ memset(evsigcaught, 0, sizeof(evsigcaught));
+ evsignal_caught = 0;
+}
+
Please sign in to comment.
Something went wrong with that request. Please try again.