Path: blob/main/usr.sbin/bluetooth/btpand/event.c
105216 views
/*1* event.h2*/34/*-5* SPDX-License-Identifier: BSD-2-Clause6*7* Copyright (c) 2009 Maksim Yevmenkin <[email protected]>8* All rights reserved.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18*19* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND20* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE21* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE22* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE23* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL24* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS25* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT27* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY28* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF29* SUCH DAMAGE.30*/313233/*34* Hack to provide libevent (see devel/libevent port) like API.35* Should be removed if FreeBSD ever decides to import libevent into base.36*/3738#include <sys/select.h>39#include <sys/time.h>40#include <sys/queue.h>41#include <assert.h>42#include <stdarg.h>43#include <stdio.h>44#include <string.h>45#include <syslog.h>4647#include "event.h"48#define L2CAP_SOCKET_CHECKED49#include "btpand.h"5051#define __event_link(ev) \52do { \53TAILQ_INSERT_TAIL(&pending, ev, next); \54ev->flags |= EV_PENDING; \55} while (0)5657static void tv_add(struct timeval *, struct timeval const *);58static void tv_sub(struct timeval *, struct timeval const *);59static int tv_cmp(struct timeval const *, struct timeval const *);60static int __event_dispatch(void);61static void __event_add_current(struct event *);62static void __event_del_current(struct event *);636465static TAILQ_HEAD(, event) pending;66static TAILQ_HEAD(, event) current;6768void69event_init(void)70{71TAILQ_INIT(&pending);72}7374int75event_dispatch(void)76{77while (__event_dispatch() == 0)78;7980return (-1);81}8283static int84__event_dispatch(void)85{86fd_set r, w;87int nfd;88struct event *ev;89struct timeval now, timeout, t;9091FD_ZERO(&r);92FD_ZERO(&w);9394nfd = 0;9596gettimeofday(&now, NULL);9798timeout.tv_sec = 10; /* arbitrary */99timeout.tv_usec = 0;100101TAILQ_INIT(¤t);102103/*104* Build fd_set's105*/106107event_log_debug("%s: building fd set...", __func__);108109while (!TAILQ_EMPTY(&pending)) {110ev = TAILQ_FIRST(&pending);111event_del(ev);112113if (ev->flags & EV_HAS_TIMEOUT) {114if (tv_cmp(&now, &ev->expire) >= 0)115t.tv_sec = t.tv_usec = 0;116else {117t = ev->expire;118tv_sub(&t, &now);119}120121if (tv_cmp(&t, &timeout) < 0)122timeout = t;123}124125if (ev->fd >= 0) {126if (ev->flags & EV_READ) {127FD_SET(ev->fd, &r);128nfd = (nfd > ev->fd) ? nfd : ev->fd;129}130131if (ev->flags & EV_WRITE) {132FD_SET(ev->fd, &w);133nfd = (nfd > ev->fd) ? nfd : ev->fd;134}135}136137__event_add_current(ev);138}139140event_log_debug("%s: waiting for events...", __func__);141142nfd = select(nfd + 1, &r, &w, NULL, &timeout);143if (nfd < 0)144return (-1);145146/*147* Process current pending148*/149150event_log_debug("%s: processing events...", __func__);151152gettimeofday(&now, NULL);153154while (!TAILQ_EMPTY(¤t)) {155ev = TAILQ_FIRST(¤t);156__event_del_current(ev);157158/* check if fd is ready for reading/writing */159if (nfd > 0 && ev->fd >= 0) {160if (FD_ISSET(ev->fd, &r) || FD_ISSET(ev->fd, &w)) {161if (ev->flags & EV_PERSIST) {162if (ev->flags & EV_HAS_TIMEOUT)163event_add(ev, &ev->timeout);164else165event_add(ev, NULL);166}167168nfd --;169170event_log_debug("%s: calling %p(%d, %p), " \171"ev=%p", __func__, ev->cb, ev->fd,172ev->cbarg, ev);173174(ev->cb)(ev->fd,175(ev->flags & (EV_READ|EV_WRITE)),176ev->cbarg);177178continue;179}180}181182/* if event has no timeout - just requeue */183if ((ev->flags & EV_HAS_TIMEOUT) == 0) {184event_add(ev, NULL);185continue;186}187188/* check if event has expired */189if (tv_cmp(&now, &ev->expire) >= 0) {190if (ev->flags & EV_PERSIST)191event_add(ev, &ev->timeout);192193event_log_debug("%s: calling %p(%d, %p), ev=%p",194__func__, ev->cb, ev->fd, ev->cbarg, ev);195196(ev->cb)(ev->fd,197(ev->flags & (EV_READ|EV_WRITE)),198ev->cbarg);199200continue;201}202203assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0);204__event_link(ev);205}206207return (0);208}209210void211__event_set(struct event *ev, int fd, short flags,212void (*cb)(int, short, void *), void *cbarg)213{214ev->fd = fd;215ev->flags = flags;216ev->cb = cb;217ev->cbarg = cbarg;218}219220int221__event_add(struct event *ev, const struct timeval *timeout)222{223assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0);224225if (timeout != NULL) {226gettimeofday(&ev->expire, NULL);227tv_add(&ev->expire, timeout);228ev->timeout = *timeout;229ev->flags |= EV_HAS_TIMEOUT;230} else231ev->flags &= ~EV_HAS_TIMEOUT;232233__event_link(ev);234235return (0);236}237238int239__event_del(struct event *ev)240{241assert((ev->flags & EV_CURRENT) == 0);242243if ((ev->flags & EV_PENDING) != 0) {244TAILQ_REMOVE(&pending, ev, next);245ev->flags &= ~EV_PENDING;246}247248return (0);249}250251static void252__event_add_current(struct event *ev)253{254assert((ev->flags & (EV_PENDING|EV_CURRENT)) == 0);255256TAILQ_INSERT_TAIL(¤t, ev, next);257ev->flags |= EV_CURRENT;258}259260static void261__event_del_current(struct event *ev)262{263assert((ev->flags & (EV_CURRENT|EV_PENDING)) == EV_CURRENT);264265TAILQ_REMOVE(¤t, ev, next);266ev->flags &= ~EV_CURRENT;267}268269static void270tv_add(struct timeval *a, struct timeval const *b)271{272a->tv_sec += b->tv_sec;273a->tv_usec += b->tv_usec;274275if(a->tv_usec >= 1000000) {276a->tv_usec -= 1000000;277a->tv_sec += 1;278}279}280281static void282tv_sub(struct timeval *a, struct timeval const *b)283{284if (a->tv_usec < b->tv_usec) {285a->tv_usec += 1000000;286a->tv_sec -= 1;287}288289a->tv_usec -= b->tv_usec;290a->tv_sec -= b->tv_sec;291}292293static int294tv_cmp(struct timeval const *a, struct timeval const *b)295{296if (a->tv_sec > b->tv_sec)297return (1);298299if (a->tv_sec < b->tv_sec)300return (-1);301302if (a->tv_usec > b->tv_usec)303return (1);304305if (a->tv_usec < b->tv_usec)306return (-1);307308return (0);309}310311312313