1187938Semax/* 2187938Semax * event.h 3187938Semax */ 4187938Semax 5187938Semax/*- 6187938Semax * Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7187938Semax * All rights reserved. 8187938Semax * 9187938Semax * Redistribution and use in source and binary forms, with or without 10187938Semax * modification, are permitted provided that the following conditions 11187938Semax * are met: 12187938Semax * 1. Redistributions of source code must retain the above copyright 13187938Semax * notice, this list of conditions and the following disclaimer. 14187938Semax * 2. Redistributions in binary form must reproduce the above copyright 15187938Semax * notice, this list of conditions and the following disclaimer in the 16187938Semax * documentation and/or other materials provided with the distribution. 17187938Semax * 18187938Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19187938Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20187938Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21187938Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22187938Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23187938Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24187938Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25187938Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26187938Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27187938Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28187938Semax * SUCH DAMAGE. 29187938Semax */ 30187938Semax 31187938Semax/* $FreeBSD$ */ 32187938Semax 33187938Semax/* 34187938Semax * Hack to provide libevent (see devel/libevent port) like API. 35187938Semax * Should be removed if FreeBSD ever decides to import libevent into base. 36187938Semax */ 37187938Semax 38187938Semax#include <sys/select.h> 39187938Semax#include <sys/time.h> 40187938Semax#include <sys/queue.h> 41187938Semax#include <assert.h> 42187938Semax#include <stdarg.h> 43187938Semax#include <stdio.h> 44187938Semax#include <string.h> 45187938Semax#include <syslog.h> 46187938Semax 47187938Semax#include "event.h" 48187938Semax#include "btpand.h" 49187938Semax 50187938Semax#define __event_link(ev) \ 51187938Semaxdo { \ 52187938Semax TAILQ_INSERT_TAIL(&pending, ev, next); \ 53187938Semax ev->flags |= EV_PENDING; \ 54187938Semax} while (0) 55187938Semax 56187938Semaxstatic void tv_add(struct timeval *, struct timeval const *); 57187938Semaxstatic void tv_sub(struct timeval *, struct timeval const *); 58187938Semaxstatic int tv_cmp(struct timeval const *, struct timeval const *); 59187938Semaxstatic int __event_dispatch(void); 60187938Semaxstatic void __event_add_current(struct event *); 61187938Semaxstatic void __event_del_current(struct event *); 62187938Semax 63187938Semax 64187938Semaxstatic TAILQ_HEAD(, event) pending; 65187938Semaxstatic TAILQ_HEAD(, event) current; 66187938Semax 67187938Semaxvoid 68187938Semaxevent_init(void) 69187938Semax{ 70187938Semax TAILQ_INIT(&pending); 71187938Semax} 72187938Semax 73187938Semaxint 74187938Semaxevent_dispatch(void) 75187938Semax{ 76187938Semax while (__event_dispatch() == 0) 77187938Semax ; 78187938Semax 79187938Semax return (-1); 80187938Semax} 81187938Semax 82187938Semaxstatic int 83187938Semax__event_dispatch(void) 84187938Semax{ 85187938Semax fd_set r, w; 86187938Semax int nfd; 87187938Semax struct event *ev; 88187938Semax struct timeval now, timeout, t; 89187938Semax 90187938Semax FD_ZERO(&r); 91187938Semax FD_ZERO(&w); 92187938Semax 93187938Semax nfd = 0; 94187938Semax 95187938Semax gettimeofday(&now, NULL); 96187938Semax 97187938Semax timeout.tv_sec = 10; /* arbitrary */ 98187938Semax timeout.tv_usec = 0; 99187938Semax 100187938Semax TAILQ_INIT(¤t); 101187938Semax 102187938Semax /* 103187938Semax * Build fd_set's 104187938Semax */ 105187938Semax 106187938Semax event_log_debug("%s: building fd set...", __func__); 107187938Semax 108187938Semax while (!TAILQ_EMPTY(&pending)) { 109187938Semax ev = TAILQ_FIRST(&pending); 110187938Semax event_del(ev); 111187938Semax 112187938Semax if (ev->flags & EV_HAS_TIMEOUT) { 113191232Semax if (tv_cmp(&now, &ev->expire) >= 0) 114187938Semax t.tv_sec = t.tv_usec = 0; 115191232Semax else { 116191232Semax t = ev->expire; 117191232Semax tv_sub(&t, &now); 118191232Semax } 119187938Semax 120187938Semax if (tv_cmp(&t, &timeout) < 0) 121187938Semax timeout = t; 122187938Semax } 123187938Semax 124187938Semax if (ev->fd >= 0) { 125187938Semax if (ev->flags & EV_READ) { 126187938Semax FD_SET(ev->fd, &r); 127187938Semax nfd = (nfd > ev->fd) ? nfd : ev->fd; 128187938Semax } 129187938Semax 130187938Semax if (ev->flags & EV_WRITE) { 131187938Semax FD_SET(ev->fd, &w); 132187938Semax nfd = (nfd > ev->fd) ? nfd : ev->fd; 133187938Semax } 134187938Semax } 135187938Semax 136187938Semax __event_add_current(ev); 137187938Semax } 138187938Semax 139187938Semax event_log_debug("%s: waiting for events...", __func__); 140187938Semax 141187938Semax nfd = select(nfd + 1, &r, &w, NULL, &timeout); 142187938Semax if (nfd < 0) 143187938Semax return (-1); 144187938Semax 145187938Semax /* 146187938Semax * Process current pending 147187938Semax */ 148187938Semax 149187938Semax event_log_debug("%s: processing events...", __func__); 150187938Semax 151187938Semax gettimeofday(&now, NULL); 152187938Semax 153187938Semax while (!TAILQ_EMPTY(¤t)) { 154187938Semax ev = TAILQ_FIRST(¤t); 155187938Semax __event_del_current(ev); 156187938Semax 157187938Semax /* check if fd is ready for reading/writing */ 158187938Semax if (nfd > 0 && ev->fd >= 0) { 159187938Semax if (FD_ISSET(ev->fd, &r) || FD_ISSET(ev->fd, &w)) { 160187938Semax if (ev->flags & EV_PERSIST) { 161187938Semax if (ev->flags & EV_HAS_TIMEOUT) 162187938Semax event_add(ev, &ev->timeout); 163187938Semax else 164187938Semax event_add(ev, NULL); 165187938Semax } 166187938Semax 167187938Semax nfd --; 168187938Semax 169187938Semax event_log_debug("%s: calling %p(%d, %p), " \ 170187938Semax "ev=%p", __func__, ev->cb, ev->fd, 171187938Semax ev->cbarg, ev); 172187938Semax 173187938Semax (ev->cb)(ev->fd, 174187938Semax (ev->flags & (EV_READ|EV_WRITE)), 175187938Semax ev->cbarg); 176187938Semax 177187938Semax continue; 178187938Semax } 179187938Semax } 180187938Semax 181187938Semax /* if event has no timeout - just requeue */ 182187938Semax if ((ev->flags & EV_HAS_TIMEOUT) == 0) { 183187938Semax event_add(ev, NULL); 184187938Semax continue; 185187938Semax } 186187938Semax 187187938Semax /* check if event has expired */ 188187938Semax if (tv_cmp(&now, &ev->expire) >= 0) { 189187938Semax if (ev->flags & EV_PERSIST) 190187938Semax event_add(ev, &ev->timeout); 191187938Semax 192187938Semax event_log_debug("%s: calling %p(%d, %p), ev=%p", 193187938Semax __func__, ev->cb, ev->fd, ev->cbarg, ev); 194187938Semax 195187938Semax (ev->cb)(ev->fd, 196187938Semax (ev->flags & (EV_READ|EV_WRITE)), 197187938Semax ev->cbarg); 198187938Semax 199187938Semax continue; 200187938Semax } 201187938Semax 202187938Semax assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0); 203187938Semax __event_link(ev); 204187938Semax } 205187938Semax 206187938Semax return (0); 207187938Semax} 208187938Semax 209187938Semaxvoid 210187938Semax__event_set(struct event *ev, int fd, short flags, 211187938Semax void (*cb)(int, short, void *), void *cbarg) 212187938Semax{ 213187938Semax ev->fd = fd; 214187938Semax ev->flags = flags; 215187938Semax ev->cb = cb; 216187938Semax ev->cbarg = cbarg; 217187938Semax} 218187938Semax 219187938Semaxint 220187938Semax__event_add(struct event *ev, const struct timeval *timeout) 221187938Semax{ 222187938Semax assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0); 223187938Semax 224187938Semax if (timeout != NULL) { 225187938Semax gettimeofday(&ev->expire, NULL); 226187938Semax tv_add(&ev->expire, timeout); 227187938Semax ev->timeout = *timeout; 228187938Semax ev->flags |= EV_HAS_TIMEOUT; 229187938Semax } else 230187938Semax ev->flags &= ~EV_HAS_TIMEOUT; 231187938Semax 232187938Semax __event_link(ev); 233187938Semax 234187938Semax return (0); 235187938Semax} 236187938Semax 237187938Semaxint 238187938Semax__event_del(struct event *ev) 239187938Semax{ 240187938Semax assert((ev->flags & EV_CURRENT) == 0); 241187938Semax 242187938Semax if ((ev->flags & EV_PENDING) != 0) { 243187938Semax TAILQ_REMOVE(&pending, ev, next); 244187938Semax ev->flags &= ~EV_PENDING; 245187938Semax } 246187938Semax 247187938Semax return (0); 248187938Semax} 249187938Semax 250187938Semaxstatic void 251187938Semax__event_add_current(struct event *ev) 252187938Semax{ 253187938Semax assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0); 254187938Semax 255187938Semax TAILQ_INSERT_TAIL(¤t, ev, next); 256187938Semax ev->flags |= EV_CURRENT; 257187938Semax} 258187938Semax 259187938Semaxstatic void 260187938Semax__event_del_current(struct event *ev) 261187938Semax{ 262187938Semax assert((ev->flags & (EV_CURRENT|EV_PENDING)) == EV_CURRENT); 263187938Semax 264187938Semax TAILQ_REMOVE(¤t, ev, next); 265187938Semax ev->flags &= ~EV_CURRENT; 266187938Semax} 267187938Semax 268187938Semaxstatic void 269187938Semaxtv_add(struct timeval *a, struct timeval const *b) 270187938Semax{ 271187938Semax a->tv_sec += b->tv_sec; 272187938Semax a->tv_usec += b->tv_usec; 273187938Semax 274187938Semax if(a->tv_usec >= 1000000) { 275187938Semax a->tv_usec -= 1000000; 276187938Semax a->tv_sec += 1; 277187938Semax } 278187938Semax} 279187938Semax 280187938Semaxstatic void 281187938Semaxtv_sub(struct timeval *a, struct timeval const *b) 282187938Semax{ 283187938Semax if (a->tv_usec < b->tv_usec) { 284187938Semax a->tv_usec += 1000000; 285187938Semax a->tv_sec -= 1; 286187938Semax } 287187938Semax 288187938Semax a->tv_usec -= b->tv_usec; 289187938Semax a->tv_sec -= b->tv_sec; 290187938Semax} 291187938Semax 292187938Semaxstatic int 293187938Semaxtv_cmp(struct timeval const *a, struct timeval const *b) 294187938Semax{ 295187938Semax if (a->tv_sec > b->tv_sec) 296187938Semax return (1); 297187938Semax 298187938Semax if (a->tv_sec < b->tv_sec) 299187938Semax return (-1); 300187938Semax 301187938Semax if (a->tv_usec > b->tv_usec) 302187938Semax return (1); 303187938Semax 304187938Semax if (a->tv_usec < b->tv_usec) 305187938Semax return (-1); 306187938Semax 307187938Semax return (0); 308187938Semax} 309187938Semax 310