new event_once interface; start of buffering interface for buffered events

svn:r93
This commit is contained in:
Niels Provos 2004-02-22 21:17:23 +00:00
parent 1b974101b9
commit ec2c1db47e
6 changed files with 267 additions and 5 deletions

View File

@ -21,7 +21,7 @@ EXTRA_DIST = acconfig.h err.c event.h evsignal.h event.3 kqueue.c \
lib_LIBRARIES = libevent.a lib_LIBRARIES = libevent.a
libevent_a_SOURCES = event.c libevent_a_SOURCES = event.c buffer.c
libevent_a_LIBADD = @LIBOBJS@ libevent_a_LIBADD = @LIBOBJS@
include_HEADERS = event.h include_HEADERS = event.h

165
buffer.c Normal file
View File

@ -0,0 +1,165 @@
/*
* Copyright 2002, 2003 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
*/
#include <sys/param.h>
#include <sys/types.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
#include <unistd.h>
#undef timeout_pending
#undef timeout_initialized
#include <event.h>
#include "event.h"
extern int debug;
struct evbuffer *
evbuffer_new(void)
{
struct evbuffer *buffer;
if ((buffer = calloc(1, sizeof(struct evbuffer))) == NULL)
err(1, "%s: calloc", __func__);
return (buffer);
}
void
evbuffer_free(struct evbuffer *buffer)
{
if (buffer->buffer != NULL)
free(buffer->buffer);
free(buffer);
}
void
evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
{
evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
evbuffer_drain(inbuf, inbuf->off);
}
int
evbuffer_add_printf(struct evbuffer *buf, char *fmt, ...)
{
int res = -1;
char *msg;
va_list ap;
va_start(ap, fmt);
if (vasprintf(&msg, fmt, ap) == -1)
goto end;
res = strlen(msg);
evbuffer_add(buf, msg, res);
free(msg);
end:
va_end(ap);
return (res);
}
void
evbuffer_add(struct evbuffer *buf, u_char *data, size_t datlen)
{
size_t need = buf->off + datlen;
if (buf->totallen < need) {
if ((buf->buffer = realloc(buf->buffer, need)) == NULL)
err(1, "%s: realloc", __func__);
buf->totallen = need;
}
memcpy(buf->buffer + buf->off, data, datlen);
buf->off += datlen;
}
void
evbuffer_drain(struct evbuffer *buf, size_t len)
{
if (len >= buf->off) {
buf->off = 0;
return;
}
memmove(buf->buffer, buf->buffer + len, buf->off - len);
buf->off -= len;
}
int
evbuffer_read(struct evbuffer *buffer, int fd, int howmuch)
{
u_char inbuf[4096];
int n;
if (howmuch < 0 || howmuch > sizeof(inbuf))
howmuch = sizeof(inbuf);
n = read(fd, inbuf, howmuch);
if (n == -1)
return (-1);
if (n == 0)
return (0);
evbuffer_add(buffer, inbuf, n);
return (n);
}
int
evbuffer_write(struct evbuffer *buffer, int fd)
{
int n;
n = write(fd, buffer->buffer, buffer->off);
if (n == -1)
return (-1);
if (n == 0)
return (0);
evbuffer_drain(buffer, n);
return (n);
}
u_char *
evbuffer_find(struct evbuffer *buffer, u_char *what, size_t len)
{
size_t remain = buffer->off;
u_char *search = buffer->buffer;
u_char *p;
while ((p = memchr(search, *what, remain)) != NULL && remain >= len) {
if (memcmp(p, what, len) == 0)
return (p);
search = p + 1;
remain = buffer->off - (size_t)(search - buffer->buffer);
}
return (NULL);
}

View File

@ -2,7 +2,7 @@ dnl configure.in for libevent
dnl Dug Song <dugsong@monkey.org> dnl Dug Song <dugsong@monkey.org>
AC_INIT(event.c) AC_INIT(event.c)
AM_INIT_AUTOMAKE(libevent,0.7b) AM_INIT_AUTOMAKE(libevent,0.7c)
AM_CONFIG_HEADER(config.h) AM_CONFIG_HEADER(config.h)
AM_MAINTAINER_MODE AM_MAINTAINER_MODE
@ -27,7 +27,7 @@ AC_CHECK_LIB(socket, socket)
dnl Checks for header files. dnl Checks for header files.
AC_HEADER_STDC AC_HEADER_STDC
AC_CHECK_HEADERS(inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h) AC_CHECK_HEADERS(stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h)
if test "x$ac_cv_header_sys_queue_h" = "xyes"; then if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h) AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
AC_EGREP_CPP(yes, AC_EGREP_CPP(yes,

17
event.3
View File

@ -36,6 +36,7 @@
.Nm event_set , .Nm event_set ,
.Nm event_add , .Nm event_add ,
.Nm event_del , .Nm event_del ,
.Nm event_once ,
.Nm event_pending , .Nm event_pending ,
.Nm event_initialized , .Nm event_initialized ,
.Nm evtimer_set , .Nm evtimer_set ,
@ -65,6 +66,8 @@
.Ft int .Ft int
.Fn "event_del" "struct event *ev" .Fn "event_del" "struct event *ev"
.Ft int .Ft int
.Fn "event_once" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv"
.Ft int
.Fn "event_pending" "struct event *ev" "short event" "struct timeval *tv" .Fn "event_pending" "struct event *ev" "short event" "struct timeval *tv"
.Ft int .Ft int
.Fn "event_initialized" "struct event *ev" .Fn "event_initialized" "struct event *ev"
@ -234,6 +237,20 @@ will cancel the event in the argument
If the event has already executed or has never been added If the event has already executed or has never been added
the call will have no effect. the call will have no effect.
.Pp .Pp
The function
.Fn event_once
is similiar to
.Fn event_set .
However, it schedules a callback to be called exactly once and does not
require the caller to prepare an
.Fa event
structure.
This function supports
.Fa EV_TIMEOUT ,
.Fa EV_READ
and
.Fa EV_WRITE .
.Pp
The The
.Fn event_pending .Fn event_pending
function can be used to check if the event specified by function can be used to check if the event specified by

59
event.c
View File

@ -273,6 +273,62 @@ event_loop(int flags)
return (0); return (0);
} }
/* Sets up an event for processing once */
struct event_once {
struct event ev;
void (*cb)(int, short, void *);
void *arg;
};
/* One-time callback, it deletes itself */
static void
event_once_cb(int fd, short events, void *arg)
{
struct event_once *eonce = arg;
(*eonce->cb)(fd, events, eonce->arg);
free(eonce);
}
/* Schedules an event once */
int
event_once(int fd, short events,
void (*callback)(int, short, void *), void *arg, struct timeval *tv)
{
struct event_once *eonce;
struct timeval etv;
if ((eonce = calloc(1, sizeof(struct event_once))) == NULL)
return (-1);
if (events == EV_TIMEOUT) {
if (tv == NULL) {
timerclear(&etv);
tv = &etv;
}
eonce->cb = callback;
eonce->arg = arg;
evtimer_set(&eonce->ev, event_once_cb, &eonce);
} else if (events & (EV_READ|EV_WRITE)) {
events &= EV_READ|EV_WRITE;
event_set(&eonce->ev, fd, events, event_once_cb, &eonce);
} else {
/* Bad event combination */
return (-1);
}
event_add(&eonce->ev, tv);
return (0);
}
void void
event_set(struct event *ev, int fd, short events, event_set(struct event *ev, int fd, short events,
void (*callback)(int, short, void *), void *arg) void (*callback)(int, short, void *), void *arg)
@ -445,6 +501,9 @@ timeout_next(struct timeval *tv)
timersub(&ev->ev_timeout, &now, tv); timersub(&ev->ev_timeout, &now, tv);
assert(tv->tv_sec >= 0);
assert(tv->tv_usec >= 0);
LOG_DBG((LOG_MISC, 60, "timeout_next: in %d seconds", tv->tv_sec)); LOG_DBG((LOG_MISC, 60, "timeout_next: in %d seconds", tv->tv_sec));
return (0); return (0);
} }

25
event.h
View File

@ -1,5 +1,3 @@
/* $OpenBSD: event.h,v 1.4 2002/07/12 18:50:48 provos Exp $ */
/* /*
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved. * All rights reserved.
@ -153,6 +151,8 @@ void timeout_process(void);
#define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) #define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
void event_set(struct event *, int, short, void (*)(int, short, void *), void *); void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
int event_once(int, short, void (*)(int, short, void *), void *, struct timeval *);
int event_add(struct event *, struct timeval *); int event_add(struct event *, struct timeval *);
int event_del(struct event *); int event_del(struct event *);
void event_active(struct event *, int, short); void event_active(struct event *, int, short);
@ -165,6 +165,27 @@ int event_pending(struct event *, short, struct timeval *);
#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) #define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
#endif #endif
/* These functions deal with buffering input and output */
struct evbuffer {
u_char *buffer;
size_t totallen;
size_t off;
};
#define EVBUFFER_LENGTH(x) (x)->off
struct evbuffer *evbuffer_new(void);
void evbuffer_free(struct evbuffer *);
void evbuffer_add(struct evbuffer *, u_char *, size_t);
void evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);
int evbuffer_add_printf(struct evbuffer *, char *fmt, ...);
void evbuffer_drain(struct evbuffer *, size_t);
int evbuffer_write(struct evbuffer *, int);
int evbuffer_read(struct evbuffer *, int, int);
u_char *evbuffer_find(struct evbuffer *, u_char *, size_t);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif