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