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 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 468f2a52f4SMatthias Ringwald #include "btstack_run_loop_posix.h" 47*b6fc147fSMatthias Ringwald 48*b6fc147fSMatthias Ringwald #include "btstack_run_loop.h" 49*b6fc147fSMatthias Ringwald #include "btstack_util.h" 50b7d596c1SMatthias Ringwald #include "btstack_linked_list.h" 51b7d596c1SMatthias Ringwald #include "btstack_debug.h" 52b7d596c1SMatthias Ringwald 53b7d596c1SMatthias Ringwald #include <stdio.h> 54b7d596c1SMatthias Ringwald #include <stdlib.h> 55*b6fc147fSMatthias Ringwald #include <sys/select.h> 56f316a845SMatthias Ringwald #include <sys/time.h> 57b7d596c1SMatthias Ringwald 58528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_dump_timer(void); 59b7d596c1SMatthias Ringwald 60b7d596c1SMatthias Ringwald // the run loop 618f2a52f4SMatthias Ringwald static btstack_linked_list_t data_sources; 62b7d596c1SMatthias Ringwald static int data_sources_modified; 638f2a52f4SMatthias Ringwald static btstack_linked_list_t timers; 64f316a845SMatthias Ringwald // start time. tv_usec = 0 65b7d596c1SMatthias Ringwald static struct timeval init_tv; 66b7d596c1SMatthias Ringwald 67b7d596c1SMatthias Ringwald /** 68b7d596c1SMatthias Ringwald * Add data_source to run_loop 69b7d596c1SMatthias Ringwald */ 70ec820d77SMatthias Ringwald static void btstack_run_loop_posix_add_data_source(btstack_data_source_t *ds){ 71b7d596c1SMatthias Ringwald data_sources_modified = 1; 72398a95ecSMatthias Ringwald // log_info("btstack_run_loop_posix_add_data_source %x with fd %u\n", (int) ds, ds->source.fd); 73b7d596c1SMatthias Ringwald btstack_linked_list_add(&data_sources, (btstack_linked_item_t *) ds); 74b7d596c1SMatthias Ringwald } 75b7d596c1SMatthias Ringwald 76b7d596c1SMatthias Ringwald /** 77b7d596c1SMatthias Ringwald * Remove data_source from run loop 78b7d596c1SMatthias Ringwald */ 79ec820d77SMatthias Ringwald static int btstack_run_loop_posix_remove_data_source(btstack_data_source_t *ds){ 80b7d596c1SMatthias Ringwald data_sources_modified = 1; 81528a4a3bSMatthias Ringwald // log_info("btstack_run_loop_posix_remove_data_source %x\n", (int) ds); 82b7d596c1SMatthias Ringwald return btstack_linked_list_remove(&data_sources, (btstack_linked_item_t *) ds); 83b7d596c1SMatthias Ringwald } 84b7d596c1SMatthias Ringwald 85b7d596c1SMatthias Ringwald /** 86b7d596c1SMatthias Ringwald * Add timer to run_loop (keep list sorted) 87b7d596c1SMatthias Ringwald */ 88ec820d77SMatthias Ringwald static void btstack_run_loop_posix_add_timer(btstack_timer_source_t *ts){ 89b7d596c1SMatthias Ringwald btstack_linked_item_t *it; 90b7d596c1SMatthias Ringwald for (it = (btstack_linked_item_t *) &timers; it->next ; it = it->next){ 91f316a845SMatthias Ringwald btstack_timer_source_t * next = (btstack_timer_source_t *) it->next; 92f316a845SMatthias Ringwald if (next == ts){ 93528a4a3bSMatthias Ringwald log_error( "btstack_run_loop_timer_add error: timer to add already in list!"); 94b7d596c1SMatthias Ringwald return; 95b7d596c1SMatthias Ringwald } 96*b6fc147fSMatthias Ringwald // exit if new timeout before list timeout 97*b6fc147fSMatthias Ringwald int32_t delta = btstack_time_delta(ts->timeout, next->timeout); 98*b6fc147fSMatthias Ringwald if (delta < 0) break; 99b7d596c1SMatthias Ringwald } 100b7d596c1SMatthias Ringwald ts->item.next = it->next; 101b7d596c1SMatthias Ringwald it->next = (btstack_linked_item_t *) ts; 102f316a845SMatthias Ringwald log_debug("Added timer %p at %u\n", ts, ts->timeout); 103528a4a3bSMatthias Ringwald // btstack_run_loop_posix_dump_timer(); 104b7d596c1SMatthias Ringwald } 105b7d596c1SMatthias Ringwald 106b7d596c1SMatthias Ringwald /** 107b7d596c1SMatthias Ringwald * Remove timer from run loop 108b7d596c1SMatthias Ringwald */ 109ec820d77SMatthias Ringwald static int btstack_run_loop_posix_remove_timer(btstack_timer_source_t *ts){ 110b7d596c1SMatthias Ringwald // log_info("Removed timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec); 111528a4a3bSMatthias Ringwald // btstack_run_loop_posix_dump_timer(); 112b7d596c1SMatthias Ringwald return btstack_linked_list_remove(&timers, (btstack_linked_item_t *) ts); 113b7d596c1SMatthias Ringwald } 114b7d596c1SMatthias Ringwald 115528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_dump_timer(void){ 116b7d596c1SMatthias Ringwald btstack_linked_item_t *it; 117b7d596c1SMatthias Ringwald int i = 0; 118b7d596c1SMatthias Ringwald for (it = (btstack_linked_item_t *) timers; it ; it = it->next){ 119ec820d77SMatthias Ringwald btstack_timer_source_t *ts = (btstack_timer_source_t*) it; 120f316a845SMatthias Ringwald log_info("timer %u, timeout %u\n", i, ts->timeout); 121b7d596c1SMatthias Ringwald } 122b7d596c1SMatthias Ringwald } 123b7d596c1SMatthias Ringwald 1249120e843SMatthias Ringwald static void btstack_run_loop_posix_enable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 1259120e843SMatthias Ringwald ds->flags |= callback_types; 1269120e843SMatthias Ringwald } 1279120e843SMatthias Ringwald 1289120e843SMatthias Ringwald static void btstack_run_loop_posix_disable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 1299120e843SMatthias Ringwald ds->flags &= ~callback_types; 1309120e843SMatthias Ringwald } 1319120e843SMatthias Ringwald 132b7d596c1SMatthias Ringwald /** 133f316a845SMatthias Ringwald * @brief Queries the current time in ms since start 134f316a845SMatthias Ringwald */ 135f316a845SMatthias Ringwald static uint32_t btstack_run_loop_posix_get_time_ms(void){ 136f316a845SMatthias Ringwald struct timeval tv; 137f316a845SMatthias Ringwald gettimeofday(&tv, NULL); 1387c959318SMatthias Ringwald uint32_t time_ms = (uint32_t)((tv.tv_sec - init_tv.tv_sec) * 1000) + (tv.tv_usec / 1000); 139615ae444SMatthias Ringwald log_debug("btstack_run_loop_posix_get_time_ms: %u <- %u / %u", time_ms, (int) tv.tv_sec, (int) tv.tv_usec); 140f316a845SMatthias Ringwald return time_ms; 141f316a845SMatthias Ringwald } 142f316a845SMatthias Ringwald 143f316a845SMatthias Ringwald /** 144b7d596c1SMatthias Ringwald * Execute run_loop 145b7d596c1SMatthias Ringwald */ 146528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_execute(void) { 1479120e843SMatthias Ringwald fd_set descriptors_read; 1489120e843SMatthias Ringwald fd_set descriptors_write; 149b7d596c1SMatthias Ringwald 150ec820d77SMatthias Ringwald btstack_timer_source_t *ts; 151b7d596c1SMatthias Ringwald btstack_linked_list_iterator_t it; 152f316a845SMatthias Ringwald struct timeval * timeout; 153f316a845SMatthias Ringwald struct timeval tv; 154f316a845SMatthias Ringwald uint32_t now_ms; 155b7d596c1SMatthias Ringwald 156b7d596c1SMatthias Ringwald while (1) { 157b7d596c1SMatthias Ringwald // collect FDs 1589120e843SMatthias Ringwald FD_ZERO(&descriptors_read); 1599120e843SMatthias Ringwald FD_ZERO(&descriptors_write); 160f316a845SMatthias Ringwald int highest_fd = -1; 161b7d596c1SMatthias Ringwald btstack_linked_list_iterator_init(&it, &data_sources); 162b7d596c1SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 163ec820d77SMatthias Ringwald btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it); 164398a95ecSMatthias Ringwald if (ds->source.fd < 0) continue; 1659120e843SMatthias Ringwald if (ds->flags & DATA_SOURCE_CALLBACK_READ){ 166398a95ecSMatthias Ringwald FD_SET(ds->source.fd, &descriptors_read); 167398a95ecSMatthias Ringwald if (ds->source.fd > highest_fd) { 168398a95ecSMatthias Ringwald highest_fd = ds->source.fd; 1699120e843SMatthias Ringwald } 170398a95ecSMatthias Ringwald log_debug("btstack_run_loop_execute adding fd %u for read", ds->source.fd); 1719120e843SMatthias Ringwald } 1729120e843SMatthias Ringwald if (ds->flags & DATA_SOURCE_CALLBACK_WRITE){ 173398a95ecSMatthias Ringwald FD_SET(ds->source.fd, &descriptors_write); 174398a95ecSMatthias Ringwald if (ds->source.fd > highest_fd) { 175398a95ecSMatthias Ringwald highest_fd = ds->source.fd; 176b7d596c1SMatthias Ringwald } 177398a95ecSMatthias Ringwald log_debug("btstack_run_loop_execute adding fd %u for write", ds->source.fd); 178b7d596c1SMatthias Ringwald } 179b7d596c1SMatthias Ringwald } 180b7d596c1SMatthias Ringwald 181b7d596c1SMatthias Ringwald // get next timeout 182b7d596c1SMatthias Ringwald timeout = NULL; 183b7d596c1SMatthias Ringwald if (timers) { 184ec820d77SMatthias Ringwald ts = (btstack_timer_source_t *) timers; 185f316a845SMatthias Ringwald timeout = &tv; 186*b6fc147fSMatthias Ringwald uint32_t list_timeout = ts->timeout; 187f316a845SMatthias Ringwald now_ms = btstack_run_loop_posix_get_time_ms(); 188*b6fc147fSMatthias Ringwald int32_t delta = btstack_time_delta(list_timeout, now_ms); 189f316a845SMatthias Ringwald if (delta < 0){ 190f316a845SMatthias Ringwald delta = 0; 191b7d596c1SMatthias Ringwald } 192f316a845SMatthias Ringwald tv.tv_sec = delta / 1000; 1937c959318SMatthias Ringwald tv.tv_usec = (int) (delta - (tv.tv_sec * 1000)) * 1000; 194f316a845SMatthias Ringwald log_debug("btstack_run_loop_execute next timeout in %u ms", delta); 195b7d596c1SMatthias Ringwald } 196b7d596c1SMatthias Ringwald 197b7d596c1SMatthias Ringwald // wait for ready FDs 1989120e843SMatthias Ringwald select( highest_fd+1 , &descriptors_read, &descriptors_write, NULL, timeout); 199b7d596c1SMatthias Ringwald 20088e0b3b2SMatthias Ringwald 201b7d596c1SMatthias Ringwald data_sources_modified = 0; 202b7d596c1SMatthias Ringwald btstack_linked_list_iterator_init(&it, &data_sources); 203b7d596c1SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it) && !data_sources_modified){ 204ec820d77SMatthias Ringwald btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it); 205398a95ecSMatthias Ringwald log_debug("btstack_run_loop_posix_execute: check ds %p with fd %u\n", ds, ds->source.fd); 206398a95ecSMatthias Ringwald if (FD_ISSET(ds->source.fd, &descriptors_read)) { 207398a95ecSMatthias Ringwald log_debug("btstack_run_loop_posix_execute: process read ds %p with fd %u\n", ds, ds->source.fd); 2087cd5ef95SMatthias Ringwald ds->process(ds, DATA_SOURCE_CALLBACK_READ); 209b7d596c1SMatthias Ringwald } 2104b7565a2SMatthias Ringwald if (data_sources_modified) break; 211398a95ecSMatthias Ringwald if (FD_ISSET(ds->source.fd, &descriptors_write)) { 212398a95ecSMatthias Ringwald log_debug("btstack_run_loop_posix_execute: process write ds %p with fd %u\n", ds, ds->source.fd); 2139120e843SMatthias Ringwald ds->process(ds, DATA_SOURCE_CALLBACK_WRITE); 2149120e843SMatthias Ringwald } 215b7d596c1SMatthias Ringwald } 216f316a845SMatthias Ringwald log_debug("btstack_run_loop_posix_execute: after ds check\n"); 217b7d596c1SMatthias Ringwald 218b7d596c1SMatthias Ringwald // process timers 21988e0b3b2SMatthias Ringwald now_ms = btstack_run_loop_posix_get_time_ms(); 220b7d596c1SMatthias Ringwald while (timers) { 221ec820d77SMatthias Ringwald ts = (btstack_timer_source_t *) timers; 222*b6fc147fSMatthias Ringwald int32_t delta = btstack_time_delta(ts->timeout, now_ms); 223*b6fc147fSMatthias Ringwald if (delta > 0) 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 227b7832c7fSMatthias 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