remote: close file on usteer_init_local_id fread fail
[project/usteer.git] / timeout.c
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
14 *
15 * Copyright (C) 2020 embedd.ch
16 * Copyright (C) 2020 Felix Fietkau <nbd@nbd.name>
17 * Copyright (C) 2020 John Crispin <john@phrozen.org>
18 */
19
20 #include <string.h>
21
22 #include <libubox/utils.h>
23
24 #include "timeout.h"
25
26 static int usteer_timeout_cmp(const void *k1, const void *k2, void *ptr)
27 {
28 uint32_t ref = (uint32_t) (intptr_t) ptr;
29 int32_t t1 = (uint32_t) (intptr_t) k1 - ref;
30 int32_t t2 = (uint32_t) (intptr_t) k2 - ref;
31
32 if (t1 < t2)
33 return -1;
34 else if (t1 > t2)
35 return 1;
36 else
37 return 0;
38 }
39
40 static int32_t usteer_timeout_delta(struct usteer_timeout *t, uint32_t time)
41 {
42 uint32_t val = (uint32_t) (intptr_t) t->node.key;
43 return val - time;
44 }
45
46 static void usteer_timeout_recalc(struct usteer_timeout_queue *q, uint32_t time)
47 {
48 struct usteer_timeout *t;
49 int32_t delta;
50
51 if (avl_is_empty(&q->tree)) {
52 uloop_timeout_cancel(&q->timeout);
53 return;
54 }
55
56 t = avl_first_element(&q->tree, t, node);
57
58 delta = usteer_timeout_delta(t, time);
59 if (delta < 1)
60 delta = 1;
61
62 uloop_timeout_set(&q->timeout, delta);
63 }
64
65 static uint32_t ampgr_timeout_current_time(void)
66 {
67 struct timespec ts;
68 uint32_t val;
69
70 clock_gettime(CLOCK_MONOTONIC, &ts);
71 val = ts.tv_sec * 1000;
72 val += ts.tv_nsec / 1000000;
73
74 return val;
75 }
76
77 static void usteer_timeout_cb(struct uloop_timeout *timeout)
78 {
79 struct usteer_timeout_queue *q;
80 struct usteer_timeout *t, *tmp;
81 bool found;
82 uint32_t time;
83
84 q = container_of(timeout, struct usteer_timeout_queue, timeout);
85 do {
86 found = false;
87 time = ampgr_timeout_current_time();
88
89 avl_for_each_element_safe(&q->tree, t, node, tmp) {
90 if (usteer_timeout_delta(t, time) > 0)
91 break;
92
93 usteer_timeout_cancel(q, t);
94 if (q->cb)
95 q->cb(q, t);
96 found = true;
97 }
98 } while (found);
99
100 usteer_timeout_recalc(q, time);
101 }
102
103
104 void usteer_timeout_init(struct usteer_timeout_queue *q)
105 {
106 avl_init(&q->tree, usteer_timeout_cmp, true, NULL);
107 q->timeout.cb = usteer_timeout_cb;
108 }
109
110 static void __usteer_timeout_cancel(struct usteer_timeout_queue *q,
111 struct usteer_timeout *t)
112 {
113 avl_delete(&q->tree, &t->node);
114 }
115
116 void usteer_timeout_set(struct usteer_timeout_queue *q, struct usteer_timeout *t,
117 int msecs)
118 {
119 uint32_t time = ampgr_timeout_current_time();
120 uint32_t val = time + msecs;
121 bool recalc = false;
122
123 q->tree.cmp_ptr = (void *) (intptr_t) time;
124 if (usteer_timeout_isset(t)) {
125 if (avl_is_first(&q->tree, &t->node))
126 recalc = true;
127
128 __usteer_timeout_cancel(q, t);
129 }
130
131 t->node.key = (void *) (intptr_t) val;
132 avl_insert(&q->tree, &t->node);
133 if (avl_is_first(&q->tree, &t->node))
134 recalc = true;
135
136 if (recalc)
137 usteer_timeout_recalc(q, time);
138 }
139
140 void usteer_timeout_cancel(struct usteer_timeout_queue *q,
141 struct usteer_timeout *t)
142 {
143 if (!usteer_timeout_isset(t))
144 return;
145
146 __usteer_timeout_cancel(q, t);
147 memset(&t->node.list, 0, sizeof(t->node.list));
148 }
149
150 void usteer_timeout_flush(struct usteer_timeout_queue *q)
151 {
152 struct usteer_timeout *t, *tmp;
153
154 uloop_timeout_cancel(&q->timeout);
155 avl_remove_all_elements(&q->tree, t, node, tmp) {
156 memset(&t->node.list, 0, sizeof(t->node.list));
157 if (q->cb)
158 q->cb(q, t);
159 }
160 }