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