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.
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.
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.
15 * Copyright (C) 2020 embedd.ch
16 * Copyright (C) 2020 Felix Fietkau <nbd@nbd.name>
17 * Copyright (C) 2020 John Crispin <john@phrozen.org>
22 #include <libubox/utils.h>
26 static int usteer_timeout_cmp(const void *k1
, const void *k2
, void *ptr
)
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
;
40 static int32_t usteer_timeout_delta(struct usteer_timeout
*t
, uint32_t time
)
42 uint32_t val
= (uint32_t) (intptr_t) t
->node
.key
;
46 static void usteer_timeout_recalc(struct usteer_timeout_queue
*q
, uint32_t time
)
48 struct usteer_timeout
*t
;
51 if (avl_is_empty(&q
->tree
)) {
52 uloop_timeout_cancel(&q
->timeout
);
56 t
= avl_first_element(&q
->tree
, t
, node
);
58 delta
= usteer_timeout_delta(t
, time
);
62 uloop_timeout_set(&q
->timeout
, delta
);
65 static uint32_t ampgr_timeout_current_time(void)
70 clock_gettime(CLOCK_MONOTONIC
, &ts
);
71 val
= ts
.tv_sec
* 1000;
72 val
+= ts
.tv_nsec
/ 1000000;
77 static void usteer_timeout_cb(struct uloop_timeout
*timeout
)
79 struct usteer_timeout_queue
*q
;
80 struct usteer_timeout
*t
, *tmp
;
84 q
= container_of(timeout
, struct usteer_timeout_queue
, timeout
);
87 time
= ampgr_timeout_current_time();
89 avl_for_each_element_safe(&q
->tree
, t
, node
, tmp
) {
90 if (usteer_timeout_delta(t
, time
) > 0)
93 usteer_timeout_cancel(q
, t
);
100 usteer_timeout_recalc(q
, time
);
104 void usteer_timeout_init(struct usteer_timeout_queue
*q
)
106 avl_init(&q
->tree
, usteer_timeout_cmp
, true, NULL
);
107 q
->timeout
.cb
= usteer_timeout_cb
;
110 static void __usteer_timeout_cancel(struct usteer_timeout_queue
*q
,
111 struct usteer_timeout
*t
)
113 avl_delete(&q
->tree
, &t
->node
);
116 void usteer_timeout_set(struct usteer_timeout_queue
*q
, struct usteer_timeout
*t
,
119 uint32_t time
= ampgr_timeout_current_time();
120 uint32_t val
= time
+ msecs
;
123 q
->tree
.cmp_ptr
= (void *) (intptr_t) time
;
124 if (usteer_timeout_isset(t
)) {
125 if (avl_is_first(&q
->tree
, &t
->node
))
128 __usteer_timeout_cancel(q
, t
);
131 t
->node
.key
= (void *) (intptr_t) val
;
132 avl_insert(&q
->tree
, &t
->node
);
133 if (avl_is_first(&q
->tree
, &t
->node
))
137 usteer_timeout_recalc(q
, time
);
140 void usteer_timeout_cancel(struct usteer_timeout_queue
*q
,
141 struct usteer_timeout
*t
)
143 if (!usteer_timeout_isset(t
))
146 __usteer_timeout_cancel(q
, t
);
147 memset(&t
->node
.list
, 0, sizeof(t
->node
.list
));
150 void usteer_timeout_flush(struct usteer_timeout_queue
*q
)
152 struct usteer_timeout
*t
, *tmp
;
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
));