mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-17 16:29:28 -04:00
Initial revision
svn:r2
This commit is contained in:
commit
aa6567fe64
55
acconfig.h
Normal file
55
acconfig.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* Define if kqueue works correctly with pipes */
|
||||
#undef HAVE_WORKING_KQUEUE
|
||||
|
||||
/* 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> */
|
||||
#undef HAVE_TIMERADD
|
||||
#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> */
|
||||
#undef HAVE_TAILQFOREACH
|
||||
#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 */
|
117
configure.in
Normal file
117
configure.in
Normal file
@ -0,0 +1,117 @@
|
||||
dnl configure.in for libevent
|
||||
dnl Dug Song <dugsong@monkey.org>
|
||||
AC_INIT(event.c)
|
||||
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
||||
dnl Initialize prefix.
|
||||
if test "$prefix" = "NONE"; then
|
||||
prefix="/usr/local"
|
||||
fi
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
|
||||
dnl Checks for libraries.
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(unistd.h sys/time.h sys/queue.h sys/event.h)
|
||||
if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
|
||||
AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
|
||||
AC_EGREP_CPP(yes,
|
||||
[
|
||||
#include <sys/queue.h>
|
||||
#ifdef TAILQ_FOREACH
|
||||
yes
|
||||
#endif
|
||||
], [AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_TAILQFOREACH) ], AC_MSG_RESULT(no)
|
||||
)
|
||||
fi
|
||||
|
||||
if test "x$ac_cv_header_sys_time_h" = "xyes"; then
|
||||
AC_MSG_CHECKING(for timeradd in sys/time.h)
|
||||
AC_EGREP_CPP(yes,
|
||||
[
|
||||
#include <sys/time.h>
|
||||
#ifdef timeradd
|
||||
yes
|
||||
#endif
|
||||
], [ AC_DEFINE(HAVE_TIMERADD)
|
||||
AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
|
||||
)
|
||||
fi
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_HEADER_TIME
|
||||
|
||||
dnl Checks for library functions.
|
||||
AC_CHECK_FUNCS(gettimeofday)
|
||||
|
||||
AC_SUBST(EVSRCS)
|
||||
AC_CHECK_FUNCS(select, [haveselect=yes], )
|
||||
if test "x$haveselect" = "xyes" ; then
|
||||
EVSRCS="select.c"
|
||||
fi
|
||||
|
||||
havekqueue=no
|
||||
if test "x$ac_cv_header_sys_event_h" = "xyes"; then
|
||||
AC_CHECK_FUNCS(kqueue, [havekqueue=yes], )
|
||||
if test "x$havekqueue" = "xyes" ; then
|
||||
AC_MSG_CHECKING(for working kqueue)
|
||||
AC_TRY_RUN(
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/event.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int kq;
|
||||
int n;
|
||||
int fd[[2]];
|
||||
struct kevent ev;
|
||||
struct timespec ts;
|
||||
char buf[[8000]];
|
||||
|
||||
if (pipe(fd) == -1)
|
||||
exit(1);
|
||||
if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1)
|
||||
exit(1);
|
||||
|
||||
while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf))
|
||||
;
|
||||
|
||||
if ((kq = kqueue()) == -1)
|
||||
exit(1);
|
||||
|
||||
ev.ident = fd[[1]];
|
||||
ev.filter = EVFILT_WRITE;
|
||||
ev.flags = EV_ADD | EV_ENABLE;
|
||||
n = kevent(kq, &ev, 1, NULL, 0, NULL);
|
||||
if (n == -1)
|
||||
exit(1);
|
||||
|
||||
read(fd[[0]], buf, sizeof(buf));
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
n = kevent(kq, NULL, 0, &ev, 1, &ts);
|
||||
if (n == -1 || n == 0)
|
||||
exit(1);
|
||||
|
||||
exit(0);
|
||||
}, [AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_WORKING_KQUEUE)
|
||||
EVSRCS="$EVSRCS kqueue.c"], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_OUTPUT(Makefile test/Makefile)
|
268
event.3
Normal file
268
event.3
Normal file
@ -0,0 +1,268 @@
|
||||
.\" $OpenBSD: timeout.9,v 1.11 2000/10/12 18:06:03 aaron 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 June 23, 1996
|
||||
.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_initalized ,
|
||||
.Nm timeout_set ,
|
||||
.Nm timeout_add ,
|
||||
.Nm timeout_del
|
||||
.Nm timeout_pending ,
|
||||
.Nm timeout_initalized ,
|
||||
.Nd execute a function when a specific event occurs
|
||||
.Sh SYNOPSIS
|
||||
.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 "timeout_set" "struct event *ev" "void (*fn)(int, short, void *)" "void *arg"
|
||||
.Ft void
|
||||
.Fn "timeout_add" "struct event *ev" "struct timeval *"
|
||||
.Ft void
|
||||
.Fn "timeout_del" "struct event *ev"
|
||||
.Ft int
|
||||
.Fn "timeout_pending" "struct event *ev" "struct timeval *tv"
|
||||
.Ft int
|
||||
.Fn "timeout_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 at a given time has passed.
|
||||
.Pp
|
||||
The
|
||||
.Nm event
|
||||
API needs to be initalized with
|
||||
.Fn event_init
|
||||
before it can be used.
|
||||
.Pp
|
||||
In order to process events, an application needs to call
|
||||
.Fn event_dispatch .
|
||||
This functions 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, with 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_READ ,
|
||||
or
|
||||
.Va EV_WRITE .
|
||||
.Pp
|
||||
Once initialized, the
|
||||
.Fa ev
|
||||
structure can be used in repeatedly in
|
||||
.Fn event_add
|
||||
and
|
||||
.Fn event_del
|
||||
and does not need to be reinitialized unless you wish to
|
||||
change the function called and/or the argument to it.
|
||||
.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 has already 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 timeout_set ,
|
||||
.Fn timeout_add ,
|
||||
.Fn timeout_del ,
|
||||
.Fn timeout_initialized ,
|
||||
and
|
||||
.Fn timeout_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
|
||||
It is possible to disable support for
|
||||
.Va kqueue
|
||||
but setting the environment variable
|
||||
.Va EVENT_NOKQUEUE .
|
||||
.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.
|
454
event.c
Normal file
454
event.c
Normal file
@ -0,0 +1,454 @@
|
||||
/*
|
||||
* 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>
|
||||
#include <sys/tree.h>
|
||||
#include <sys/time.h>
|
||||
#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_WORKING_KQUEUE
|
||||
extern struct eventop kqops;
|
||||
#endif
|
||||
|
||||
/* In order of preference */
|
||||
struct eventop *eventops[] = {
|
||||
#ifdef HAVE_WORKING_KQUEUE
|
||||
&kqops,
|
||||
#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 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);
|
||||
|
||||
evbase = NULL;
|
||||
for (i = 0; eventops[i] && !evbase; i++) {
|
||||
evsel = eventops[i];
|
||||
|
||||
evbase = evsel->init();
|
||||
}
|
||||
|
||||
#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(&activequeue));
|
||||
}
|
||||
|
||||
void
|
||||
event_process_active(void)
|
||||
{
|
||||
struct event *ev;
|
||||
|
||||
for (ev = TAILQ_FIRST(&activequeue); ev;
|
||||
ev = TAILQ_FIRST(&activequeue)) {
|
||||
event_queue_remove(ev, EVLIST_ACTIVE);
|
||||
|
||||
(*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",
|
||||
__FUNCTION__));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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));
|
||||
if (ev->ev_flags & EVLIST_TIMEOUT)
|
||||
event_queue_remove(ev, EVLIST_TIMEOUT);
|
||||
|
||||
event_queue_insert(ev, EVLIST_TIMEOUT);
|
||||
}
|
||||
|
||||
if ((ev->ev_events & (EV_READ|EV_WRITE)) &&
|
||||
!(ev->ev_flags & EVLIST_INSERTED)) {
|
||||
event_queue_insert(ev, EVLIST_INSERTED);
|
||||
|
||||
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));
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
event_active(struct event *ev, int res)
|
||||
{
|
||||
ev->ev_res = res;
|
||||
event_queue_insert(ev, EVLIST_ACTIVE);
|
||||
}
|
||||
|
||||
int
|
||||
timeout_next(struct timeval *tv)
|
||||
{
|
||||
struct timeval now;
|
||||
struct event *ev;
|
||||
|
||||
if ((ev = RB_MIN(event_tree, &timetree)) == NULL) {
|
||||
timerclear(tv);
|
||||
tv->tv_sec = TIMEOUT_DEFAULT;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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", __FUNCTION__,
|
||||
ev, ev->ev_fd, queue);
|
||||
|
||||
ev->ev_flags &= ~queue;
|
||||
switch (queue) {
|
||||
case EVLIST_ACTIVE:
|
||||
TAILQ_REMOVE(&activequeue, ev, ev_active_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", __FUNCTION__, 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", __FUNCTION__,
|
||||
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_TIMEOUT:
|
||||
timeout_insert(ev);
|
||||
break;
|
||||
case EVLIST_INSERTED:
|
||||
TAILQ_INSERT_TAIL(&eventqueue, ev, ev_next);
|
||||
break;
|
||||
default:
|
||||
errx(1, "%s: unknown queue %x", __FUNCTION__, queue);
|
||||
}
|
||||
}
|
138
event.h
Normal file
138
event.h
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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_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
|
||||
|
||||
/* 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;
|
||||
RB_ENTRY (event) ev_timeout_node;
|
||||
|
||||
int ev_fd;
|
||||
short ev_events;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
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 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)
|
||||
|
||||
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);
|
||||
|
||||
int event_pending(struct event *, short, struct timeval *);
|
||||
|
||||
#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVENT_H_ */
|
238
install-sh
Executable file
238
install-sh
Executable file
@ -0,0 +1,238 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
#
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
tranformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
300
kqueue.c
Normal file
300
kqueue.c
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* 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>
|
||||
#include <sys/time.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/event.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.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 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 (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(__FUNCTION__": malloc");
|
||||
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(__FUNCTION__": malloc");
|
||||
return (-1);
|
||||
}
|
||||
kqop->events = newchange;
|
||||
|
||||
kqop->nevents = nevents;
|
||||
}
|
||||
|
||||
memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
|
||||
|
||||
LOG_DBG((LOG_MISC, 70, __FUNCTION__": fd %d %s%s",
|
||||
kev->ident,
|
||||
kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
|
||||
kev->flags == EV_DELETE ? " (del)" : ""));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
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, __FUNCTION__": kevent reports %d", 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 = events[i].udata;
|
||||
|
||||
if (events[i].filter == EVFILT_READ) {
|
||||
which |= EV_READ;
|
||||
} else if (events[i].filter == EVFILT_WRITE) {
|
||||
which |= EV_WRITE;
|
||||
}
|
||||
|
||||
if (which) {
|
||||
ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
|
||||
event_del(ev);
|
||||
event_active(ev, which);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
kq_add(void *arg, struct event *ev)
|
||||
{
|
||||
struct kqop *kqop = arg;
|
||||
struct kevent kev;
|
||||
|
||||
if (ev->ev_events & EV_READ) {
|
||||
memset(&kev, 0, sizeof(kev));
|
||||
kev.ident = ev->ev_fd;
|
||||
kev.filter = EVFILT_READ;
|
||||
kev.flags = EV_ADD | EV_ONESHOT;
|
||||
kev.udata = 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 | EV_ONESHOT;
|
||||
kev.udata = 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_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);
|
||||
}
|
94
sample/event-test.c
Normal file
94
sample/event-test.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Compile with:
|
||||
* cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <event.h>
|
||||
|
||||
void
|
||||
fifo_read(int fd, short event, void *arg)
|
||||
{
|
||||
char buf[255];
|
||||
int len;
|
||||
struct event *ev = arg;
|
||||
|
||||
/* Reschedule this event */
|
||||
event_add(ev, NULL);
|
||||
|
||||
fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n",
|
||||
fd, event, arg);
|
||||
|
||||
len = read(fd, buf, sizeof(buf) - 1);
|
||||
if (len == -1) {
|
||||
perror("read");
|
||||
return;
|
||||
} else if (len == 0) {
|
||||
fprintf(stderr, "Connection closed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
fprintf(stdout, "Read: %s\n", buf);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
struct stat st;
|
||||
char *fifo = "event.fifo";
|
||||
int socket;
|
||||
struct event evfifo;
|
||||
|
||||
if (lstat (fifo, &st) == 0) {
|
||||
if ((st.st_mode & S_IFMT) == S_IFREG) {
|
||||
errno = EEXIST;
|
||||
perror("lstat");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
unlink (fifo);
|
||||
if (mkfifo (fifo, 0600) == -1) {
|
||||
perror("mkfifo");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */
|
||||
#ifdef __linux
|
||||
socket = open (fifo, O_RDWR | O_NONBLOCK, 0);
|
||||
#else
|
||||
socket = open (fifo, O_RDONLY | O_NONBLOCK, 0);
|
||||
#endif
|
||||
|
||||
if (socket == -1) {
|
||||
perror("open");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Write data to %s\n", fifo);
|
||||
|
||||
/* Initalize the event library */
|
||||
event_init();
|
||||
|
||||
/* Initalize one event */
|
||||
event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo);
|
||||
|
||||
/* Add it to the active events, without a timeout */
|
||||
event_add(&evfifo, NULL);
|
||||
|
||||
event_dispatch();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
59
sample/time-test.c
Normal file
59
sample/time-test.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Compile with:
|
||||
* cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <event.h>
|
||||
|
||||
int lasttime;
|
||||
|
||||
void
|
||||
timeout_cb(int fd, short event, void *arg)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct event *timeout = arg;
|
||||
int newtime = time(NULL);
|
||||
|
||||
printf("%s: called at %d: %d\n", __FUNCTION__, newtime,
|
||||
newtime - lasttime);
|
||||
lasttime = newtime;
|
||||
|
||||
timerclear(&tv);
|
||||
tv.tv_sec = 2;
|
||||
event_add(timeout, &tv);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
struct event timeout;
|
||||
struct timeval tv;
|
||||
|
||||
/* Initalize the event library */
|
||||
event_init();
|
||||
|
||||
/* Initalize one event */
|
||||
timeout_set(&timeout, timeout_cb, &timeout);
|
||||
|
||||
timerclear(&tv);
|
||||
tv.tv_sec = 2;
|
||||
event_add(&timeout, &tv);
|
||||
|
||||
lasttime = time(NULL);
|
||||
|
||||
event_dispatch();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
213
select.c
Normal file
213
select.c
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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>
|
||||
#include <sys/time.h>
|
||||
#include <sys/queue.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.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 timequeue;
|
||||
extern struct event_list eventqueue;
|
||||
extern struct event_list addqueue;
|
||||
|
||||
#ifndef howmany
|
||||
#define howmany(x, y) (((x)+((y)-1))/(y))
|
||||
#endif
|
||||
|
||||
struct selectop {
|
||||
int event_fds; /* Highest fd in fd set */
|
||||
int event_fdsz;
|
||||
fd_set *event_readset;
|
||||
fd_set *event_writeset;
|
||||
} sop;
|
||||
|
||||
void *select_init (void);
|
||||
int select_add (void *, struct event *);
|
||||
int select_del (void *, struct event *);
|
||||
int select_recalc (void *, int);
|
||||
int select_dispatch (void *, struct timeval *);
|
||||
|
||||
struct eventop selectops = {
|
||||
"select",
|
||||
select_init,
|
||||
select_add,
|
||||
select_del,
|
||||
select_recalc,
|
||||
select_dispatch
|
||||
};
|
||||
|
||||
void *
|
||||
select_init(void)
|
||||
{
|
||||
memset(&sop, 0, sizeof(sop));
|
||||
|
||||
return (&sop);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called with the highest fd that we know about. If it is 0, completely
|
||||
* recalculate everything.
|
||||
*/
|
||||
|
||||
int
|
||||
select_recalc(void *arg, int max)
|
||||
{
|
||||
struct selectop *sop = arg;
|
||||
fd_set *readset, *writeset;
|
||||
struct event *ev;
|
||||
int fdsz;
|
||||
|
||||
if (sop->event_fds < max)
|
||||
sop->event_fds = max;
|
||||
|
||||
if (!sop->event_fds) {
|
||||
TAILQ_FOREACH(ev, &eventqueue, ev_next)
|
||||
if (ev->ev_fd > sop->event_fds)
|
||||
sop->event_fds = ev->ev_fd;
|
||||
}
|
||||
|
||||
fdsz = howmany(sop->event_fds + 1, NFDBITS) * sizeof(fd_mask);
|
||||
if (fdsz > sop->event_fdsz) {
|
||||
if ((readset = realloc(sop->event_readset, fdsz)) == NULL) {
|
||||
log_error("malloc");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((writeset = realloc(sop->event_writeset, fdsz)) == NULL) {
|
||||
log_error("malloc");
|
||||
free(readset);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memset((char *)readset + sop->event_fdsz, 0,
|
||||
fdsz - sop->event_fdsz);
|
||||
memset((char *)writeset + sop->event_fdsz, 0,
|
||||
fdsz - sop->event_fdsz);
|
||||
|
||||
sop->event_readset = readset;
|
||||
sop->event_writeset = writeset;
|
||||
sop->event_fdsz = fdsz;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
select_dispatch(void *arg, struct timeval *tv)
|
||||
{
|
||||
int maxfd, res;
|
||||
struct event *ev, *next;
|
||||
struct selectop *sop = arg;
|
||||
|
||||
memset(sop->event_readset, 0, sop->event_fdsz);
|
||||
memset(sop->event_writeset, 0, sop->event_fdsz);
|
||||
|
||||
TAILQ_FOREACH(ev, &eventqueue, ev_next) {
|
||||
if (ev->ev_events & EV_WRITE)
|
||||
FD_SET(ev->ev_fd, sop->event_writeset);
|
||||
if (ev->ev_events & EV_READ)
|
||||
FD_SET(ev->ev_fd, sop->event_readset);
|
||||
}
|
||||
|
||||
|
||||
if ((res = select(sop->event_fds + 1, sop->event_readset,
|
||||
sop->event_writeset, NULL, tv)) == -1) {
|
||||
if (errno != EINTR) {
|
||||
log_error("select");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
LOG_DBG((LOG_MISC, 80, __FUNCTION__": select reports %d",
|
||||
res));
|
||||
|
||||
maxfd = 0;
|
||||
for (ev = TAILQ_FIRST(&eventqueue); ev != NULL; ev = next) {
|
||||
next = TAILQ_NEXT(ev, ev_next);
|
||||
|
||||
res = 0;
|
||||
if (FD_ISSET(ev->ev_fd, sop->event_readset))
|
||||
res |= EV_READ;
|
||||
if (FD_ISSET(ev->ev_fd, sop->event_writeset))
|
||||
res |= EV_WRITE;
|
||||
res &= ev->ev_events;
|
||||
|
||||
if (res) {
|
||||
event_del(ev);
|
||||
event_active(ev, res);
|
||||
} else if (ev->ev_fd > maxfd)
|
||||
maxfd = ev->ev_fd;
|
||||
}
|
||||
|
||||
sop->event_fds = maxfd;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
select_add(void *arg, struct event *ev)
|
||||
{
|
||||
struct selectop *sop = arg;
|
||||
|
||||
/*
|
||||
* Keep track of the highest fd, so that we can calculate the size
|
||||
* of the fd_sets for select(2)
|
||||
*/
|
||||
if (sop->event_fds < ev->ev_fd)
|
||||
sop->event_fds = ev->ev_fd;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Nothing to be done here.
|
||||
*/
|
||||
|
||||
int
|
||||
select_del(void *arg, struct event *ev)
|
||||
{
|
||||
return (0);
|
||||
}
|
69
test/test-eof.c
Normal file
69
test/test-eof.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Compile with:
|
||||
* cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <event.h>
|
||||
|
||||
int test_okay = 1;
|
||||
int called = 0;
|
||||
|
||||
void
|
||||
read_cb(int fd, short event, void *arg)
|
||||
{
|
||||
char buf[256];
|
||||
int len;
|
||||
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
|
||||
printf("%s: read %d%s\n", __FUNCTION__,
|
||||
len, len ? "" : " - means EOF");
|
||||
|
||||
if (len) {
|
||||
if (!called)
|
||||
event_add(arg, NULL);
|
||||
} else if (called == 1)
|
||||
test_okay = 0;
|
||||
|
||||
called++;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
struct event ev;
|
||||
char *test = "test string";
|
||||
int pair[2];
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
|
||||
return (1);
|
||||
|
||||
|
||||
write(pair[0], test, strlen(test)+1);
|
||||
shutdown(pair[0], SHUT_WR);
|
||||
|
||||
/* Initalize the event library */
|
||||
event_init();
|
||||
|
||||
/* Initalize one event */
|
||||
event_set(&ev, pair[1], EV_READ, read_cb, &ev);
|
||||
|
||||
event_add(&ev, NULL);
|
||||
|
||||
event_dispatch();
|
||||
|
||||
return (test_okay);
|
||||
}
|
||||
|
69
test/test-weof.c
Normal file
69
test/test-weof.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Compile with:
|
||||
* cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <event.h>
|
||||
|
||||
int pair[2];
|
||||
int test_okay = 1;
|
||||
int called = 0;
|
||||
|
||||
void
|
||||
write_cb(int fd, short event, void *arg)
|
||||
{
|
||||
char *test = "test string";
|
||||
int len;
|
||||
|
||||
len = write(fd, test, strlen(test) + 1);
|
||||
|
||||
printf("%s: write %d%s\n", __FUNCTION__,
|
||||
len, len ? "" : " - means EOF");
|
||||
|
||||
if (len > 0) {
|
||||
if (!called)
|
||||
event_add(arg, NULL);
|
||||
close(pair[0]);
|
||||
} else if (called == 1):
|
||||
test_okay = 0;
|
||||
|
||||
called++;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
struct event ev;
|
||||
|
||||
if (signal(SIGPIPE, SIG_IGN) == SIG_IGN)
|
||||
return (1);
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
|
||||
return (1);
|
||||
|
||||
/* Initalize the event library */
|
||||
event_init();
|
||||
|
||||
/* Initalize one event */
|
||||
event_set(&ev, pair[1], EV_WRITE, write_cb, &ev);
|
||||
|
||||
event_add(&ev, NULL);
|
||||
|
||||
event_dispatch();
|
||||
|
||||
return (test_okay);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user