#define EV_ACTIVE 0x80
struct event_base {
+ /* pending timeouts */
struct AATree timeout_tree;
+ /* fd events */
struct StatList fd_list;
+
+ /* pollfd <-> event mapping */
struct event **pfd_event;
struct pollfd *pfd_list;
int pfd_size;
- bool loop_break;
- bool loop_exit;
-
/* signal handling */
struct List sig_node;
+ unsigned int sig_seen[MAX_SIGNAL];
struct List sig_waiters[MAX_SIGNAL];
int sig_send, sig_recv;
struct event sig_ev;
- unsigned int sig_seen[MAX_SIGNAL];
+
+ /* exit loop ASAP */
+ bool loop_break;
+ /* finish current loop and exit */
+ bool loop_exit;
};
/* default event base */
static struct sigaction old_handler[MAX_SIGNAL];
static LIST(sig_base_list);
-
+/* internal signal functions */
static bool sig_init(struct event_base *base, int sig);
static void sig_close(struct event_base *base);
struct event_base *base;
int i;
- base = calloc(1, sizeof(*base));
+ base = zmalloc(sizeof(*base));
/* initialize timeout and fd areas */
aatree_init(&base->timeout_tree, cmp_timeout, NULL);
free(base);
}
+/* set flag to exit loop ASAP */
int event_base_loopbreak(struct event_base *base)
{
base->loop_break = true;
* Multi-base functions.
*/
+/* fill event structure */
void event_assign(struct event *ev, struct event_base *base, int fd, short flags, uevent_cb_f cb, void *arg)
{
Assert(base);
ev_dbg(ev, "event_set");
}
+/* Change base for a event */
+int event_base_set(struct event_base *base, struct event *ev)
+{
+ if (ev->flags & EV_ACTIVE) {
+ errno = EINVAL;
+ return -1;
+ }
+ ev->base = base;
+ return 0;
+}
+
+/* Check if activated */
+int is_event_active(struct event *ev)
+{
+ return (ev->flags & EV_ACTIVE) ? 1 : 0;
+}
+
+/* de-activate event */
int event_del(struct event *ev)
{
struct event_base *base = ev->base;
}
-/* handles only relarive timeouts */
+/* activate event */
int event_add(struct event *ev, struct timeval *timeout)
{
struct event_base *base = ev->base;
Assert((ev->flags & EV_ACTIVE) == 0);
Assert(base);
- /* timeout sanity check, but dont use it yet */
+ /* sanity check, but dont do anything yet */
if (timeout) {
- if (ev->flags & EV_PERSIST) {
- errno = EINVAL;
- return -1;
- }
- } else if (ev->flags & EV_TIMEOUT) {
- ev->flags &= ~EV_TIMEOUT;
+ if (ev->flags & EV_PERSIST)
+ goto err_inval;
+ } else {
+ if (ev->flags & EV_TIMEOUT)
+ ev->flags &= ~EV_TIMEOUT;
+ if (!(ev->flags & (EV_SIGNAL | EV_READ | EV_WRITE)))
+ goto err_inval;
}
/* setup signal/fd */
if (ev->flags & EV_SIGNAL) {
- if (ev->flags & (EV_READ|EV_WRITE)) {
- errno = EINVAL;
- return -1;
- }
+ if (ev->flags & (EV_READ|EV_WRITE))
+ goto err_inval;
if (!sig_init(base, ev->fd))
return -1;
list_append(&base->sig_waiters[ev->fd], &ev->node);
ev->flags |= EV_ACTIVE;
ev_dbg(ev, "event_add");
-
return 0;
+
+err_inval:
+ errno = EINVAL;
+ return -1;
}
/*
return NULL;
}
+/* decide how long poll() should sleep */
static int calc_timeout(struct event_base *base)
{
struct event *ev;
return res;
}
+/* deliver fd events */
static void process_fds(struct event_base *base, int pf_cnt)
{
int i;
if (!ev)
continue;
base->pfd_event[i] = NULL;
- ev->ev_idx = -1; // is it needed?
+ ev->ev_idx = -1;
if (pf->revents & (POLLIN | POLLOUT | POLLERR | POLLHUP)) {
int flags = ev->flags & (EV_READ | EV_WRITE);
deliver_event(ev, flags);
}
}
+/* handle passed timeouts */
static void process_timeouts(struct event_base *base)
{
struct timeval now;
}
}
+/* main event loop */
int event_base_loop(struct event_base *base, int loop_flags)
{
int pf_cnt, res, timeout_ms;
if (res == -1 && errno != EINTR)
return -1;
+ /* process events */
if (res > 0) {
process_fds(base, pf_cnt);
if (base->loop_break)
return 0;
}
-
process_timeouts(base);
- if (base->loop_break)
- return 0;
-
+ /* decide whether to continue looping */
if (loop_flags & EVLOOP_ONCE)
return 0;
-
- if (base->loop_exit)
+ if (base->loop_break || base->loop_exit)
return 0;
-
goto loop;
}
if (res < 0) {
if (errno == EINTR)
goto loop;
- if (errno != EAGAIN)
- goto some_error;
- } else if (res == 0)
- goto some_error;
+ } else if ((res == sizeof(buf)) && (res > 1))
+ goto loop;
/* now check for new signals */
for (sig = 0; sig < MAX_SIGNAL; sig++) {
deliver_signal(base, sig);
}
}
- return;
-
-some_error:
- //log_warning("signal reading got error: res=%d err=%s", res, strerror(errno));
- sig_close(base);
}
+/* setup signal handling for particular signal */
static bool sig_init(struct event_base *base, int sig)
{
int spair[2];
cb_func(fd, flags, cb_arg);
}
+/* wait for one-time event, provide event struct internally */
int event_base_once(struct event_base *base, int fd, short flags,
uevent_cb_f cb_func, void *cb_arg,
struct timeval *timeout)
return 0;
}
+/*
+ * Stop loop at particular time.
+ */
+
static void loopexit_handler(int fd, short flags, void *arg)
{
struct event_base *base = arg;
int event_base_loopexit(struct event_base *base, struct timeval *timeout)
{
- return event_base_once(base, -1, 0, loopexit_handler, base, timeout);
-}
-
-int event_base_set(struct event_base *base, struct event *ev)
-{
- if (ev->flags & EV_ACTIVE) {
+ if (!timeout) {
errno = EINVAL;
return -1;
}
- ev->base = base;
- return 0;
-}
-
-/*
- * Is activated.
- */
-
-int is_event_initialized(struct event *ev)
-{
- return (ev->flags & EV_ACTIVE) ? 1 : 0;
+ return event_base_once(base, -1, 0, loopexit_handler, base, timeout);
}
#include <usual/aatree.h>
#include <usual/list.h>
+/*
+ * Flags for event_set() / event_assign():
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_PERSIST
+ *
+ * Flags given to user callback:
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
+ */
enum EventFlags {
EV_TIMEOUT = 1,
EV_READ = 2,
EV_PERSIST = 16,
};
+/* Flags for event_loop() */
enum EventLoopType {
EVLOOP_ONCE = 1,
EVLOOP_NONBLOCK = 2,
};
+/* event_base contents are not open */
struct event_base;
+/* user callback signature */
typedef void (*uevent_cb_f)(int fd, short flags, void *arg);
+/* macros to read fd and signal values */
+#define EVENT_FD(ev) ((ev)->fd)
+#define EVENT_SIGNAL(ev) ((ev)->fd)
+
+/*
+ * Our event structure.
+ *
+ * Although the struct is open, no direct accesses should be done.
+ * Thus also the fields are incompat with libevent.
+ */
struct event {
+ /* node for fd or signal lists */
struct List node;
+ /* timeout info */
struct timeval timeout;
struct AANode timeout_node;
+ /* back-pointer into pollfd list */
int ev_idx;
+
+ /* event base it is attached to */
struct event_base *base;
+ /* user callback */
uevent_cb_f cb_func;
void *cb_arg;
+ /* fd or signal */
int fd;
+
+ /* both user and internal flags */
short flags;
};
int event_base_set(struct event_base *base, struct event *ev);
/* pointless compat */
-#define event_initialized(ev) is_event_initialized(ev)
-#define signal_initialized(ev) is_event_initialized(ev)
-#define evtimer_initialized(ev) is_event_initialized(ev)
#define event_dispatch() event_loop(0)
#define event_base_dispatch(base) event_base_loop(base, 0)
-int is_event_initialized(struct event *ev);
+#define event_initialized(ev) is_event_active(ev)
+#define signal_initialized(ev) is_event_active(ev)
+#define evtimer_initialized(ev) is_event_active(ev)
+int is_event_active(struct event *ev);
#endif