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(&current);
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(&current)) {
157187938Semax		ev = TAILQ_FIRST(&current);
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(&current, 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(&current, 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