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 38b7d596c1SMatthias Ringwald /* 394ab92137SMatthias Ringwald * btstack_run_loop.c 40b7d596c1SMatthias Ringwald * 41b7d596c1SMatthias Ringwald * Created by Matthias Ringwald on 6/6/09. 42b7d596c1SMatthias Ringwald */ 43b7d596c1SMatthias Ringwald 44b7d596c1SMatthias Ringwald #include "btstack_run_loop.h" 458f2a52f4SMatthias Ringwald #include "btstack_run_loop_posix.h" 46b7d596c1SMatthias Ringwald #include "btstack_linked_list.h" 47b7d596c1SMatthias Ringwald #include "btstack_debug.h" 48b7d596c1SMatthias Ringwald 49b7d596c1SMatthias Ringwald #ifdef _WIN32 50b7d596c1SMatthias Ringwald #include "Winsock2.h" 51b7d596c1SMatthias Ringwald #else 52b7d596c1SMatthias Ringwald #include <sys/select.h> 53b7d596c1SMatthias Ringwald #endif 54f316a845SMatthias Ringwald 55b7d596c1SMatthias Ringwald #include <stdio.h> 56b7d596c1SMatthias Ringwald #include <stdlib.h> 57f316a845SMatthias Ringwald #include <sys/time.h> 58b7d596c1SMatthias Ringwald 59528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_dump_timer(void); 60b7d596c1SMatthias Ringwald 61b7d596c1SMatthias Ringwald // the run loop 628f2a52f4SMatthias Ringwald static btstack_linked_list_t data_sources; 63b7d596c1SMatthias Ringwald static int data_sources_modified; 648f2a52f4SMatthias Ringwald static btstack_linked_list_t timers; 65f316a845SMatthias Ringwald // start time. tv_usec = 0 66b7d596c1SMatthias Ringwald static struct timeval init_tv; 67b7d596c1SMatthias Ringwald 68b7d596c1SMatthias Ringwald /** 69b7d596c1SMatthias Ringwald * Add data_source to run_loop 70b7d596c1SMatthias Ringwald */ 71ec820d77SMatthias Ringwald static void btstack_run_loop_posix_add_data_source(btstack_data_source_t *ds){ 72b7d596c1SMatthias Ringwald data_sources_modified = 1; 73528a4a3bSMatthias Ringwald // log_info("btstack_run_loop_posix_add_data_source %x with fd %u\n", (int) ds, ds->fd); 74b7d596c1SMatthias Ringwald btstack_linked_list_add(&data_sources, (btstack_linked_item_t *) ds); 75b7d596c1SMatthias Ringwald } 76b7d596c1SMatthias Ringwald 77b7d596c1SMatthias Ringwald /** 78b7d596c1SMatthias Ringwald * Remove data_source from run loop 79b7d596c1SMatthias Ringwald */ 80ec820d77SMatthias Ringwald static int btstack_run_loop_posix_remove_data_source(btstack_data_source_t *ds){ 81b7d596c1SMatthias Ringwald data_sources_modified = 1; 82528a4a3bSMatthias Ringwald // log_info("btstack_run_loop_posix_remove_data_source %x\n", (int) ds); 83b7d596c1SMatthias Ringwald return btstack_linked_list_remove(&data_sources, (btstack_linked_item_t *) ds); 84b7d596c1SMatthias Ringwald } 85b7d596c1SMatthias Ringwald 86b7d596c1SMatthias Ringwald /** 87b7d596c1SMatthias Ringwald * Add timer to run_loop (keep list sorted) 88b7d596c1SMatthias Ringwald */ 89ec820d77SMatthias Ringwald static void btstack_run_loop_posix_add_timer(btstack_timer_source_t *ts){ 90b7d596c1SMatthias Ringwald btstack_linked_item_t *it; 91b7d596c1SMatthias Ringwald for (it = (btstack_linked_item_t *) &timers; it->next ; it = it->next){ 92f316a845SMatthias Ringwald btstack_timer_source_t * next = (btstack_timer_source_t *) it->next; 93f316a845SMatthias Ringwald if (next == ts){ 94528a4a3bSMatthias Ringwald log_error( "btstack_run_loop_timer_add error: timer to add already in list!"); 95b7d596c1SMatthias Ringwald return; 96b7d596c1SMatthias Ringwald } 97f316a845SMatthias Ringwald if (next->timeout > ts->timeout) { 98b7d596c1SMatthias Ringwald break; 99b7d596c1SMatthias Ringwald } 100b7d596c1SMatthias Ringwald } 101b7d596c1SMatthias Ringwald ts->item.next = it->next; 102b7d596c1SMatthias Ringwald it->next = (btstack_linked_item_t *) ts; 103f316a845SMatthias Ringwald log_debug("Added timer %p at %u\n", ts, ts->timeout); 104528a4a3bSMatthias Ringwald // btstack_run_loop_posix_dump_timer(); 105b7d596c1SMatthias Ringwald } 106b7d596c1SMatthias Ringwald 107b7d596c1SMatthias Ringwald /** 108b7d596c1SMatthias Ringwald * Remove timer from run loop 109b7d596c1SMatthias Ringwald */ 110ec820d77SMatthias Ringwald static int btstack_run_loop_posix_remove_timer(btstack_timer_source_t *ts){ 111b7d596c1SMatthias Ringwald // log_info("Removed timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec); 112528a4a3bSMatthias Ringwald // btstack_run_loop_posix_dump_timer(); 113b7d596c1SMatthias Ringwald return btstack_linked_list_remove(&timers, (btstack_linked_item_t *) ts); 114b7d596c1SMatthias Ringwald } 115b7d596c1SMatthias Ringwald 116528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_dump_timer(void){ 117b7d596c1SMatthias Ringwald btstack_linked_item_t *it; 118b7d596c1SMatthias Ringwald int i = 0; 119b7d596c1SMatthias Ringwald for (it = (btstack_linked_item_t *) timers; it ; it = it->next){ 120ec820d77SMatthias Ringwald btstack_timer_source_t *ts = (btstack_timer_source_t*) it; 121f316a845SMatthias Ringwald log_info("timer %u, timeout %u\n", i, ts->timeout); 122b7d596c1SMatthias Ringwald } 123b7d596c1SMatthias Ringwald } 124b7d596c1SMatthias Ringwald 1259120e843SMatthias Ringwald static void btstack_run_loop_posix_enable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 1269120e843SMatthias Ringwald ds->flags |= callback_types; 1279120e843SMatthias Ringwald } 1289120e843SMatthias Ringwald 1299120e843SMatthias Ringwald static void btstack_run_loop_posix_disable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 1309120e843SMatthias Ringwald ds->flags &= ~callback_types; 1319120e843SMatthias Ringwald } 1329120e843SMatthias Ringwald 133b7d596c1SMatthias Ringwald /** 134f316a845SMatthias Ringwald * @brief Queries the current time in ms since start 135f316a845SMatthias Ringwald */ 136f316a845SMatthias Ringwald static uint32_t btstack_run_loop_posix_get_time_ms(void){ 137f316a845SMatthias Ringwald struct timeval tv; 138f316a845SMatthias Ringwald gettimeofday(&tv, NULL); 139f316a845SMatthias Ringwald uint32_t time_ms = ((tv.tv_sec - init_tv.tv_sec) * 1000) + (tv.tv_usec / 1000); 140f316a845SMatthias Ringwald log_info("btstack_run_loop_posix_get_time_ms: %u <- %u / %u", time_ms, (int) tv.tv_sec, (int) tv.tv_usec); 141f316a845SMatthias Ringwald return time_ms; 142f316a845SMatthias Ringwald } 143f316a845SMatthias Ringwald 144f316a845SMatthias Ringwald /** 145b7d596c1SMatthias Ringwald * Execute run_loop 146b7d596c1SMatthias Ringwald */ 147528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_execute(void) { 1489120e843SMatthias Ringwald fd_set descriptors_read; 1499120e843SMatthias Ringwald fd_set descriptors_write; 150b7d596c1SMatthias Ringwald 151ec820d77SMatthias Ringwald btstack_timer_source_t *ts; 152b7d596c1SMatthias Ringwald btstack_linked_list_iterator_t it; 153f316a845SMatthias Ringwald struct timeval * timeout; 154f316a845SMatthias Ringwald struct timeval tv; 155f316a845SMatthias Ringwald uint32_t now_ms; 156b7d596c1SMatthias Ringwald 157b7d596c1SMatthias Ringwald while (1) { 158b7d596c1SMatthias Ringwald // collect FDs 1599120e843SMatthias Ringwald FD_ZERO(&descriptors_read); 1609120e843SMatthias Ringwald FD_ZERO(&descriptors_write); 161f316a845SMatthias Ringwald int highest_fd = -1; 162b7d596c1SMatthias Ringwald btstack_linked_list_iterator_init(&it, &data_sources); 163b7d596c1SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 164ec820d77SMatthias Ringwald btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it); 1659120e843SMatthias Ringwald if (ds->fd < 0) continue; 1669120e843SMatthias Ringwald if (ds->flags & DATA_SOURCE_CALLBACK_READ){ 1679120e843SMatthias Ringwald FD_SET(ds->fd, &descriptors_read); 1689120e843SMatthias Ringwald if (ds->fd > highest_fd) { 1699120e843SMatthias Ringwald highest_fd = ds->fd; 1709120e843SMatthias Ringwald } 171f316a845SMatthias Ringwald log_debug("btstack_run_loop_execute adding fd %u for read", ds->fd); 1729120e843SMatthias Ringwald } 1739120e843SMatthias Ringwald if (ds->flags & DATA_SOURCE_CALLBACK_WRITE){ 1749120e843SMatthias Ringwald FD_SET(ds->fd, &descriptors_write); 175b7d596c1SMatthias Ringwald if (ds->fd > highest_fd) { 176b7d596c1SMatthias Ringwald highest_fd = ds->fd; 177b7d596c1SMatthias Ringwald } 178f316a845SMatthias Ringwald log_debug("btstack_run_loop_execute adding fd %u for write", ds->fd); 179b7d596c1SMatthias Ringwald } 180b7d596c1SMatthias Ringwald } 181b7d596c1SMatthias Ringwald 182b7d596c1SMatthias Ringwald // get next timeout 183b7d596c1SMatthias Ringwald timeout = NULL; 184b7d596c1SMatthias Ringwald if (timers) { 185ec820d77SMatthias Ringwald ts = (btstack_timer_source_t *) timers; 186f316a845SMatthias Ringwald timeout = &tv; 187f316a845SMatthias Ringwald now_ms = btstack_run_loop_posix_get_time_ms(); 188f316a845SMatthias Ringwald int delta = ts->timeout - now_ms; 189f316a845SMatthias Ringwald if (delta < 0){ 190f316a845SMatthias Ringwald delta = 0; 191b7d596c1SMatthias Ringwald } 192f316a845SMatthias Ringwald tv.tv_sec = delta / 1000; 193f316a845SMatthias Ringwald tv.tv_usec = (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 200b7d596c1SMatthias Ringwald data_sources_modified = 0; 201b7d596c1SMatthias Ringwald btstack_linked_list_iterator_init(&it, &data_sources); 202b7d596c1SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it) && !data_sources_modified){ 203ec820d77SMatthias Ringwald btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it); 204*d382f531SMatthias Ringwald log_debug("btstack_run_loop_posix_execute: check ds %p with fd %u\n", ds, ds->fd); 2059120e843SMatthias Ringwald if (FD_ISSET(ds->fd, &descriptors_read)) { 206*d382f531SMatthias Ringwald log_debug("btstack_run_loop_posix_execute: process read ds %p with fd %u\n", ds, ds->fd); 2077cd5ef95SMatthias Ringwald ds->process(ds, DATA_SOURCE_CALLBACK_READ); 208b7d596c1SMatthias Ringwald } 2099120e843SMatthias Ringwald if (FD_ISSET(ds->fd, &descriptors_write)) { 210*d382f531SMatthias Ringwald log_debug("btstack_run_loop_posix_execute: process write ds %p with fd %u\n", ds, ds->fd); 2119120e843SMatthias Ringwald ds->process(ds, DATA_SOURCE_CALLBACK_WRITE); 2129120e843SMatthias Ringwald } 213b7d596c1SMatthias Ringwald } 214f316a845SMatthias Ringwald log_debug("btstack_run_loop_posix_execute: after ds check\n"); 215b7d596c1SMatthias Ringwald 216b7d596c1SMatthias Ringwald // process timers 217b7d596c1SMatthias Ringwald // pre: 0 <= tv_usec < 1000000 218b7d596c1SMatthias Ringwald while (timers) { 219ec820d77SMatthias Ringwald ts = (btstack_timer_source_t *) timers; 220f316a845SMatthias Ringwald if (ts->timeout > now_ms) break; 221f316a845SMatthias Ringwald log_debug("btstack_run_loop_posix_execute: process timer %p\n", ts); 222b7d596c1SMatthias Ringwald 223b7d596c1SMatthias Ringwald // remove timer before processing it to allow handler to re-register with run loop 224528a4a3bSMatthias Ringwald btstack_run_loop_remove_timer(ts); 225b7d596c1SMatthias Ringwald ts->process(ts); 226b7d596c1SMatthias Ringwald } 227b7d596c1SMatthias Ringwald } 228b7d596c1SMatthias Ringwald } 229b7d596c1SMatthias Ringwald 230b7d596c1SMatthias Ringwald // set timer 231ec820d77SMatthias Ringwald static void btstack_run_loop_posix_set_timer(btstack_timer_source_t *a, uint32_t timeout_in_ms){ 232f316a845SMatthias Ringwald uint32_t time_ms = btstack_run_loop_posix_get_time_ms(); 233f316a845SMatthias Ringwald a->timeout = time_ms + timeout_in_ms; 234f316a845SMatthias Ringwald log_info("btstack_run_loop_posix_set_timer to %u ms (now %u, timeout %u)", a->timeout, time_ms, timeout_in_ms); 235b7d596c1SMatthias Ringwald } 236b7d596c1SMatthias Ringwald 237528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_init(void){ 238b7d596c1SMatthias Ringwald data_sources = NULL; 239b7d596c1SMatthias Ringwald timers = NULL; 240f316a845SMatthias Ringwald // just assume that we started at tv_usec == 0 241b7d596c1SMatthias Ringwald gettimeofday(&init_tv, NULL); 242f316a845SMatthias Ringwald init_tv.tv_usec = 0; 243f316a845SMatthias Ringwald log_debug("btstack_run_loop_posix_init at %u/%u", (int) init_tv.tv_sec, 0); 244b7d596c1SMatthias Ringwald } 245b7d596c1SMatthias Ringwald 246b7d596c1SMatthias Ringwald 247528a4a3bSMatthias Ringwald static const btstack_run_loop_t btstack_run_loop_posix = { 248528a4a3bSMatthias Ringwald &btstack_run_loop_posix_init, 249528a4a3bSMatthias Ringwald &btstack_run_loop_posix_add_data_source, 250528a4a3bSMatthias Ringwald &btstack_run_loop_posix_remove_data_source, 2519120e843SMatthias Ringwald &btstack_run_loop_posix_enable_data_source_callbacks, 2529120e843SMatthias Ringwald &btstack_run_loop_posix_disable_data_source_callbacks, 253528a4a3bSMatthias Ringwald &btstack_run_loop_posix_set_timer, 254528a4a3bSMatthias Ringwald &btstack_run_loop_posix_add_timer, 255528a4a3bSMatthias Ringwald &btstack_run_loop_posix_remove_timer, 256528a4a3bSMatthias Ringwald &btstack_run_loop_posix_execute, 257528a4a3bSMatthias Ringwald &btstack_run_loop_posix_dump_timer, 258528a4a3bSMatthias Ringwald &btstack_run_loop_posix_get_time_ms, 259b7d596c1SMatthias Ringwald }; 260b7d596c1SMatthias Ringwald 261b7d596c1SMatthias Ringwald /** 262528a4a3bSMatthias Ringwald * Provide btstack_run_loop_posix instance 263b7d596c1SMatthias Ringwald */ 264528a4a3bSMatthias Ringwald const btstack_run_loop_t * btstack_run_loop_posix_get_instance(void){ 265528a4a3bSMatthias Ringwald return &btstack_run_loop_posix; 266b7d596c1SMatthias Ringwald } 267b7d596c1SMatthias Ringwald 268