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