1 /*
2 * Copyright (C) 2014 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at
34 * [email protected]
35 *
36 */
37
38 #define BTSTACK_FILE__ "btstack_run_loop.c"
39
40 /*
41 * run_loop.c
42 *
43 * Created by Matthias Ringwald on 6/6/09.
44 */
45
46 #include "btstack_run_loop.h"
47
48 #include "btstack_debug.h"
49 #include "btstack_config.h"
50 #include "btstack_util.h"
51
52 #include <inttypes.h>
53
54 static const btstack_run_loop_t * the_run_loop = NULL;
55
56 extern const btstack_run_loop_t btstack_run_loop_embedded;
57
58 /*
59 * Portable implementation of timer and data source management as base for platform specific implementations
60 */
61
62 // private data (access only by run loop implementations)
63 btstack_linked_list_t btstack_run_loop_base_timers;
64 btstack_linked_list_t btstack_run_loop_base_data_sources;
65 btstack_linked_list_t btstack_run_loop_base_callbacks;
66
btstack_run_loop_base_init(void)67 void btstack_run_loop_base_init(void){
68 btstack_run_loop_base_timers = NULL;
69 btstack_run_loop_base_data_sources = NULL;
70 btstack_run_loop_base_callbacks = NULL;
71 }
72
btstack_run_loop_base_add_data_source(btstack_data_source_t * data_source)73 void btstack_run_loop_base_add_data_source(btstack_data_source_t * data_source){
74 btstack_linked_list_add(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) data_source);
75 }
76
btstack_run_loop_base_remove_data_source(btstack_data_source_t * data_source)77 bool btstack_run_loop_base_remove_data_source(btstack_data_source_t * data_source){
78 return btstack_linked_list_remove(&btstack_run_loop_base_data_sources, (btstack_linked_item_t *) data_source);
79 }
80
btstack_run_loop_base_enable_data_source_callbacks(btstack_data_source_t * data_source,uint16_t callback_types)81 void btstack_run_loop_base_enable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callback_types){
82 data_source->flags |= callback_types;
83 }
84
btstack_run_loop_base_disable_data_source_callbacks(btstack_data_source_t * data_source,uint16_t callback_types)85 void btstack_run_loop_base_disable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callback_types){
86 data_source->flags &= ~callback_types;
87 }
88
btstack_run_loop_base_remove_timer(btstack_timer_source_t * timer)89 bool btstack_run_loop_base_remove_timer(btstack_timer_source_t * timer){
90 return btstack_linked_list_remove(&btstack_run_loop_base_timers, (btstack_linked_item_t *) timer);
91 }
92
btstack_run_loop_base_add_timer(btstack_timer_source_t * timer)93 void btstack_run_loop_base_add_timer(btstack_timer_source_t * timer){
94 btstack_linked_item_t *it;
95 for (it = (btstack_linked_item_t *) &btstack_run_loop_base_timers; it->next ; it = it->next){
96 btstack_timer_source_t * next = (btstack_timer_source_t *) it->next;
97
98 if (next == timer){
99 log_error("Timer %p already registered! Please read source code comment.", (void*)timer);
100 //
101 // Dear BTstack User!
102 //
103 // If you hit the assert below, your application code tried to add a timer to the list of
104 // timers that's already in the timer list, i.e., it's already registered.
105 //
106 // As you've probably already modified the timer, just ignoring this might lead to unexpected
107 // and hard to debug issues. Instead, we decided to raise an assert in this case to help.
108 //
109 // Please do a backtrace and check where you register this timer.
110 // If you just want to restart it you can call btstack_run_loop_timer_remove(..) before restarting the timer.
111 //
112 btstack_assert(false);
113 }
114
115 int32_t delta = btstack_time_delta(timer->timeout, next->timeout);
116 if (delta < 0) break;
117 }
118 timer->item.next = it->next;
119 it->next = (btstack_linked_item_t *) timer;
120 }
121
btstack_run_loop_base_process_timers(uint32_t now)122 void btstack_run_loop_base_process_timers(uint32_t now){
123 // process timers, exit when timeout is in the future
124 while (btstack_run_loop_base_timers) {
125 btstack_timer_source_t * timer = (btstack_timer_source_t *) btstack_run_loop_base_timers;
126 int32_t delta = btstack_time_delta(timer->timeout, now);
127 if (delta > 0) break;
128 btstack_run_loop_base_remove_timer(timer);
129 timer->process(timer);
130 }
131 }
132
btstack_run_loop_base_dump_timer(void)133 void btstack_run_loop_base_dump_timer(void){
134 #ifdef ENABLE_LOG_INFO
135 btstack_linked_item_t *it;
136 uint16_t i = 0;
137 for (it = (btstack_linked_item_t *) btstack_run_loop_base_timers; it ; it = it->next){
138 btstack_timer_source_t * timer = (btstack_timer_source_t*) it;
139 log_info("timer %u (%p): timeout %" PRIbtstack_time_t "\n", i, (void *) timer, timer->timeout);
140 }
141 #endif
142
143 }
144 /**
145 * @brief Get time until first timer fires
146 * @return -1 if no timers, time until next timeout otherwise
147 */
btstack_run_loop_base_get_time_until_timeout(uint32_t now)148 int32_t btstack_run_loop_base_get_time_until_timeout(uint32_t now){
149 if (btstack_run_loop_base_timers == NULL) return -1;
150 btstack_timer_source_t * timer = (btstack_timer_source_t *) btstack_run_loop_base_timers;
151 uint32_t list_timeout = timer->timeout;
152 int32_t delta = btstack_time_delta(list_timeout, now);
153 if (delta < 0){
154 delta = 0;
155 }
156 return delta;
157 }
158
btstack_run_loop_base_poll_data_sources(void)159 void btstack_run_loop_base_poll_data_sources(void){
160 // poll data sources
161 btstack_data_source_t *ds;
162 btstack_data_source_t *next;
163 for (ds = (btstack_data_source_t *) btstack_run_loop_base_data_sources; ds != NULL ; ds = next){
164 next = (btstack_data_source_t *) ds->item.next; // cache pointer to next data_source to allow data source to remove itself
165 if (ds->flags & DATA_SOURCE_CALLBACK_POLL){
166 ds->process(ds, DATA_SOURCE_CALLBACK_POLL);
167 }
168 }
169 }
170
btstack_run_loop_base_add_callback(btstack_context_callback_registration_t * callback_registration)171 void btstack_run_loop_base_add_callback(btstack_context_callback_registration_t * callback_registration){
172 btstack_linked_list_add_tail(&btstack_run_loop_base_callbacks, (btstack_linked_item_t *) callback_registration);
173 }
174
175
btstack_run_loop_base_execute_callbacks(void)176 void btstack_run_loop_base_execute_callbacks(void){
177 while (1){
178 btstack_context_callback_registration_t * callback_registration = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&btstack_run_loop_base_callbacks);
179 if (callback_registration == NULL){
180 break;
181 }
182 (*callback_registration->callback)(callback_registration->context);
183 }
184 }
185
186
187 /**
188 * BTstack Run Loop Implementation, mainly dispatches to port-specific implementation
189 */
190
191 // main implementation
192
btstack_run_loop_set_timer_handler(btstack_timer_source_t * timer,void (* process)(btstack_timer_source_t * _timer))193 void btstack_run_loop_set_timer_handler(btstack_timer_source_t * timer, void (*process)(btstack_timer_source_t * _timer)){
194 timer->process = process;
195 }
196
btstack_run_loop_set_data_source_handler(btstack_data_source_t * data_source,void (* process)(btstack_data_source_t * _data_source,btstack_data_source_callback_type_t callback_type))197 void btstack_run_loop_set_data_source_handler(btstack_data_source_t * data_source, void (*process)(btstack_data_source_t *_data_source, btstack_data_source_callback_type_t callback_type)){
198 data_source->process = process;
199 }
200
btstack_run_loop_set_data_source_fd(btstack_data_source_t * data_source,int fd)201 void btstack_run_loop_set_data_source_fd(btstack_data_source_t * data_source, int fd){
202 data_source->source.fd = fd;
203 }
204
btstack_run_loop_get_data_source_fd(btstack_data_source_t * data_source)205 int btstack_run_loop_get_data_source_fd(btstack_data_source_t * data_source){
206 return data_source->source.fd;
207 }
208
btstack_run_loop_set_data_source_handle(btstack_data_source_t * data_source,void * handle)209 void btstack_run_loop_set_data_source_handle(btstack_data_source_t * data_source, void * handle){
210 data_source->source.handle = handle;
211 }
212
btstack_run_loop_get_data_source_handle(btstack_data_source_t * data_source)213 void * btstack_run_loop_get_data_source_handle(btstack_data_source_t * data_source){
214 return data_source->source.handle;
215 }
216
btstack_run_loop_enable_data_source_callbacks(btstack_data_source_t * data_source,uint16_t callbacks)217 void btstack_run_loop_enable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks){
218 btstack_assert(the_run_loop != NULL);
219 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL);
220 the_run_loop->enable_data_source_callbacks(data_source, callbacks);
221 }
222
btstack_run_loop_disable_data_source_callbacks(btstack_data_source_t * data_source,uint16_t callbacks)223 void btstack_run_loop_disable_data_source_callbacks(btstack_data_source_t * data_source, uint16_t callbacks){
224 btstack_assert(the_run_loop != NULL);
225 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL);
226 the_run_loop->disable_data_source_callbacks(data_source, callbacks);
227 }
228
229 /**
230 * Add data_source to run_loop
231 */
btstack_run_loop_add_data_source(btstack_data_source_t * data_source)232 void btstack_run_loop_add_data_source(btstack_data_source_t * data_source){
233 btstack_assert(the_run_loop != NULL);
234 btstack_assert(the_run_loop->enable_data_source_callbacks != NULL);
235 btstack_assert(data_source->process != NULL);
236 the_run_loop->add_data_source(data_source);
237 }
238
239 /**
240 * Remove data_source from run loop
241 */
btstack_run_loop_remove_data_source(btstack_data_source_t * data_source)242 int btstack_run_loop_remove_data_source(btstack_data_source_t * data_source){
243 btstack_assert(the_run_loop != NULL);
244 btstack_assert(the_run_loop->disable_data_source_callbacks != NULL);
245 btstack_assert(data_source->process != NULL);
246 return the_run_loop->remove_data_source(data_source);
247 }
248
btstack_run_loop_poll_data_sources_from_irq(void)249 void btstack_run_loop_poll_data_sources_from_irq(void){
250 btstack_assert(the_run_loop != NULL);
251 btstack_assert(the_run_loop->poll_data_sources_from_irq != NULL);
252 the_run_loop->poll_data_sources_from_irq();
253 }
254
btstack_run_loop_set_timer(btstack_timer_source_t * timer,uint32_t timeout_in_ms)255 void btstack_run_loop_set_timer(btstack_timer_source_t *timer, uint32_t timeout_in_ms){
256 btstack_assert(the_run_loop != NULL);
257 the_run_loop->set_timer(timer, timeout_in_ms);
258 }
259
260 /**
261 * @brief Set context for this timer
262 */
btstack_run_loop_set_timer_context(btstack_timer_source_t * timer,void * context)263 void btstack_run_loop_set_timer_context(btstack_timer_source_t * timer, void * context){
264 timer->context = context;
265 }
266
267 /**
268 * @brief Get context for this timer
269 */
btstack_run_loop_get_timer_context(btstack_timer_source_t * timer)270 void * btstack_run_loop_get_timer_context(btstack_timer_source_t * timer){
271 return timer->context;
272 }
273
274 /**
275 * Add timer to run_loop (keep list sorted)
276 */
btstack_run_loop_add_timer(btstack_timer_source_t * timer)277 void btstack_run_loop_add_timer(btstack_timer_source_t * timer){
278 btstack_assert(the_run_loop != NULL);
279 btstack_assert(timer->process != NULL);
280 the_run_loop->add_timer(timer);
281 }
282
283 /**
284 * Remove timer from run loop
285 */
btstack_run_loop_remove_timer(btstack_timer_source_t * timer)286 int btstack_run_loop_remove_timer(btstack_timer_source_t * timer){
287 btstack_assert(the_run_loop != NULL);
288 return the_run_loop->remove_timer(timer);
289 }
290
291 /**
292 * @brief Get current time in ms
293 */
btstack_run_loop_get_time_ms(void)294 uint32_t btstack_run_loop_get_time_ms(void){
295 btstack_assert(the_run_loop != NULL);
296 return the_run_loop->get_time_ms();
297 }
298
299
btstack_run_loop_timer_dump(void)300 void btstack_run_loop_timer_dump(void){
301 btstack_assert(the_run_loop != NULL);
302 the_run_loop->dump_timer();
303 }
304
305 /**
306 * Execute run_loop
307 */
btstack_run_loop_execute(void)308 void btstack_run_loop_execute(void){
309 btstack_assert(the_run_loop != NULL);
310 the_run_loop->execute();
311 }
312
btstack_run_loop_trigger_exit(void)313 void btstack_run_loop_trigger_exit(void){
314 btstack_assert(the_run_loop != NULL);
315 btstack_assert(the_run_loop->trigger_exit != NULL);
316 the_run_loop->trigger_exit();
317 }
318
btstack_run_loop_execute_on_main_thread(btstack_context_callback_registration_t * callback_registration)319 void btstack_run_loop_execute_on_main_thread(btstack_context_callback_registration_t * callback_registration){
320 btstack_assert(the_run_loop != NULL);
321 btstack_assert(the_run_loop->execute_on_main_thread != NULL);
322 the_run_loop->execute_on_main_thread(callback_registration);
323 }
324
325 // init must be called before any other run_loop call
btstack_run_loop_init(const btstack_run_loop_t * run_loop)326 void btstack_run_loop_init(const btstack_run_loop_t * run_loop){
327 btstack_assert(the_run_loop == NULL);
328 the_run_loop = run_loop;
329 the_run_loop->init();
330 }
331
btstack_run_loop_deinit(void)332 void btstack_run_loop_deinit(void){
333 the_run_loop = NULL;
334 }
335
336