One directory for source code.
[tinc] / fd / event.c
1 /*
2     event.c -- event queue
3
4     Copyright (C) 2003-2004 Guus Sliepen <guus@tinc-vpn.org>,
5                   2003-2004 Ivo Timmermans <ivo@tinc-vpn.org>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21     $Id$
22 */
23
24 #include "system.h"
25
26 #include "support/avl.h"
27 #include "support/xalloc.h"
28 #include "fd/event.h"
29
30 avl_tree_t *events;
31
32 static event_id_t id;
33
34 static int timevalcmp(struct timeval a, struct timeval b) {
35         return a.tv_sec - b.tv_sec ?: a.tv_usec - b.tv_usec;
36 }
37
38 static int event_compare(const event_t *a, const event_t *b) {
39         return timevalcmp(a->tv, b->tv) ?: a->id - b->id;
40 }
41
42 bool event_init(void) {
43         events = avl_tree_new((avl_compare_t)event_compare, (avl_action_t)event_free);
44
45         return true;
46 }
47
48 bool event_exit(void) {
49         avl_tree_del(events);
50
51         return true;
52 }
53
54 event_t *event_new(void) {
55         event_t *event;
56
57         return clear(new(event));
58 }
59
60 void event_free(event_t *event) {
61         free(event);
62 }
63
64 void event_set(event_t *event, struct timeval timeout, event_handler_t handler, void *data) {
65         gettimeofday(&event->tv, NULL);
66         event_update(event, timeout);
67         event->interval = timeout;
68         event->handler = handler;
69         event->data = data;
70 }       
71
72 void event_update(event_t *event, struct timeval timeout) {
73         event->tv.tv_sec += timeout.tv_sec;
74         event->tv.tv_usec += timeout.tv_usec;
75         event->tv.tv_sec += event->tv.tv_usec / 1000000;
76         event->tv.tv_usec %= 1000000;
77 }       
78
79 bool event_add(event_t *event) {
80         event->id = ++id;
81         return avl_add(events, event);
82 }
83
84 bool event_del(event_t *event) {
85         return avl_del(events, event);
86 }
87
88 void event_handle(void) {
89         struct timeval now;
90         event_t *event;
91         avl_node_t *avl;
92
93         gettimeofday(&now, NULL);
94
95         avl_foreach_node(events, avl, {
96                 event = avl->data;
97                 
98                 if(timercmp(&event->tv, &now, <)) {
99                         avl_unlink_node(events, avl);
100                         if(event->handler(event))
101                                 avl_add_node(events, avl);
102                         else
103                                 avl_node_free(events, avl);
104                 } else {
105                         break;
106                 }
107         });
108 }
109
110 struct timeval event_timeout(void) {
111         struct timeval tv, now;
112         event_t *event;
113
114         gettimeofday(&now, NULL);
115
116         if(events->head) {
117                 event = events->head->data;
118
119                 tv.tv_sec = event->tv.tv_sec - now.tv_sec;
120                 tv.tv_usec = event->tv.tv_usec - now.tv_usec;
121
122                 if(tv.tv_usec < 0) {
123                         tv.tv_usec += 1e6;
124                         tv.tv_sec--;
125                 }
126
127                 if(tv.tv_sec < 0) {
128                         tv.tv_sec = 0;
129                         tv.tv_usec = 0;
130                 }
131         } else {
132                 tv.tv_sec = -1;
133                 tv.tv_usec = -1;
134         }
135
136         return tv;
137 }