17718ced0SMaksim Yevmenkin /* 27718ced0SMaksim Yevmenkin * event.h 37718ced0SMaksim Yevmenkin */ 47718ced0SMaksim Yevmenkin 57718ced0SMaksim Yevmenkin /*- 67718ced0SMaksim Yevmenkin * Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin@yahoo.com> 77718ced0SMaksim Yevmenkin * All rights reserved. 87718ced0SMaksim Yevmenkin * 97718ced0SMaksim Yevmenkin * Redistribution and use in source and binary forms, with or without 107718ced0SMaksim Yevmenkin * modification, are permitted provided that the following conditions 117718ced0SMaksim Yevmenkin * are met: 127718ced0SMaksim Yevmenkin * 1. Redistributions of source code must retain the above copyright 137718ced0SMaksim Yevmenkin * notice, this list of conditions and the following disclaimer. 147718ced0SMaksim Yevmenkin * 2. Redistributions in binary form must reproduce the above copyright 157718ced0SMaksim Yevmenkin * notice, this list of conditions and the following disclaimer in the 167718ced0SMaksim Yevmenkin * documentation and/or other materials provided with the distribution. 177718ced0SMaksim Yevmenkin * 187718ced0SMaksim Yevmenkin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 197718ced0SMaksim Yevmenkin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 207718ced0SMaksim Yevmenkin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 217718ced0SMaksim Yevmenkin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 227718ced0SMaksim Yevmenkin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 237718ced0SMaksim Yevmenkin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 247718ced0SMaksim Yevmenkin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 257718ced0SMaksim Yevmenkin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 267718ced0SMaksim Yevmenkin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 277718ced0SMaksim Yevmenkin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 287718ced0SMaksim Yevmenkin * SUCH DAMAGE. 297718ced0SMaksim Yevmenkin */ 307718ced0SMaksim Yevmenkin 317718ced0SMaksim Yevmenkin /* $FreeBSD$ */ 327718ced0SMaksim Yevmenkin 337718ced0SMaksim Yevmenkin /* 347718ced0SMaksim Yevmenkin * Hack to provide libevent (see devel/libevent port) like API. 357718ced0SMaksim Yevmenkin * Should be removed if FreeBSD ever decides to import libevent into base. 367718ced0SMaksim Yevmenkin */ 377718ced0SMaksim Yevmenkin 387718ced0SMaksim Yevmenkin #include <sys/select.h> 397718ced0SMaksim Yevmenkin #include <sys/time.h> 407718ced0SMaksim Yevmenkin #include <sys/queue.h> 417718ced0SMaksim Yevmenkin #include <assert.h> 427718ced0SMaksim Yevmenkin #include <stdarg.h> 437718ced0SMaksim Yevmenkin #include <stdio.h> 447718ced0SMaksim Yevmenkin #include <string.h> 457718ced0SMaksim Yevmenkin #include <syslog.h> 467718ced0SMaksim Yevmenkin 477718ced0SMaksim Yevmenkin #include "event.h" 487718ced0SMaksim Yevmenkin #include "btpand.h" 497718ced0SMaksim Yevmenkin 507718ced0SMaksim Yevmenkin #define __event_link(ev) \ 517718ced0SMaksim Yevmenkin do { \ 527718ced0SMaksim Yevmenkin TAILQ_INSERT_TAIL(&pending, ev, next); \ 537718ced0SMaksim Yevmenkin ev->flags |= EV_PENDING; \ 547718ced0SMaksim Yevmenkin } while (0) 557718ced0SMaksim Yevmenkin 567718ced0SMaksim Yevmenkin static void tv_add(struct timeval *, struct timeval const *); 577718ced0SMaksim Yevmenkin static void tv_sub(struct timeval *, struct timeval const *); 587718ced0SMaksim Yevmenkin static int tv_cmp(struct timeval const *, struct timeval const *); 597718ced0SMaksim Yevmenkin static int __event_dispatch(void); 607718ced0SMaksim Yevmenkin static void __event_add_current(struct event *); 617718ced0SMaksim Yevmenkin static void __event_del_current(struct event *); 627718ced0SMaksim Yevmenkin 637718ced0SMaksim Yevmenkin 647718ced0SMaksim Yevmenkin static TAILQ_HEAD(, event) pending; 657718ced0SMaksim Yevmenkin static TAILQ_HEAD(, event) current; 667718ced0SMaksim Yevmenkin 677718ced0SMaksim Yevmenkin void 687718ced0SMaksim Yevmenkin event_init(void) 697718ced0SMaksim Yevmenkin { 707718ced0SMaksim Yevmenkin TAILQ_INIT(&pending); 717718ced0SMaksim Yevmenkin } 727718ced0SMaksim Yevmenkin 737718ced0SMaksim Yevmenkin int 747718ced0SMaksim Yevmenkin event_dispatch(void) 757718ced0SMaksim Yevmenkin { 767718ced0SMaksim Yevmenkin while (__event_dispatch() == 0) 777718ced0SMaksim Yevmenkin ; 787718ced0SMaksim Yevmenkin 797718ced0SMaksim Yevmenkin return (-1); 807718ced0SMaksim Yevmenkin } 817718ced0SMaksim Yevmenkin 827718ced0SMaksim Yevmenkin static int 837718ced0SMaksim Yevmenkin __event_dispatch(void) 847718ced0SMaksim Yevmenkin { 857718ced0SMaksim Yevmenkin fd_set r, w; 867718ced0SMaksim Yevmenkin int nfd; 877718ced0SMaksim Yevmenkin struct event *ev; 887718ced0SMaksim Yevmenkin struct timeval now, timeout, t; 897718ced0SMaksim Yevmenkin 907718ced0SMaksim Yevmenkin FD_ZERO(&r); 917718ced0SMaksim Yevmenkin FD_ZERO(&w); 927718ced0SMaksim Yevmenkin 937718ced0SMaksim Yevmenkin nfd = 0; 947718ced0SMaksim Yevmenkin 957718ced0SMaksim Yevmenkin gettimeofday(&now, NULL); 967718ced0SMaksim Yevmenkin 977718ced0SMaksim Yevmenkin timeout.tv_sec = 10; /* arbitrary */ 987718ced0SMaksim Yevmenkin timeout.tv_usec = 0; 997718ced0SMaksim Yevmenkin 1007718ced0SMaksim Yevmenkin TAILQ_INIT(¤t); 1017718ced0SMaksim Yevmenkin 1027718ced0SMaksim Yevmenkin /* 1037718ced0SMaksim Yevmenkin * Build fd_set's 1047718ced0SMaksim Yevmenkin */ 1057718ced0SMaksim Yevmenkin 1067718ced0SMaksim Yevmenkin event_log_debug("%s: building fd set...", __func__); 1077718ced0SMaksim Yevmenkin 1087718ced0SMaksim Yevmenkin while (!TAILQ_EMPTY(&pending)) { 1097718ced0SMaksim Yevmenkin ev = TAILQ_FIRST(&pending); 1107718ced0SMaksim Yevmenkin event_del(ev); 1117718ced0SMaksim Yevmenkin 1127718ced0SMaksim Yevmenkin if (ev->flags & EV_HAS_TIMEOUT) { 113dba59455SMaksim Yevmenkin if (tv_cmp(&now, &ev->expire) >= 0) 1147718ced0SMaksim Yevmenkin t.tv_sec = t.tv_usec = 0; 115dba59455SMaksim Yevmenkin else { 116dba59455SMaksim Yevmenkin t = ev->expire; 117dba59455SMaksim Yevmenkin tv_sub(&t, &now); 118dba59455SMaksim Yevmenkin } 1197718ced0SMaksim Yevmenkin 1207718ced0SMaksim Yevmenkin if (tv_cmp(&t, &timeout) < 0) 1217718ced0SMaksim Yevmenkin timeout = t; 1227718ced0SMaksim Yevmenkin } 1237718ced0SMaksim Yevmenkin 1247718ced0SMaksim Yevmenkin if (ev->fd >= 0) { 1257718ced0SMaksim Yevmenkin if (ev->flags & EV_READ) { 1267718ced0SMaksim Yevmenkin FD_SET(ev->fd, &r); 1277718ced0SMaksim Yevmenkin nfd = (nfd > ev->fd) ? nfd : ev->fd; 1287718ced0SMaksim Yevmenkin } 1297718ced0SMaksim Yevmenkin 1307718ced0SMaksim Yevmenkin if (ev->flags & EV_WRITE) { 1317718ced0SMaksim Yevmenkin FD_SET(ev->fd, &w); 1327718ced0SMaksim Yevmenkin nfd = (nfd > ev->fd) ? nfd : ev->fd; 1337718ced0SMaksim Yevmenkin } 1347718ced0SMaksim Yevmenkin } 1357718ced0SMaksim Yevmenkin 1367718ced0SMaksim Yevmenkin __event_add_current(ev); 1377718ced0SMaksim Yevmenkin } 1387718ced0SMaksim Yevmenkin 1397718ced0SMaksim Yevmenkin event_log_debug("%s: waiting for events...", __func__); 1407718ced0SMaksim Yevmenkin 1417718ced0SMaksim Yevmenkin nfd = select(nfd + 1, &r, &w, NULL, &timeout); 1427718ced0SMaksim Yevmenkin if (nfd < 0) 1437718ced0SMaksim Yevmenkin return (-1); 1447718ced0SMaksim Yevmenkin 1457718ced0SMaksim Yevmenkin /* 1467718ced0SMaksim Yevmenkin * Process current pending 1477718ced0SMaksim Yevmenkin */ 1487718ced0SMaksim Yevmenkin 1497718ced0SMaksim Yevmenkin event_log_debug("%s: processing events...", __func__); 1507718ced0SMaksim Yevmenkin 1517718ced0SMaksim Yevmenkin gettimeofday(&now, NULL); 1527718ced0SMaksim Yevmenkin 1537718ced0SMaksim Yevmenkin while (!TAILQ_EMPTY(¤t)) { 1547718ced0SMaksim Yevmenkin ev = TAILQ_FIRST(¤t); 1557718ced0SMaksim Yevmenkin __event_del_current(ev); 1567718ced0SMaksim Yevmenkin 1577718ced0SMaksim Yevmenkin /* check if fd is ready for reading/writing */ 1587718ced0SMaksim Yevmenkin if (nfd > 0 && ev->fd >= 0) { 1597718ced0SMaksim Yevmenkin if (FD_ISSET(ev->fd, &r) || FD_ISSET(ev->fd, &w)) { 1607718ced0SMaksim Yevmenkin if (ev->flags & EV_PERSIST) { 1617718ced0SMaksim Yevmenkin if (ev->flags & EV_HAS_TIMEOUT) 1627718ced0SMaksim Yevmenkin event_add(ev, &ev->timeout); 1637718ced0SMaksim Yevmenkin else 1647718ced0SMaksim Yevmenkin event_add(ev, NULL); 1657718ced0SMaksim Yevmenkin } 1667718ced0SMaksim Yevmenkin 1677718ced0SMaksim Yevmenkin nfd --; 1687718ced0SMaksim Yevmenkin 1697718ced0SMaksim Yevmenkin event_log_debug("%s: calling %p(%d, %p), " \ 1707718ced0SMaksim Yevmenkin "ev=%p", __func__, ev->cb, ev->fd, 1717718ced0SMaksim Yevmenkin ev->cbarg, ev); 1727718ced0SMaksim Yevmenkin 1737718ced0SMaksim Yevmenkin (ev->cb)(ev->fd, 1747718ced0SMaksim Yevmenkin (ev->flags & (EV_READ|EV_WRITE)), 1757718ced0SMaksim Yevmenkin ev->cbarg); 1767718ced0SMaksim Yevmenkin 1777718ced0SMaksim Yevmenkin continue; 1787718ced0SMaksim Yevmenkin } 1797718ced0SMaksim Yevmenkin } 1807718ced0SMaksim Yevmenkin 1817718ced0SMaksim Yevmenkin /* if event has no timeout - just requeue */ 1827718ced0SMaksim Yevmenkin if ((ev->flags & EV_HAS_TIMEOUT) == 0) { 1837718ced0SMaksim Yevmenkin event_add(ev, NULL); 1847718ced0SMaksim Yevmenkin continue; 1857718ced0SMaksim Yevmenkin } 1867718ced0SMaksim Yevmenkin 1877718ced0SMaksim Yevmenkin /* check if event has expired */ 1887718ced0SMaksim Yevmenkin if (tv_cmp(&now, &ev->expire) >= 0) { 1897718ced0SMaksim Yevmenkin if (ev->flags & EV_PERSIST) 1907718ced0SMaksim Yevmenkin event_add(ev, &ev->timeout); 1917718ced0SMaksim Yevmenkin 1927718ced0SMaksim Yevmenkin event_log_debug("%s: calling %p(%d, %p), ev=%p", 1937718ced0SMaksim Yevmenkin __func__, ev->cb, ev->fd, ev->cbarg, ev); 1947718ced0SMaksim Yevmenkin 1957718ced0SMaksim Yevmenkin (ev->cb)(ev->fd, 1967718ced0SMaksim Yevmenkin (ev->flags & (EV_READ|EV_WRITE)), 1977718ced0SMaksim Yevmenkin ev->cbarg); 1987718ced0SMaksim Yevmenkin 1997718ced0SMaksim Yevmenkin continue; 2007718ced0SMaksim Yevmenkin } 2017718ced0SMaksim Yevmenkin 2027718ced0SMaksim Yevmenkin assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0); 2037718ced0SMaksim Yevmenkin __event_link(ev); 2047718ced0SMaksim Yevmenkin } 2057718ced0SMaksim Yevmenkin 2067718ced0SMaksim Yevmenkin return (0); 2077718ced0SMaksim Yevmenkin } 2087718ced0SMaksim Yevmenkin 2097718ced0SMaksim Yevmenkin void 2107718ced0SMaksim Yevmenkin __event_set(struct event *ev, int fd, short flags, 2117718ced0SMaksim Yevmenkin void (*cb)(int, short, void *), void *cbarg) 2127718ced0SMaksim Yevmenkin { 2137718ced0SMaksim Yevmenkin ev->fd = fd; 2147718ced0SMaksim Yevmenkin ev->flags = flags; 2157718ced0SMaksim Yevmenkin ev->cb = cb; 2167718ced0SMaksim Yevmenkin ev->cbarg = cbarg; 2177718ced0SMaksim Yevmenkin } 2187718ced0SMaksim Yevmenkin 2197718ced0SMaksim Yevmenkin int 2207718ced0SMaksim Yevmenkin __event_add(struct event *ev, const struct timeval *timeout) 2217718ced0SMaksim Yevmenkin { 2227718ced0SMaksim Yevmenkin assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0); 2237718ced0SMaksim Yevmenkin 2247718ced0SMaksim Yevmenkin if (timeout != NULL) { 2257718ced0SMaksim Yevmenkin gettimeofday(&ev->expire, NULL); 2267718ced0SMaksim Yevmenkin tv_add(&ev->expire, timeout); 2277718ced0SMaksim Yevmenkin ev->timeout = *timeout; 2287718ced0SMaksim Yevmenkin ev->flags |= EV_HAS_TIMEOUT; 2297718ced0SMaksim Yevmenkin } else 2307718ced0SMaksim Yevmenkin ev->flags &= ~EV_HAS_TIMEOUT; 2317718ced0SMaksim Yevmenkin 2327718ced0SMaksim Yevmenkin __event_link(ev); 2337718ced0SMaksim Yevmenkin 2347718ced0SMaksim Yevmenkin return (0); 2357718ced0SMaksim Yevmenkin } 2367718ced0SMaksim Yevmenkin 2377718ced0SMaksim Yevmenkin int 2387718ced0SMaksim Yevmenkin __event_del(struct event *ev) 2397718ced0SMaksim Yevmenkin { 2407718ced0SMaksim Yevmenkin assert((ev->flags & EV_CURRENT) == 0); 2417718ced0SMaksim Yevmenkin 2427718ced0SMaksim Yevmenkin if ((ev->flags & EV_PENDING) != 0) { 2437718ced0SMaksim Yevmenkin TAILQ_REMOVE(&pending, ev, next); 2447718ced0SMaksim Yevmenkin ev->flags &= ~EV_PENDING; 2457718ced0SMaksim Yevmenkin } 2467718ced0SMaksim Yevmenkin 2477718ced0SMaksim Yevmenkin return (0); 2487718ced0SMaksim Yevmenkin } 2497718ced0SMaksim Yevmenkin 2507718ced0SMaksim Yevmenkin static void 2517718ced0SMaksim Yevmenkin __event_add_current(struct event *ev) 2527718ced0SMaksim Yevmenkin { 2537718ced0SMaksim Yevmenkin assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0); 2547718ced0SMaksim Yevmenkin 2557718ced0SMaksim Yevmenkin TAILQ_INSERT_TAIL(¤t, ev, next); 2567718ced0SMaksim Yevmenkin ev->flags |= EV_CURRENT; 2577718ced0SMaksim Yevmenkin } 2587718ced0SMaksim Yevmenkin 2597718ced0SMaksim Yevmenkin static void 2607718ced0SMaksim Yevmenkin __event_del_current(struct event *ev) 2617718ced0SMaksim Yevmenkin { 2627718ced0SMaksim Yevmenkin assert((ev->flags & (EV_CURRENT|EV_PENDING)) == EV_CURRENT); 2637718ced0SMaksim Yevmenkin 2647718ced0SMaksim Yevmenkin TAILQ_REMOVE(¤t, ev, next); 2657718ced0SMaksim Yevmenkin ev->flags &= ~EV_CURRENT; 2667718ced0SMaksim Yevmenkin } 2677718ced0SMaksim Yevmenkin 2687718ced0SMaksim Yevmenkin static void 2697718ced0SMaksim Yevmenkin tv_add(struct timeval *a, struct timeval const *b) 2707718ced0SMaksim Yevmenkin { 2717718ced0SMaksim Yevmenkin a->tv_sec += b->tv_sec; 2727718ced0SMaksim Yevmenkin a->tv_usec += b->tv_usec; 2737718ced0SMaksim Yevmenkin 2747718ced0SMaksim Yevmenkin if(a->tv_usec >= 1000000) { 2757718ced0SMaksim Yevmenkin a->tv_usec -= 1000000; 2767718ced0SMaksim Yevmenkin a->tv_sec += 1; 2777718ced0SMaksim Yevmenkin } 2787718ced0SMaksim Yevmenkin } 2797718ced0SMaksim Yevmenkin 2807718ced0SMaksim Yevmenkin static void 2817718ced0SMaksim Yevmenkin tv_sub(struct timeval *a, struct timeval const *b) 2827718ced0SMaksim Yevmenkin { 2837718ced0SMaksim Yevmenkin if (a->tv_usec < b->tv_usec) { 2847718ced0SMaksim Yevmenkin a->tv_usec += 1000000; 2857718ced0SMaksim Yevmenkin a->tv_sec -= 1; 2867718ced0SMaksim Yevmenkin } 2877718ced0SMaksim Yevmenkin 2887718ced0SMaksim Yevmenkin a->tv_usec -= b->tv_usec; 2897718ced0SMaksim Yevmenkin a->tv_sec -= b->tv_sec; 2907718ced0SMaksim Yevmenkin } 2917718ced0SMaksim Yevmenkin 2927718ced0SMaksim Yevmenkin static int 2937718ced0SMaksim Yevmenkin tv_cmp(struct timeval const *a, struct timeval const *b) 2947718ced0SMaksim Yevmenkin { 2957718ced0SMaksim Yevmenkin if (a->tv_sec > b->tv_sec) 2967718ced0SMaksim Yevmenkin return (1); 2977718ced0SMaksim Yevmenkin 2987718ced0SMaksim Yevmenkin if (a->tv_sec < b->tv_sec) 2997718ced0SMaksim Yevmenkin return (-1); 3007718ced0SMaksim Yevmenkin 3017718ced0SMaksim Yevmenkin if (a->tv_usec > b->tv_usec) 3027718ced0SMaksim Yevmenkin return (1); 3037718ced0SMaksim Yevmenkin 3047718ced0SMaksim Yevmenkin if (a->tv_usec < b->tv_usec) 3057718ced0SMaksim Yevmenkin return (-1); 3067718ced0SMaksim Yevmenkin 3077718ced0SMaksim Yevmenkin return (0); 3087718ced0SMaksim Yevmenkin } 3097718ced0SMaksim Yevmenkin 310