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