Split event.c into per-API files
[tinc] / src / event.c
1 /*
2     event.c -- I/O, timeout, and event handling
3     Copyright (C) 2012-2022 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21
22 #include "event.h"
23
24 struct timeval now;
25
26 static int io_compare(const io_t *a, const io_t *b) {
27 #ifndef HAVE_WINDOWS
28         return a->fd - b->fd;
29 #else
30
31         if(a->event < b->event) {
32                 return -1;
33         }
34
35         if(a->event > b->event) {
36                 return 1;
37         }
38
39         return 0;
40 #endif
41 }
42
43 static int timeout_compare(const timeout_t *a, const timeout_t *b) {
44         struct timeval diff;
45         timersub(&a->tv, &b->tv, &diff);
46
47         if(diff.tv_sec < 0) {
48                 return -1;
49         }
50
51         if(diff.tv_sec > 0) {
52                 return 1;
53         }
54
55         if(diff.tv_usec < 0) {
56                 return -1;
57         }
58
59         if(diff.tv_usec > 0) {
60                 return 1;
61         }
62
63         if(a < b) {
64                 return -1;
65         }
66
67         if(a > b) {
68                 return 1;
69         }
70
71         return 0;
72 }
73
74 splay_tree_t io_tree = {.compare = (splay_compare_t)io_compare};
75 splay_tree_t timeout_tree = {.compare = (splay_compare_t)timeout_compare};
76
77 void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, const struct timeval *tv) {
78         timeout->cb = cb;
79         timeout->data = data;
80         timeout->node.data = timeout;
81
82         timeout_set(timeout, tv);
83 }
84
85 void timeout_set(timeout_t *timeout, const struct timeval *tv) {
86         if(timerisset(&timeout->tv)) {
87                 splay_unlink_node(&timeout_tree, &timeout->node);
88         }
89
90         if(!now.tv_sec) {
91                 gettimeofday(&now, NULL);
92         }
93
94         timeradd(&now, tv, &timeout->tv);
95
96         if(!splay_insert_node(&timeout_tree, &timeout->node)) {
97                 abort();
98         }
99 }
100
101 void timeout_del(timeout_t *timeout) {
102         if(!timeout->cb) {
103                 return;
104         }
105
106         splay_unlink_node(&timeout_tree, &timeout->node);
107         timeout->cb = 0;
108         timeout->tv = (struct timeval) {
109                 0, 0
110         };
111 }
112
113 struct timeval *timeout_execute(struct timeval *diff) {
114         gettimeofday(&now, NULL);
115         struct timeval *tv = NULL;
116
117         while(timeout_tree.head) {
118                 timeout_t *timeout = timeout_tree.head->data;
119                 timersub(&timeout->tv, &now, diff);
120
121                 if(diff->tv_sec < 0) {
122                         timeout->cb(timeout->data);
123
124                         if(timercmp(&timeout->tv, &now, <)) {
125                                 timeout_del(timeout);
126                         }
127                 } else {
128                         tv = diff;
129                         break;
130                 }
131         }
132
133         return tv;
134 }