xref: /btstack/platform/posix/btstack_run_loop_posix.c (revision b7832c7f15aef48dc138b5f23b2d3434da52a201)
1b7d596c1SMatthias Ringwald /*
2b7d596c1SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3b7d596c1SMatthias Ringwald  *
4b7d596c1SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5b7d596c1SMatthias Ringwald  * modification, are permitted provided that the following conditions
6b7d596c1SMatthias Ringwald  * are met:
7b7d596c1SMatthias Ringwald  *
8b7d596c1SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9b7d596c1SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10b7d596c1SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11b7d596c1SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12b7d596c1SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13b7d596c1SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14b7d596c1SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15b7d596c1SMatthias Ringwald  *    from this software without specific prior written permission.
16b7d596c1SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17b7d596c1SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18b7d596c1SMatthias Ringwald  *    monetary gain.
19b7d596c1SMatthias Ringwald  *
20b7d596c1SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21b7d596c1SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22b7d596c1SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23b7d596c1SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24b7d596c1SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25b7d596c1SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26b7d596c1SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27b7d596c1SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28b7d596c1SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29b7d596c1SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30b7d596c1SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b7d596c1SMatthias Ringwald  * SUCH DAMAGE.
32b7d596c1SMatthias Ringwald  *
33b7d596c1SMatthias Ringwald  * Please inquire about commercial licensing options at
34b7d596c1SMatthias Ringwald  * [email protected]
35b7d596c1SMatthias Ringwald  *
36b7d596c1SMatthias Ringwald  */
37b7d596c1SMatthias Ringwald 
38ab2c6ae4SMatthias Ringwald #define __BTSTACK_FILE__ "btstack_run_loop_posix.c"
39ab2c6ae4SMatthias Ringwald 
40b7d596c1SMatthias Ringwald /*
414ab92137SMatthias Ringwald  *  btstack_run_loop.c
42b7d596c1SMatthias Ringwald  *
43b7d596c1SMatthias Ringwald  *  Created by Matthias Ringwald on 6/6/09.
44b7d596c1SMatthias Ringwald  */
45b7d596c1SMatthias Ringwald 
46b7d596c1SMatthias Ringwald #include "btstack_run_loop.h"
478f2a52f4SMatthias Ringwald #include "btstack_run_loop_posix.h"
48b7d596c1SMatthias Ringwald #include "btstack_linked_list.h"
49b7d596c1SMatthias Ringwald #include "btstack_debug.h"
50b7d596c1SMatthias Ringwald 
51b7d596c1SMatthias Ringwald #ifdef _WIN32
52b7d596c1SMatthias Ringwald #include "Winsock2.h"
53b7d596c1SMatthias Ringwald #else
54b7d596c1SMatthias Ringwald #include <sys/select.h>
55b7d596c1SMatthias Ringwald #endif
56f316a845SMatthias Ringwald 
57b7d596c1SMatthias Ringwald #include <stdio.h>
58b7d596c1SMatthias Ringwald #include <stdlib.h>
59f316a845SMatthias Ringwald #include <sys/time.h>
60b7d596c1SMatthias Ringwald 
61528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_dump_timer(void);
62b7d596c1SMatthias Ringwald 
63b7d596c1SMatthias Ringwald // the run loop
648f2a52f4SMatthias Ringwald static btstack_linked_list_t data_sources;
65b7d596c1SMatthias Ringwald static int data_sources_modified;
668f2a52f4SMatthias Ringwald static btstack_linked_list_t timers;
67f316a845SMatthias Ringwald // start time. tv_usec = 0
68b7d596c1SMatthias Ringwald static struct timeval init_tv;
69b7d596c1SMatthias Ringwald 
70b7d596c1SMatthias Ringwald /**
71b7d596c1SMatthias Ringwald  * Add data_source to run_loop
72b7d596c1SMatthias Ringwald  */
73ec820d77SMatthias Ringwald static void btstack_run_loop_posix_add_data_source(btstack_data_source_t *ds){
74b7d596c1SMatthias Ringwald     data_sources_modified = 1;
75528a4a3bSMatthias Ringwald     // log_info("btstack_run_loop_posix_add_data_source %x with fd %u\n", (int) ds, ds->fd);
76b7d596c1SMatthias Ringwald     btstack_linked_list_add(&data_sources, (btstack_linked_item_t *) ds);
77b7d596c1SMatthias Ringwald }
78b7d596c1SMatthias Ringwald 
79b7d596c1SMatthias Ringwald /**
80b7d596c1SMatthias Ringwald  * Remove data_source from run loop
81b7d596c1SMatthias Ringwald  */
82ec820d77SMatthias Ringwald static int btstack_run_loop_posix_remove_data_source(btstack_data_source_t *ds){
83b7d596c1SMatthias Ringwald     data_sources_modified = 1;
84528a4a3bSMatthias Ringwald     // log_info("btstack_run_loop_posix_remove_data_source %x\n", (int) ds);
85b7d596c1SMatthias Ringwald     return btstack_linked_list_remove(&data_sources, (btstack_linked_item_t *) ds);
86b7d596c1SMatthias Ringwald }
87b7d596c1SMatthias Ringwald 
88b7d596c1SMatthias Ringwald /**
89b7d596c1SMatthias Ringwald  * Add timer to run_loop (keep list sorted)
90b7d596c1SMatthias Ringwald  */
91ec820d77SMatthias Ringwald static void btstack_run_loop_posix_add_timer(btstack_timer_source_t *ts){
92b7d596c1SMatthias Ringwald     btstack_linked_item_t *it;
93b7d596c1SMatthias Ringwald     for (it = (btstack_linked_item_t *) &timers; it->next ; it = it->next){
94f316a845SMatthias Ringwald         btstack_timer_source_t * next = (btstack_timer_source_t *) it->next;
95f316a845SMatthias Ringwald         if (next == ts){
96528a4a3bSMatthias Ringwald             log_error( "btstack_run_loop_timer_add error: timer to add already in list!");
97b7d596c1SMatthias Ringwald             return;
98b7d596c1SMatthias Ringwald         }
99f316a845SMatthias Ringwald         if (next->timeout > ts->timeout) {
100b7d596c1SMatthias Ringwald             break;
101b7d596c1SMatthias Ringwald         }
102b7d596c1SMatthias Ringwald     }
103b7d596c1SMatthias Ringwald     ts->item.next = it->next;
104b7d596c1SMatthias Ringwald     it->next = (btstack_linked_item_t *) ts;
105f316a845SMatthias Ringwald     log_debug("Added timer %p at %u\n", ts, ts->timeout);
106528a4a3bSMatthias Ringwald     // btstack_run_loop_posix_dump_timer();
107b7d596c1SMatthias Ringwald }
108b7d596c1SMatthias Ringwald 
109b7d596c1SMatthias Ringwald /**
110b7d596c1SMatthias Ringwald  * Remove timer from run loop
111b7d596c1SMatthias Ringwald  */
112ec820d77SMatthias Ringwald static int btstack_run_loop_posix_remove_timer(btstack_timer_source_t *ts){
113b7d596c1SMatthias Ringwald     // log_info("Removed timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec);
114528a4a3bSMatthias Ringwald     // btstack_run_loop_posix_dump_timer();
115b7d596c1SMatthias Ringwald     return btstack_linked_list_remove(&timers, (btstack_linked_item_t *) ts);
116b7d596c1SMatthias Ringwald }
117b7d596c1SMatthias Ringwald 
118528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_dump_timer(void){
119b7d596c1SMatthias Ringwald     btstack_linked_item_t *it;
120b7d596c1SMatthias Ringwald     int i = 0;
121b7d596c1SMatthias Ringwald     for (it = (btstack_linked_item_t *) timers; it ; it = it->next){
122ec820d77SMatthias Ringwald         btstack_timer_source_t *ts = (btstack_timer_source_t*) it;
123f316a845SMatthias Ringwald         log_info("timer %u, timeout %u\n", i, ts->timeout);
124b7d596c1SMatthias Ringwald     }
125b7d596c1SMatthias Ringwald }
126b7d596c1SMatthias Ringwald 
1279120e843SMatthias Ringwald static void btstack_run_loop_posix_enable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){
1289120e843SMatthias Ringwald     ds->flags |= callback_types;
1299120e843SMatthias Ringwald }
1309120e843SMatthias Ringwald 
1319120e843SMatthias Ringwald static void btstack_run_loop_posix_disable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){
1329120e843SMatthias Ringwald     ds->flags &= ~callback_types;
1339120e843SMatthias Ringwald }
1349120e843SMatthias Ringwald 
135b7d596c1SMatthias Ringwald /**
136f316a845SMatthias Ringwald  * @brief Queries the current time in ms since start
137f316a845SMatthias Ringwald  */
138f316a845SMatthias Ringwald static uint32_t btstack_run_loop_posix_get_time_ms(void){
139f316a845SMatthias Ringwald     struct timeval tv;
140f316a845SMatthias Ringwald     gettimeofday(&tv, NULL);
1417c959318SMatthias Ringwald     uint32_t time_ms = (uint32_t)((tv.tv_sec  - init_tv.tv_sec) * 1000) + (tv.tv_usec / 1000);
142615ae444SMatthias Ringwald     log_debug("btstack_run_loop_posix_get_time_ms: %u <- %u / %u", time_ms, (int) tv.tv_sec, (int) tv.tv_usec);
143f316a845SMatthias Ringwald     return time_ms;
144f316a845SMatthias Ringwald }
145f316a845SMatthias Ringwald 
146f316a845SMatthias Ringwald /**
147b7d596c1SMatthias Ringwald  * Execute run_loop
148b7d596c1SMatthias Ringwald  */
149528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_execute(void) {
1509120e843SMatthias Ringwald     fd_set descriptors_read;
1519120e843SMatthias Ringwald     fd_set descriptors_write;
152b7d596c1SMatthias Ringwald 
153ec820d77SMatthias Ringwald     btstack_timer_source_t       *ts;
154b7d596c1SMatthias Ringwald     btstack_linked_list_iterator_t it;
155f316a845SMatthias Ringwald     struct timeval * timeout;
156f316a845SMatthias Ringwald     struct timeval tv;
157f316a845SMatthias Ringwald     uint32_t now_ms;
158b7d596c1SMatthias Ringwald 
159b7d596c1SMatthias Ringwald     while (1) {
160b7d596c1SMatthias Ringwald         // collect FDs
1619120e843SMatthias Ringwald         FD_ZERO(&descriptors_read);
1629120e843SMatthias Ringwald         FD_ZERO(&descriptors_write);
163f316a845SMatthias Ringwald         int highest_fd = -1;
164b7d596c1SMatthias Ringwald         btstack_linked_list_iterator_init(&it, &data_sources);
165b7d596c1SMatthias Ringwald         while (btstack_linked_list_iterator_has_next(&it)){
166ec820d77SMatthias Ringwald             btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it);
1679120e843SMatthias Ringwald             if (ds->fd < 0) continue;
1689120e843SMatthias Ringwald             if (ds->flags & DATA_SOURCE_CALLBACK_READ){
1699120e843SMatthias Ringwald                 FD_SET(ds->fd, &descriptors_read);
1709120e843SMatthias Ringwald                 if (ds->fd > highest_fd) {
1719120e843SMatthias Ringwald                     highest_fd = ds->fd;
1729120e843SMatthias Ringwald                 }
173f316a845SMatthias Ringwald                 log_debug("btstack_run_loop_execute adding fd %u for read", ds->fd);
1749120e843SMatthias Ringwald             }
1759120e843SMatthias Ringwald             if (ds->flags & DATA_SOURCE_CALLBACK_WRITE){
1769120e843SMatthias Ringwald                 FD_SET(ds->fd, &descriptors_write);
177b7d596c1SMatthias Ringwald                 if (ds->fd > highest_fd) {
178b7d596c1SMatthias Ringwald                     highest_fd = ds->fd;
179b7d596c1SMatthias Ringwald                 }
180f316a845SMatthias Ringwald                 log_debug("btstack_run_loop_execute adding fd %u for write", ds->fd);
181b7d596c1SMatthias Ringwald             }
182b7d596c1SMatthias Ringwald         }
183b7d596c1SMatthias Ringwald 
184b7d596c1SMatthias Ringwald         // get next timeout
185b7d596c1SMatthias Ringwald         timeout = NULL;
186b7d596c1SMatthias Ringwald         if (timers) {
187ec820d77SMatthias Ringwald             ts = (btstack_timer_source_t *) timers;
188f316a845SMatthias Ringwald             timeout = &tv;
189f316a845SMatthias Ringwald             now_ms = btstack_run_loop_posix_get_time_ms();
190f316a845SMatthias Ringwald             int delta = ts->timeout - now_ms;
191f316a845SMatthias Ringwald             if (delta < 0){
192f316a845SMatthias Ringwald                 delta = 0;
193b7d596c1SMatthias Ringwald             }
194f316a845SMatthias Ringwald             tv.tv_sec  = delta / 1000;
1957c959318SMatthias Ringwald             tv.tv_usec = (int) (delta - (tv.tv_sec * 1000)) * 1000;
196f316a845SMatthias Ringwald             log_debug("btstack_run_loop_execute next timeout in %u ms", delta);
197b7d596c1SMatthias Ringwald         }
198b7d596c1SMatthias Ringwald 
199b7d596c1SMatthias Ringwald         // wait for ready FDs
2009120e843SMatthias Ringwald         select( highest_fd+1 , &descriptors_read, &descriptors_write, NULL, timeout);
201b7d596c1SMatthias Ringwald 
20288e0b3b2SMatthias Ringwald 
203b7d596c1SMatthias Ringwald         data_sources_modified = 0;
204b7d596c1SMatthias Ringwald         btstack_linked_list_iterator_init(&it, &data_sources);
205b7d596c1SMatthias Ringwald         while (btstack_linked_list_iterator_has_next(&it) && !data_sources_modified){
206ec820d77SMatthias Ringwald             btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it);
207d382f531SMatthias Ringwald             log_debug("btstack_run_loop_posix_execute: check ds %p with fd %u\n", ds, ds->fd);
2089120e843SMatthias Ringwald             if (FD_ISSET(ds->fd, &descriptors_read)) {
209d382f531SMatthias Ringwald                 log_debug("btstack_run_loop_posix_execute: process read ds %p with fd %u\n", ds, ds->fd);
2107cd5ef95SMatthias Ringwald                 ds->process(ds, DATA_SOURCE_CALLBACK_READ);
211b7d596c1SMatthias Ringwald             }
2129120e843SMatthias Ringwald             if (FD_ISSET(ds->fd, &descriptors_write)) {
213d382f531SMatthias Ringwald                 log_debug("btstack_run_loop_posix_execute: process write ds %p with fd %u\n", ds, ds->fd);
2149120e843SMatthias Ringwald                 ds->process(ds, DATA_SOURCE_CALLBACK_WRITE);
2159120e843SMatthias Ringwald             }
216b7d596c1SMatthias Ringwald         }
217f316a845SMatthias Ringwald         log_debug("btstack_run_loop_posix_execute: after ds check\n");
218b7d596c1SMatthias Ringwald 
219b7d596c1SMatthias Ringwald         // process timers
22088e0b3b2SMatthias Ringwald         now_ms = btstack_run_loop_posix_get_time_ms();
221b7d596c1SMatthias Ringwald         while (timers) {
222ec820d77SMatthias Ringwald             ts = (btstack_timer_source_t *) timers;
223f316a845SMatthias Ringwald             if (ts->timeout > now_ms) break;
224f316a845SMatthias Ringwald             log_debug("btstack_run_loop_posix_execute: process timer %p\n", ts);
225b7d596c1SMatthias Ringwald 
226b7d596c1SMatthias Ringwald             // remove timer before processing it to allow handler to re-register with run loop
227*b7832c7fSMatthias Ringwald             btstack_run_loop_posix_remove_timer(ts);
228b7d596c1SMatthias Ringwald             ts->process(ts);
229b7d596c1SMatthias Ringwald         }
230b7d596c1SMatthias Ringwald     }
231b7d596c1SMatthias Ringwald }
232b7d596c1SMatthias Ringwald 
233b7d596c1SMatthias Ringwald // set timer
234ec820d77SMatthias Ringwald static void btstack_run_loop_posix_set_timer(btstack_timer_source_t *a, uint32_t timeout_in_ms){
235f316a845SMatthias Ringwald     uint32_t time_ms = btstack_run_loop_posix_get_time_ms();
236f316a845SMatthias Ringwald     a->timeout = time_ms + timeout_in_ms;
237615ae444SMatthias Ringwald     log_debug("btstack_run_loop_posix_set_timer to %u ms (now %u, timeout %u)", a->timeout, time_ms, timeout_in_ms);
238b7d596c1SMatthias Ringwald }
239b7d596c1SMatthias Ringwald 
240528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_init(void){
241b7d596c1SMatthias Ringwald     data_sources = NULL;
242b7d596c1SMatthias Ringwald     timers = NULL;
243f316a845SMatthias Ringwald     // just assume that we started at tv_usec == 0
244b7d596c1SMatthias Ringwald     gettimeofday(&init_tv, NULL);
245f316a845SMatthias Ringwald     init_tv.tv_usec = 0;
246f316a845SMatthias Ringwald     log_debug("btstack_run_loop_posix_init at %u/%u", (int) init_tv.tv_sec, 0);
247b7d596c1SMatthias Ringwald }
248b7d596c1SMatthias Ringwald 
249b7d596c1SMatthias Ringwald 
250528a4a3bSMatthias Ringwald static const btstack_run_loop_t btstack_run_loop_posix = {
251528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_init,
252528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_add_data_source,
253528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_remove_data_source,
2549120e843SMatthias Ringwald     &btstack_run_loop_posix_enable_data_source_callbacks,
2559120e843SMatthias Ringwald     &btstack_run_loop_posix_disable_data_source_callbacks,
256528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_set_timer,
257528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_add_timer,
258528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_remove_timer,
259528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_execute,
260528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_dump_timer,
261528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_get_time_ms,
262b7d596c1SMatthias Ringwald };
263b7d596c1SMatthias Ringwald 
264b7d596c1SMatthias Ringwald /**
265528a4a3bSMatthias Ringwald  * Provide btstack_run_loop_posix instance
266b7d596c1SMatthias Ringwald  */
267528a4a3bSMatthias Ringwald const btstack_run_loop_t * btstack_run_loop_posix_get_instance(void){
268528a4a3bSMatthias Ringwald     return &btstack_run_loop_posix;
269b7d596c1SMatthias Ringwald }
270b7d596c1SMatthias Ringwald 
271