2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
30 struct tree_entry entry
;
32 struct list wait_list
;
35 static struct tree timer_tree
;
36 static mutex_t timer_tree_mutex
;
39 static thread_t timer_thread
;
40 static cond_t timer_cond
;
41 static uchar_efficient_t timer_thread_exit
;
44 static inline void timer_lock(void)
46 mutex_lock(&timer_tree_mutex
);
49 static inline void timer_unlock(void)
51 mutex_unlock(&timer_tree_mutex
);
54 static bool timer_first(ajla_time_t
*f
)
59 e
= tree_first(&timer_tree
);
63 t
= get_struct(e
, struct timer
, entry
);
64 if (list_is_empty(&t
->wait_list
)) {
65 e
= tree_next(&t
->entry
);
66 tree_delete(&t
->entry
);
78 uint32_t timer_wait_now(void)
80 uint32_t u
= IOMUX_INDEFINITE_WAIT
;
83 if (timer_first(&mt
)) {
84 ajla_time_t m
= os_time_monotonic();
87 } else if (unlikely(mt
- m
>= IOMUX_INDEFINITE_WAIT
- 1)) {
88 u
= IOMUX_INDEFINITE_WAIT
- 1;
97 static int timer_compare(const struct tree_entry
*e
, uintptr_t mtp
)
99 struct timer
*t
= get_struct(e
, struct timer
, entry
);
100 ajla_time_t mt
= *cast_ptr(ajla_time_t
*, num_to_ptr(mtp
));
108 bool timer_register_wait(ajla_time_t mt
, mutex_t
**mutex_to_lock
, struct list
*list_entry
, ajla_error_t
*err
)
110 struct tree_insert_position ins
;
112 struct tree_entry
*e
;
116 e
= tree_find_for_insert(&timer_tree
, timer_compare
, ptr_to_num(&mt
), &ins
);
117 if (unlikely(e
!= NULL
)) {
118 t
= get_struct(e
, struct timer
, entry
);
120 t
= mem_alloc_mayfail(struct timer
*, sizeof(struct timer
), err
);
126 list_init(&t
->wait_list
);
127 tree_insert_after_find(&t
->entry
, &ins
);
130 *mutex_to_lock
= &timer_tree_mutex
;
131 list_add(&t
->wait_list
, list_entry
);
134 if (tree_first(&timer_tree
) == &t
->entry
) {
139 cond_lock(&timer_cond
);
140 cond_unlock_signal(&timer_cond
);
153 void timer_check_all(void)
155 struct tree_entry
*e
;
158 e
= tree_first(&timer_tree
);
159 if (unlikely(e
!= NULL
)) {
160 ajla_time_t m
= os_time_monotonic();
162 t
= get_struct(e
, struct timer
, entry
);
164 tree_delete(&t
->entry
);
165 call(wake_up_wait_list
)(&t
->wait_list
, &timer_tree_mutex
, true);
174 thread_function_decl(timer_thread_fn
,
175 cond_lock(&timer_cond
);
176 while (likely(!timer_thread_exit
)) {
178 us
= timer_wait_now();
179 if (us
== IOMUX_INDEFINITE_WAIT
)
180 cond_wait(&timer_cond
);
182 cond_wait_us(&timer_cond
, us
);
185 cond_unlock(&timer_cond
);
189 void timer_init(void)
191 tree_init(&timer_tree
);
192 mutex_init(&timer_tree_mutex
);
194 cond_init(&timer_cond
);
195 timer_thread_exit
= 0;
196 thread_spawn(&timer_thread
, timer_thread_fn
, NULL
, PRIORITY_TIMER
, NULL
);
200 void timer_done(void)
203 cond_lock(&timer_cond
);
204 timer_thread_exit
= 1;
205 cond_unlock_signal(&timer_cond
);
206 thread_join(&timer_thread
);
207 cond_done(&timer_cond
);
209 while (unlikely(!tree_is_empty(&timer_tree
))) {
210 struct timer
*t
= get_struct(tree_any(&timer_tree
), struct timer
, entry
);
211 tree_delete(&t
->entry
);
214 mutex_done(&timer_tree_mutex
);