xref: /btstack/platform/posix/btstack_run_loop_posix.c (revision dbeaa5cd7b75285b708462a3fc9fbbfda5cda24c)
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
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH 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 
38e501bae0SMatthias 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 
4692b78dd7SMatthias Ringwald // enable POSIX functions (needed for -std=c99)
4792b78dd7SMatthias Ringwald #define _POSIX_C_SOURCE 200809
4892b78dd7SMatthias Ringwald 
498f2a52f4SMatthias Ringwald #include "btstack_run_loop_posix.h"
50b6fc147fSMatthias Ringwald 
51b6fc147fSMatthias Ringwald #include "btstack_run_loop.h"
52b6fc147fSMatthias Ringwald #include "btstack_util.h"
53b7d596c1SMatthias Ringwald #include "btstack_linked_list.h"
54b7d596c1SMatthias Ringwald #include "btstack_debug.h"
55b7d596c1SMatthias Ringwald 
56b7d596c1SMatthias Ringwald #include <stdio.h>
57b7d596c1SMatthias Ringwald #include <stdlib.h>
58c663093bSMatthias Ringwald #include <sys/errno.h>
59b6fc147fSMatthias Ringwald #include <sys/select.h>
60f316a845SMatthias Ringwald #include <sys/time.h>
6192b78dd7SMatthias Ringwald #include <time.h>
6292b78dd7SMatthias Ringwald #include <unistd.h>
6341158b74SMatthias Ringwald #include <pthread.h>
64b7d596c1SMatthias Ringwald 
65b7d596c1SMatthias Ringwald // the run loop
6690d4f186SMatthias Ringwald static int btstack_run_loop_posix_data_sources_modified;
6792b78dd7SMatthias Ringwald 
6890d4f186SMatthias Ringwald static bool btstack_run_loop_posix_exit_requested;
692e357f7aSMatthias Ringwald 
7090d4f186SMatthias Ringwald // to trigger process callbacks other thread
7190d4f186SMatthias Ringwald static pthread_mutex_t       btstack_run_loop_posix_callbacks_mutex = PTHREAD_MUTEX_INITIALIZER;
7290d4f186SMatthias Ringwald static int                   btstack_run_loop_posix_process_callbacks_fd;
7390d4f186SMatthias Ringwald static btstack_data_source_t btstack_run_loop_posix_process_callbacks_ds;
7490d4f186SMatthias Ringwald 
7590d4f186SMatthias Ringwald // to trigger poll data sources from irq
7690d4f186SMatthias Ringwald static int                   btstack_run_loop_posix_poll_data_sources_fd;
7790d4f186SMatthias Ringwald static btstack_data_source_t btstack_run_loop_posix_poll_data_sources_ds;
7841158b74SMatthias Ringwald 
7992b78dd7SMatthias Ringwald // start time. tv_usec/tv_nsec = 0
8092b78dd7SMatthias Ringwald #ifdef _POSIX_MONOTONIC_CLOCK
8192b78dd7SMatthias Ringwald // use monotonic clock if available
8292b78dd7SMatthias Ringwald static struct timespec init_ts;
8392b78dd7SMatthias Ringwald #else
8492b78dd7SMatthias Ringwald // fallback to gettimeofday
85b7d596c1SMatthias Ringwald static struct timeval init_tv;
8692b78dd7SMatthias Ringwald #endif
87b7d596c1SMatthias Ringwald 
88b7d596c1SMatthias Ringwald /**
89b7d596c1SMatthias Ringwald  * Add data_source to run_loop
90b7d596c1SMatthias Ringwald  */
btstack_run_loop_posix_add_data_source(btstack_data_source_t * ds)91ec820d77SMatthias Ringwald static void btstack_run_loop_posix_add_data_source(btstack_data_source_t *ds){
9290d4f186SMatthias Ringwald     btstack_run_loop_posix_data_sources_modified = 1;
93075edf12SMatthias Ringwald     btstack_run_loop_base_add_data_source(ds);
94b7d596c1SMatthias Ringwald }
95b7d596c1SMatthias Ringwald 
96b7d596c1SMatthias Ringwald /**
97b7d596c1SMatthias Ringwald  * Remove data_source from run loop
98b7d596c1SMatthias Ringwald  */
btstack_run_loop_posix_remove_data_source(btstack_data_source_t * ds)99d58a1b5fSMatthias Ringwald static bool btstack_run_loop_posix_remove_data_source(btstack_data_source_t *ds){
10090d4f186SMatthias Ringwald     btstack_run_loop_posix_data_sources_modified = 1;
101075edf12SMatthias Ringwald     return btstack_run_loop_base_remove_data_source(ds);
1029120e843SMatthias Ringwald }
1039120e843SMatthias Ringwald 
10492b78dd7SMatthias Ringwald #ifdef _POSIX_MONOTONIC_CLOCK
10592b78dd7SMatthias Ringwald /**
10692b78dd7SMatthias Ringwald  * @brief Returns the timespec which represents the time(stop - start). It might be negative
10792b78dd7SMatthias Ringwald  */
timespec_diff(struct timespec * start,struct timespec * stop,struct timespec * result)10892b78dd7SMatthias Ringwald static void timespec_diff(struct timespec *start, struct timespec *stop, struct timespec *result){
10992b78dd7SMatthias Ringwald     result->tv_sec = stop->tv_sec - start->tv_sec;
11092b78dd7SMatthias Ringwald     if ((stop->tv_nsec - start->tv_nsec) < 0) {
11192b78dd7SMatthias Ringwald         result->tv_sec = stop->tv_sec - start->tv_sec - 1;
11292b78dd7SMatthias Ringwald         result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000;
11392b78dd7SMatthias Ringwald     } else {
11492b78dd7SMatthias Ringwald         result->tv_sec = stop->tv_sec - start->tv_sec;
11592b78dd7SMatthias Ringwald         result->tv_nsec = stop->tv_nsec - start->tv_nsec;
11692b78dd7SMatthias Ringwald     }
11792b78dd7SMatthias Ringwald }
11892b78dd7SMatthias Ringwald 
11992b78dd7SMatthias Ringwald /**
12092b78dd7SMatthias Ringwald  * @brief Convert timespec to miliseconds, might overflow
12192b78dd7SMatthias Ringwald  */
timespec_to_milliseconds(struct timespec * a)12292b78dd7SMatthias Ringwald static uint64_t timespec_to_milliseconds(struct timespec *a){
12392b78dd7SMatthias Ringwald     uint64_t ret = 0;
12492b78dd7SMatthias Ringwald     uint64_t sec_val = (uint64_t)(a->tv_sec);
12592b78dd7SMatthias Ringwald     uint64_t nsec_val = (uint64_t)(a->tv_nsec);
12692b78dd7SMatthias Ringwald     ret = (sec_val*1000) + (nsec_val/1000000);
12792b78dd7SMatthias Ringwald     return ret;
12892b78dd7SMatthias Ringwald }
12992b78dd7SMatthias Ringwald 
13092b78dd7SMatthias Ringwald /**
13192b78dd7SMatthias Ringwald  * @brief Returns the milisecond value of (stop - start). Might overflow
13292b78dd7SMatthias Ringwald  */
timespec_diff_milis(struct timespec * start,struct timespec * stop)13392b78dd7SMatthias Ringwald static uint64_t timespec_diff_milis(struct timespec* start, struct timespec* stop){
13492b78dd7SMatthias Ringwald     struct timespec diff_ts;
13592b78dd7SMatthias Ringwald     timespec_diff(start, stop, &diff_ts);
13692b78dd7SMatthias Ringwald     return timespec_to_milliseconds(&diff_ts);
13792b78dd7SMatthias Ringwald }
13892b78dd7SMatthias Ringwald #endif
13992b78dd7SMatthias Ringwald 
140b7d596c1SMatthias Ringwald /**
141f316a845SMatthias Ringwald  * @brief Queries the current time in ms since start
142f316a845SMatthias Ringwald  */
btstack_run_loop_posix_get_time_ms(void)143f316a845SMatthias Ringwald static uint32_t btstack_run_loop_posix_get_time_ms(void){
14492b78dd7SMatthias Ringwald     uint32_t time_ms;
14592b78dd7SMatthias Ringwald #ifdef _POSIX_MONOTONIC_CLOCK
14692b78dd7SMatthias Ringwald     struct timespec now_ts;
14792b78dd7SMatthias Ringwald     clock_gettime(CLOCK_MONOTONIC, &now_ts);
14892b78dd7SMatthias Ringwald     time_ms = (uint32_t) timespec_diff_milis(&init_ts, &now_ts);
14992b78dd7SMatthias Ringwald #else
150f316a845SMatthias Ringwald     struct timeval tv;
151f316a845SMatthias Ringwald     gettimeofday(&tv, NULL);
15292b78dd7SMatthias Ringwald     time_ms = (uint32_t) ((tv.tv_sec  - init_tv.tv_sec) * 1000) + (tv.tv_usec / 1000);
15392b78dd7SMatthias Ringwald #endif
154f316a845SMatthias Ringwald     return time_ms;
155f316a845SMatthias Ringwald }
156f316a845SMatthias Ringwald 
157f316a845SMatthias Ringwald /**
158b7d596c1SMatthias Ringwald  * Execute run_loop
159b7d596c1SMatthias Ringwald  */
btstack_run_loop_posix_execute(void)160528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_execute(void) {
1619120e843SMatthias Ringwald     fd_set descriptors_read;
1629120e843SMatthias Ringwald     fd_set descriptors_write;
163b7d596c1SMatthias Ringwald 
164b7d596c1SMatthias Ringwald     btstack_linked_list_iterator_t it;
165f316a845SMatthias Ringwald     struct timeval * timeout;
166f316a845SMatthias Ringwald     struct timeval tv;
167f316a845SMatthias Ringwald     uint32_t now_ms;
168b7d596c1SMatthias Ringwald 
16992b78dd7SMatthias Ringwald #ifdef _POSIX_MONOTONIC_CLOCK
17092b78dd7SMatthias Ringwald     log_info("POSIX run loop with monotonic clock");
17192b78dd7SMatthias Ringwald #else
17292b78dd7SMatthias Ringwald     log_info("POSIX run loop using ettimeofday fallback.");
17392b78dd7SMatthias Ringwald #endif
17492b78dd7SMatthias Ringwald 
175*dbeaa5cdSMatthias Ringwald     // clear exit flag
176*dbeaa5cdSMatthias Ringwald     btstack_run_loop_posix_exit_requested = false;
177*dbeaa5cdSMatthias Ringwald 
17890d4f186SMatthias Ringwald     while (btstack_run_loop_posix_exit_requested == false) {
179b7d596c1SMatthias Ringwald         // collect FDs
1809120e843SMatthias Ringwald         FD_ZERO(&descriptors_read);
1819120e843SMatthias Ringwald         FD_ZERO(&descriptors_write);
182f316a845SMatthias Ringwald         int highest_fd = -1;
183075edf12SMatthias Ringwald         btstack_linked_list_iterator_init(&it, &btstack_run_loop_base_data_sources);
184b7d596c1SMatthias Ringwald         while (btstack_linked_list_iterator_has_next(&it)){
185ec820d77SMatthias Ringwald             btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it);
186398a95ecSMatthias Ringwald             if (ds->source.fd < 0) continue;
1879120e843SMatthias Ringwald             if (ds->flags & DATA_SOURCE_CALLBACK_READ){
188398a95ecSMatthias Ringwald                 FD_SET(ds->source.fd, &descriptors_read);
189398a95ecSMatthias Ringwald                 if (ds->source.fd > highest_fd) {
190398a95ecSMatthias Ringwald                     highest_fd = ds->source.fd;
1919120e843SMatthias Ringwald                 }
192398a95ecSMatthias Ringwald                 log_debug("btstack_run_loop_execute adding fd %u for read", ds->source.fd);
1939120e843SMatthias Ringwald             }
1949120e843SMatthias Ringwald             if (ds->flags & DATA_SOURCE_CALLBACK_WRITE){
195398a95ecSMatthias Ringwald                 FD_SET(ds->source.fd, &descriptors_write);
196398a95ecSMatthias Ringwald                 if (ds->source.fd > highest_fd) {
197398a95ecSMatthias Ringwald                     highest_fd = ds->source.fd;
198b7d596c1SMatthias Ringwald                 }
199398a95ecSMatthias Ringwald                 log_debug("btstack_run_loop_execute adding fd %u for write", ds->source.fd);
200b7d596c1SMatthias Ringwald             }
201b7d596c1SMatthias Ringwald         }
202b7d596c1SMatthias Ringwald 
203b7d596c1SMatthias Ringwald         // get next timeout
204b7d596c1SMatthias Ringwald         timeout = NULL;
205f316a845SMatthias Ringwald         now_ms = btstack_run_loop_posix_get_time_ms();
206075edf12SMatthias Ringwald         int32_t delta_ms = btstack_run_loop_base_get_time_until_timeout(now_ms);
207075edf12SMatthias Ringwald         if (delta_ms >= 0) {
208075edf12SMatthias Ringwald             timeout = &tv;
209075edf12SMatthias Ringwald             tv.tv_sec  = delta_ms / 1000;
210075edf12SMatthias Ringwald             tv.tv_usec = (int) (delta_ms - (tv.tv_sec * 1000)) * 1000;
211075edf12SMatthias Ringwald             log_debug("btstack_run_loop_execute next timeout in %u ms", delta_ms);
212b7d596c1SMatthias Ringwald         }
213b7d596c1SMatthias Ringwald 
214b7d596c1SMatthias Ringwald         // wait for ready FDs
215c663093bSMatthias Ringwald         int res = select( highest_fd+1 , &descriptors_read, &descriptors_write, NULL, timeout);
216c663093bSMatthias Ringwald         if (res < 0){
217c663093bSMatthias Ringwald             log_error("btstack_run_loop_posix_execute: select -> errno %u", errno);
218c663093bSMatthias Ringwald         }
219c663093bSMatthias Ringwald         if (res > 0){
22090d4f186SMatthias Ringwald             btstack_run_loop_posix_data_sources_modified = 0;
221075edf12SMatthias Ringwald             btstack_linked_list_iterator_init(&it, &btstack_run_loop_base_data_sources);
22290d4f186SMatthias Ringwald             while (btstack_linked_list_iterator_has_next(&it) && !btstack_run_loop_posix_data_sources_modified){
223ec820d77SMatthias Ringwald                 btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it);
224398a95ecSMatthias Ringwald                 log_debug("btstack_run_loop_posix_execute: check ds %p with fd %u\n", ds, ds->source.fd);
225398a95ecSMatthias Ringwald                 if (FD_ISSET(ds->source.fd, &descriptors_read)) {
226398a95ecSMatthias Ringwald                     log_debug("btstack_run_loop_posix_execute: process read ds %p with fd %u\n", ds, ds->source.fd);
2277cd5ef95SMatthias Ringwald                     ds->process(ds, DATA_SOURCE_CALLBACK_READ);
228b7d596c1SMatthias Ringwald                 }
22990d4f186SMatthias Ringwald                 if (btstack_run_loop_posix_data_sources_modified) break;
230398a95ecSMatthias Ringwald                 if (FD_ISSET(ds->source.fd, &descriptors_write)) {
231398a95ecSMatthias Ringwald                     log_debug("btstack_run_loop_posix_execute: process write ds %p with fd %u\n", ds, ds->source.fd);
2329120e843SMatthias Ringwald                     ds->process(ds, DATA_SOURCE_CALLBACK_WRITE);
2339120e843SMatthias Ringwald                 }
234b7d596c1SMatthias Ringwald             }
235c663093bSMatthias Ringwald         }
236f316a845SMatthias Ringwald         log_debug("btstack_run_loop_posix_execute: after ds check\n");
237b7d596c1SMatthias Ringwald 
238b7d596c1SMatthias Ringwald         // process timers
23988e0b3b2SMatthias Ringwald         now_ms = btstack_run_loop_posix_get_time_ms();
240075edf12SMatthias Ringwald         btstack_run_loop_base_process_timers(now_ms);
241b7d596c1SMatthias Ringwald     }
242b7d596c1SMatthias Ringwald }
243b7d596c1SMatthias Ringwald 
btstack_run_loop_posix_trigger_exit(void)2442e357f7aSMatthias Ringwald static void btstack_run_loop_posix_trigger_exit(void){
24590d4f186SMatthias Ringwald     btstack_run_loop_posix_exit_requested = true;
2462e357f7aSMatthias Ringwald }
2472e357f7aSMatthias Ringwald 
248b7d596c1SMatthias Ringwald // set timer
btstack_run_loop_posix_set_timer(btstack_timer_source_t * a,uint32_t timeout_in_ms)249ec820d77SMatthias Ringwald static void btstack_run_loop_posix_set_timer(btstack_timer_source_t *a, uint32_t timeout_in_ms){
250f316a845SMatthias Ringwald     uint32_t time_ms = btstack_run_loop_posix_get_time_ms();
251f316a845SMatthias Ringwald     a->timeout = time_ms + timeout_in_ms;
252615ae444SMatthias Ringwald     log_debug("btstack_run_loop_posix_set_timer to %u ms (now %u, timeout %u)", a->timeout, time_ms, timeout_in_ms);
253b7d596c1SMatthias Ringwald }
254b7d596c1SMatthias Ringwald 
25590d4f186SMatthias Ringwald // trigger pipe
btstack_run_loop_posix_trigger_pipe(int fd)25690d4f186SMatthias Ringwald static void btstack_run_loop_posix_trigger_pipe(int fd){
25790d4f186SMatthias Ringwald     if (fd < 0) return;
25890d4f186SMatthias Ringwald     const uint8_t x = (uint8_t) 'x';
2599e6ecc42SMatthias Ringwald     ssize_t bytes_written = write(fd, &x, 1);
2609e6ecc42SMatthias Ringwald     UNUSED(bytes_written);
26190d4f186SMatthias Ringwald }
26290d4f186SMatthias Ringwald 
26390d4f186SMatthias Ringwald // poll data sources from irq
26490d4f186SMatthias Ringwald 
btstack_run_loop_posix_poll_data_sources_handler(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)26590d4f186SMatthias Ringwald static void btstack_run_loop_posix_poll_data_sources_handler(btstack_data_source_t * ds, btstack_data_source_callback_type_t callback_type){
26641158b74SMatthias Ringwald     UNUSED(callback_type);
26790d4f186SMatthias Ringwald     uint8_t buffer[1];
2689e6ecc42SMatthias Ringwald     ssize_t bytes_read = read(ds->source.fd, buffer, 1);
2699e6ecc42SMatthias Ringwald     UNUSED(bytes_read);
27090d4f186SMatthias Ringwald     // poll data sources
27190d4f186SMatthias Ringwald     btstack_run_loop_base_poll_data_sources();
27290d4f186SMatthias Ringwald }
27390d4f186SMatthias Ringwald 
btstack_run_loop_posix_poll_data_sources_from_irq(void)27490d4f186SMatthias Ringwald static void btstack_run_loop_posix_poll_data_sources_from_irq(void){
27590d4f186SMatthias Ringwald     // trigger run loop
27690d4f186SMatthias Ringwald     btstack_run_loop_posix_trigger_pipe(btstack_run_loop_posix_poll_data_sources_fd);
27790d4f186SMatthias Ringwald }
27890d4f186SMatthias Ringwald 
27990d4f186SMatthias Ringwald // execute on main thread from same or different thread
28090d4f186SMatthias Ringwald 
btstack_run_loop_posix_process_callbacks_handler(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)28190d4f186SMatthias Ringwald static void btstack_run_loop_posix_process_callbacks_handler(btstack_data_source_t * ds, btstack_data_source_callback_type_t callback_type){
28290d4f186SMatthias Ringwald     UNUSED(callback_type);
28341158b74SMatthias Ringwald     uint8_t buffer[1];
2849e6ecc42SMatthias Ringwald     ssize_t bytes_read = read(ds->source.fd, buffer, 1);
2859e6ecc42SMatthias Ringwald     UNUSED(bytes_read);
28641158b74SMatthias Ringwald     // execute callbacks - protect list with mutex
28741158b74SMatthias Ringwald     while (1){
28890d4f186SMatthias Ringwald         pthread_mutex_lock(&btstack_run_loop_posix_callbacks_mutex);
28941158b74SMatthias Ringwald         btstack_context_callback_registration_t * callback_registration = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&btstack_run_loop_base_callbacks);
29090d4f186SMatthias Ringwald         pthread_mutex_unlock(&btstack_run_loop_posix_callbacks_mutex);
29141158b74SMatthias Ringwald         if (callback_registration == NULL){
29241158b74SMatthias Ringwald             break;
29341158b74SMatthias Ringwald         }
29441158b74SMatthias Ringwald         (*callback_registration->callback)(callback_registration->context);
29541158b74SMatthias Ringwald     }
29641158b74SMatthias Ringwald }
29741158b74SMatthias Ringwald 
btstack_run_loop_posix_execute_on_main_thread(btstack_context_callback_registration_t * callback_registration)29841158b74SMatthias Ringwald static void btstack_run_loop_posix_execute_on_main_thread(btstack_context_callback_registration_t * callback_registration){
29941158b74SMatthias Ringwald     // protect list with mutex
30090d4f186SMatthias Ringwald     pthread_mutex_lock(&btstack_run_loop_posix_callbacks_mutex);
30141158b74SMatthias Ringwald     btstack_run_loop_base_add_callback(callback_registration);
30290d4f186SMatthias Ringwald     pthread_mutex_unlock(&btstack_run_loop_posix_callbacks_mutex);
30341158b74SMatthias Ringwald     // trigger run loop
30490d4f186SMatthias Ringwald     btstack_run_loop_posix_trigger_pipe(btstack_run_loop_posix_process_callbacks_fd);
30541158b74SMatthias Ringwald }
30690d4f186SMatthias Ringwald 
30790d4f186SMatthias Ringwald //init
30890d4f186SMatthias Ringwald 
30990d4f186SMatthias Ringwald // @return fd >= 0 on success
btstack_run_loop_posix_register_pipe_datasource(btstack_data_source_t * data_source)31090d4f186SMatthias Ringwald static int btstack_run_loop_posix_register_pipe_datasource(btstack_data_source_t * data_source){
31190d4f186SMatthias Ringwald     int fildes[2]; // 0 = read,  1 = write
31290d4f186SMatthias Ringwald     int status = pipe(fildes);
31390d4f186SMatthias Ringwald     if (status != 0){
31490d4f186SMatthias Ringwald         log_error("pipe() failed");
31590d4f186SMatthias Ringwald         return -1;
31690d4f186SMatthias Ringwald     }
31790d4f186SMatthias Ringwald     data_source->source.fd = fildes[0];
31890d4f186SMatthias Ringwald     data_source->flags = DATA_SOURCE_CALLBACK_READ;
31990d4f186SMatthias Ringwald     btstack_run_loop_base_add_data_source(data_source);
32090d4f186SMatthias Ringwald     log_info("Pipe: in %u, out %u", fildes[1], fildes[0]);
32190d4f186SMatthias Ringwald     return fildes[1];
32241158b74SMatthias Ringwald }
32341158b74SMatthias Ringwald 
btstack_run_loop_posix_init(void)324528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_init(void){
325075edf12SMatthias Ringwald     btstack_run_loop_base_init();
326075edf12SMatthias Ringwald 
32792b78dd7SMatthias Ringwald #ifdef _POSIX_MONOTONIC_CLOCK
32892b78dd7SMatthias Ringwald     clock_gettime(CLOCK_MONOTONIC, &init_ts);
32992b78dd7SMatthias Ringwald     init_ts.tv_nsec = 0;
33092b78dd7SMatthias Ringwald #else
331f316a845SMatthias Ringwald     // just assume that we started at tv_usec == 0
332b7d596c1SMatthias Ringwald     gettimeofday(&init_tv, NULL);
333f316a845SMatthias Ringwald     init_tv.tv_usec = 0;
33492b78dd7SMatthias Ringwald #endif
335b7d596c1SMatthias Ringwald 
33690d4f186SMatthias Ringwald     // setup pipe to trigger process callbacks
33790d4f186SMatthias Ringwald     btstack_run_loop_posix_process_callbacks_ds.process = &btstack_run_loop_posix_process_callbacks_handler;
33890d4f186SMatthias Ringwald     btstack_run_loop_posix_process_callbacks_fd = btstack_run_loop_posix_register_pipe_datasource(&btstack_run_loop_posix_process_callbacks_ds);
33990d4f186SMatthias Ringwald 
34090d4f186SMatthias Ringwald     // setup pipe to poll data sources
34190d4f186SMatthias Ringwald     btstack_run_loop_posix_poll_data_sources_ds.process = &btstack_run_loop_posix_poll_data_sources_handler;
34290d4f186SMatthias Ringwald     btstack_run_loop_posix_poll_data_sources_fd = btstack_run_loop_posix_register_pipe_datasource(&btstack_run_loop_posix_poll_data_sources_ds);
34341158b74SMatthias Ringwald }
344b7d596c1SMatthias Ringwald 
345528a4a3bSMatthias Ringwald static const btstack_run_loop_t btstack_run_loop_posix = {
346528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_init,
347528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_add_data_source,
348528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_remove_data_source,
349075edf12SMatthias Ringwald     &btstack_run_loop_base_enable_data_source_callbacks,
350075edf12SMatthias Ringwald     &btstack_run_loop_base_disable_data_source_callbacks,
351528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_set_timer,
352075edf12SMatthias Ringwald     &btstack_run_loop_base_add_timer,
353075edf12SMatthias Ringwald     &btstack_run_loop_base_remove_timer,
354528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_execute,
355075edf12SMatthias Ringwald     &btstack_run_loop_base_dump_timer,
356528a4a3bSMatthias Ringwald     &btstack_run_loop_posix_get_time_ms,
35790d4f186SMatthias Ringwald     &btstack_run_loop_posix_poll_data_sources_from_irq,
35890d4f186SMatthias Ringwald     &btstack_run_loop_posix_execute_on_main_thread,
3592e357f7aSMatthias Ringwald     &btstack_run_loop_posix_trigger_exit,
360b7d596c1SMatthias Ringwald };
361b7d596c1SMatthias Ringwald 
362b7d596c1SMatthias Ringwald /**
363528a4a3bSMatthias Ringwald  * Provide btstack_run_loop_posix instance
364b7d596c1SMatthias Ringwald  */
btstack_run_loop_posix_get_instance(void)365528a4a3bSMatthias Ringwald const btstack_run_loop_t * btstack_run_loop_posix_get_instance(void){
366528a4a3bSMatthias Ringwald     return &btstack_run_loop_posix;
367b7d596c1SMatthias Ringwald }
368b7d596c1SMatthias Ringwald 
369