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 54b7d596c1SMatthias Ringwald #include <stdio.h> 55b7d596c1SMatthias Ringwald #include <stdlib.h> 56b7d596c1SMatthias Ringwald 57528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_dump_timer(void); 58528a4a3bSMatthias Ringwald static int btstack_run_loop_posix_timeval_compare(struct timeval *a, struct timeval *b); 59ec820d77SMatthias Ringwald static int btstack_run_loop_posix_timer_compare(btstack_timer_source_t *a, btstack_timer_source_t *b); 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; 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; 72528a4a3bSMatthias Ringwald // log_info("btstack_run_loop_posix_add_data_source %x with fd %u\n", (int) ds, ds->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){ 91ec820d77SMatthias Ringwald if ((btstack_timer_source_t *) it->next == ts){ 92528a4a3bSMatthias Ringwald log_error( "btstack_run_loop_timer_add error: timer to add already in list!"); 93b7d596c1SMatthias Ringwald return; 94b7d596c1SMatthias Ringwald } 95ec820d77SMatthias Ringwald if (btstack_run_loop_posix_timer_compare( (btstack_timer_source_t *) it->next, ts) > 0) { 96b7d596c1SMatthias Ringwald break; 97b7d596c1SMatthias Ringwald } 98b7d596c1SMatthias Ringwald } 99b7d596c1SMatthias Ringwald ts->item.next = it->next; 100b7d596c1SMatthias Ringwald it->next = (btstack_linked_item_t *) ts; 101b7d596c1SMatthias Ringwald // log_info("Added timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec); 102528a4a3bSMatthias Ringwald // btstack_run_loop_posix_dump_timer(); 103b7d596c1SMatthias Ringwald } 104b7d596c1SMatthias Ringwald 105b7d596c1SMatthias Ringwald /** 106b7d596c1SMatthias Ringwald * Remove timer from run loop 107b7d596c1SMatthias Ringwald */ 108ec820d77SMatthias Ringwald static int btstack_run_loop_posix_remove_timer(btstack_timer_source_t *ts){ 109b7d596c1SMatthias Ringwald // log_info("Removed timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec); 110528a4a3bSMatthias Ringwald // btstack_run_loop_posix_dump_timer(); 111b7d596c1SMatthias Ringwald return btstack_linked_list_remove(&timers, (btstack_linked_item_t *) ts); 112b7d596c1SMatthias Ringwald } 113b7d596c1SMatthias Ringwald 114528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_dump_timer(void){ 115b7d596c1SMatthias Ringwald btstack_linked_item_t *it; 116b7d596c1SMatthias Ringwald int i = 0; 117b7d596c1SMatthias Ringwald for (it = (btstack_linked_item_t *) timers; it ; it = it->next){ 118ec820d77SMatthias Ringwald btstack_timer_source_t *ts = (btstack_timer_source_t*) it; 119b7d596c1SMatthias Ringwald log_info("timer %u, timeout %u\n", i, (unsigned int) ts->timeout.tv_sec); 120b7d596c1SMatthias Ringwald } 121b7d596c1SMatthias Ringwald } 122b7d596c1SMatthias Ringwald 123*9120e843SMatthias Ringwald static void btstack_run_loop_posix_enable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 124*9120e843SMatthias Ringwald ds->flags |= callback_types; 125*9120e843SMatthias Ringwald } 126*9120e843SMatthias Ringwald 127*9120e843SMatthias Ringwald static void btstack_run_loop_posix_disable_data_source_callbacks(btstack_data_source_t * ds, uint16_t callback_types){ 128*9120e843SMatthias Ringwald ds->flags &= ~callback_types; 129*9120e843SMatthias Ringwald } 130*9120e843SMatthias Ringwald 131b7d596c1SMatthias Ringwald /** 132b7d596c1SMatthias Ringwald * Execute run_loop 133b7d596c1SMatthias Ringwald */ 134528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_execute(void) { 135*9120e843SMatthias Ringwald fd_set descriptors_read; 136*9120e843SMatthias Ringwald fd_set descriptors_write; 137b7d596c1SMatthias Ringwald 138ec820d77SMatthias Ringwald btstack_timer_source_t *ts; 139b7d596c1SMatthias Ringwald struct timeval current_tv; 140b7d596c1SMatthias Ringwald struct timeval next_tv; 141b7d596c1SMatthias Ringwald struct timeval *timeout; 142b7d596c1SMatthias Ringwald btstack_linked_list_iterator_t it; 143b7d596c1SMatthias Ringwald 144b7d596c1SMatthias Ringwald while (1) { 145b7d596c1SMatthias Ringwald // collect FDs 146*9120e843SMatthias Ringwald FD_ZERO(&descriptors_read); 147*9120e843SMatthias Ringwald FD_ZERO(&descriptors_write); 148b7d596c1SMatthias Ringwald int highest_fd = 0; 149b7d596c1SMatthias Ringwald btstack_linked_list_iterator_init(&it, &data_sources); 150b7d596c1SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 151ec820d77SMatthias Ringwald btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it); 152*9120e843SMatthias Ringwald if (ds->fd < 0) continue; 153*9120e843SMatthias Ringwald if (ds->flags & DATA_SOURCE_CALLBACK_READ){ 154*9120e843SMatthias Ringwald FD_SET(ds->fd, &descriptors_read); 155*9120e843SMatthias Ringwald if (ds->fd > highest_fd) { 156*9120e843SMatthias Ringwald highest_fd = ds->fd; 157*9120e843SMatthias Ringwald } 158*9120e843SMatthias Ringwald } 159*9120e843SMatthias Ringwald if (ds->flags & DATA_SOURCE_CALLBACK_WRITE){ 160*9120e843SMatthias Ringwald FD_SET(ds->fd, &descriptors_write); 161b7d596c1SMatthias Ringwald if (ds->fd > highest_fd) { 162b7d596c1SMatthias Ringwald highest_fd = ds->fd; 163b7d596c1SMatthias Ringwald } 164b7d596c1SMatthias Ringwald } 165b7d596c1SMatthias Ringwald } 166b7d596c1SMatthias Ringwald 167b7d596c1SMatthias Ringwald // get next timeout 168b7d596c1SMatthias Ringwald // pre: 0 <= tv_usec < 1000000 169b7d596c1SMatthias Ringwald timeout = NULL; 170b7d596c1SMatthias Ringwald if (timers) { 171b7d596c1SMatthias Ringwald gettimeofday(¤t_tv, NULL); 172ec820d77SMatthias Ringwald ts = (btstack_timer_source_t *) timers; 173b7d596c1SMatthias Ringwald next_tv.tv_usec = ts->timeout.tv_usec - current_tv.tv_usec; 174b7d596c1SMatthias Ringwald next_tv.tv_sec = ts->timeout.tv_sec - current_tv.tv_sec; 175b7d596c1SMatthias Ringwald while (next_tv.tv_usec < 0){ 176b7d596c1SMatthias Ringwald next_tv.tv_usec += 1000000; 177b7d596c1SMatthias Ringwald next_tv.tv_sec--; 178b7d596c1SMatthias Ringwald } 179b7d596c1SMatthias Ringwald if (next_tv.tv_sec < 0){ 180b7d596c1SMatthias Ringwald next_tv.tv_sec = 0; 181b7d596c1SMatthias Ringwald next_tv.tv_usec = 0; 182b7d596c1SMatthias Ringwald } 183b7d596c1SMatthias Ringwald timeout = &next_tv; 184b7d596c1SMatthias Ringwald } 185b7d596c1SMatthias Ringwald 186b7d596c1SMatthias Ringwald // wait for ready FDs 187*9120e843SMatthias Ringwald select( highest_fd+1 , &descriptors_read, &descriptors_write, NULL, timeout); 188b7d596c1SMatthias Ringwald 189b7d596c1SMatthias Ringwald // process data sources very carefully 190b7d596c1SMatthias Ringwald // bt_control.close() triggered from a client can remove a different data source 191b7d596c1SMatthias Ringwald 192528a4a3bSMatthias Ringwald // log_info("btstack_run_loop_posix_execute: before ds check\n"); 193b7d596c1SMatthias Ringwald data_sources_modified = 0; 194b7d596c1SMatthias Ringwald btstack_linked_list_iterator_init(&it, &data_sources); 195b7d596c1SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it) && !data_sources_modified){ 196ec820d77SMatthias Ringwald btstack_data_source_t *ds = (btstack_data_source_t*) btstack_linked_list_iterator_next(&it); 197528a4a3bSMatthias Ringwald // log_info("btstack_run_loop_posix_execute: check %x with fd %u\n", (int) ds, ds->fd); 198*9120e843SMatthias Ringwald if (FD_ISSET(ds->fd, &descriptors_read)) { 199*9120e843SMatthias Ringwald // log_info("btstack_run_loop_posix_execute: process read %x with fd %u\n", (int) ds, ds->fd); 2007cd5ef95SMatthias Ringwald ds->process(ds, DATA_SOURCE_CALLBACK_READ); 201b7d596c1SMatthias Ringwald } 202*9120e843SMatthias Ringwald if (FD_ISSET(ds->fd, &descriptors_write)) { 203*9120e843SMatthias Ringwald // log_info("btstack_run_loop_posix_execute: process write %x with fd %u\n", (int) ds, ds->fd); 204*9120e843SMatthias Ringwald ds->process(ds, DATA_SOURCE_CALLBACK_WRITE); 205*9120e843SMatthias Ringwald } 206b7d596c1SMatthias Ringwald } 207528a4a3bSMatthias Ringwald // log_info("btstack_run_loop_posix_execute: after ds check\n"); 208b7d596c1SMatthias Ringwald 209b7d596c1SMatthias Ringwald // process timers 210b7d596c1SMatthias Ringwald // pre: 0 <= tv_usec < 1000000 211b7d596c1SMatthias Ringwald while (timers) { 212b7d596c1SMatthias Ringwald gettimeofday(¤t_tv, NULL); 213ec820d77SMatthias Ringwald ts = (btstack_timer_source_t *) timers; 214b7d596c1SMatthias Ringwald if (ts->timeout.tv_sec > current_tv.tv_sec) break; 215b7d596c1SMatthias Ringwald if (ts->timeout.tv_sec == current_tv.tv_sec && ts->timeout.tv_usec > current_tv.tv_usec) break; 216528a4a3bSMatthias Ringwald // log_info("btstack_run_loop_posix_execute: process times %x\n", (int) ts); 217b7d596c1SMatthias Ringwald 218b7d596c1SMatthias Ringwald // remove timer before processing it to allow handler to re-register with run loop 219528a4a3bSMatthias Ringwald btstack_run_loop_remove_timer(ts); 220b7d596c1SMatthias Ringwald ts->process(ts); 221b7d596c1SMatthias Ringwald } 222b7d596c1SMatthias Ringwald } 223b7d596c1SMatthias Ringwald } 224b7d596c1SMatthias Ringwald 225b7d596c1SMatthias Ringwald // set timer 226ec820d77SMatthias Ringwald static void btstack_run_loop_posix_set_timer(btstack_timer_source_t *a, uint32_t timeout_in_ms){ 227b7d596c1SMatthias Ringwald gettimeofday(&a->timeout, NULL); 228b7d596c1SMatthias Ringwald a->timeout.tv_sec += timeout_in_ms / 1000; 229b7d596c1SMatthias Ringwald a->timeout.tv_usec += (timeout_in_ms % 1000) * 1000; 230b7d596c1SMatthias Ringwald if (a->timeout.tv_usec > 1000000) { 231b7d596c1SMatthias Ringwald a->timeout.tv_usec -= 1000000; 232b7d596c1SMatthias Ringwald a->timeout.tv_sec++; 233b7d596c1SMatthias Ringwald } 234b7d596c1SMatthias Ringwald } 235b7d596c1SMatthias Ringwald 236b7d596c1SMatthias Ringwald // compare timers - NULL is assumed to be before the Big Bang 237b7d596c1SMatthias Ringwald // pre: 0 <= tv_usec < 1000000 238528a4a3bSMatthias Ringwald static int btstack_run_loop_posix_timeval_compare(struct timeval *a, struct timeval *b){ 239b7d596c1SMatthias Ringwald if (!a && !b) return 0; 240b7d596c1SMatthias Ringwald if (!a) return -1; 241b7d596c1SMatthias Ringwald if (!b) return 1; 242b7d596c1SMatthias Ringwald 243b7d596c1SMatthias Ringwald if (a->tv_sec < b->tv_sec) { 244b7d596c1SMatthias Ringwald return -1; 245b7d596c1SMatthias Ringwald } 246b7d596c1SMatthias Ringwald if (a->tv_sec > b->tv_sec) { 247b7d596c1SMatthias Ringwald return 1; 248b7d596c1SMatthias Ringwald } 249b7d596c1SMatthias Ringwald 250b7d596c1SMatthias Ringwald if (a->tv_usec < b->tv_usec) { 251b7d596c1SMatthias Ringwald return -1; 252b7d596c1SMatthias Ringwald } 253b7d596c1SMatthias Ringwald if (a->tv_usec > b->tv_usec) { 254b7d596c1SMatthias Ringwald return 1; 255b7d596c1SMatthias Ringwald } 256b7d596c1SMatthias Ringwald 257b7d596c1SMatthias Ringwald return 0; 258b7d596c1SMatthias Ringwald 259b7d596c1SMatthias Ringwald } 260b7d596c1SMatthias Ringwald 261b7d596c1SMatthias Ringwald // compare timers - NULL is assumed to be before the Big Bang 262b7d596c1SMatthias Ringwald // pre: 0 <= tv_usec < 1000000 263ec820d77SMatthias Ringwald static int btstack_run_loop_posix_timer_compare(btstack_timer_source_t *a, btstack_timer_source_t *b){ 264b7d596c1SMatthias Ringwald if (!a && !b) return 0; 265b7d596c1SMatthias Ringwald if (!a) return -1; 266b7d596c1SMatthias Ringwald if (!b) return 1; 267528a4a3bSMatthias Ringwald return btstack_run_loop_posix_timeval_compare(&a->timeout, &b->timeout); 268b7d596c1SMatthias Ringwald } 269b7d596c1SMatthias Ringwald 270528a4a3bSMatthias Ringwald static void btstack_run_loop_posix_init(void){ 271b7d596c1SMatthias Ringwald data_sources = NULL; 272b7d596c1SMatthias Ringwald timers = NULL; 273b7d596c1SMatthias Ringwald gettimeofday(&init_tv, NULL); 274b7d596c1SMatthias Ringwald } 275b7d596c1SMatthias Ringwald 276b7d596c1SMatthias Ringwald /** 277b7d596c1SMatthias Ringwald * @brief Queries the current time in ms since start 278b7d596c1SMatthias Ringwald */ 279528a4a3bSMatthias Ringwald static uint32_t btstack_run_loop_posix_get_time_ms(void){ 280b7d596c1SMatthias Ringwald struct timeval current_tv; 281b7d596c1SMatthias Ringwald gettimeofday(¤t_tv, NULL); 282b7d596c1SMatthias Ringwald return (current_tv.tv_sec - init_tv.tv_sec) * 1000 283b7d596c1SMatthias Ringwald + (current_tv.tv_usec - init_tv.tv_usec) / 1000; 284b7d596c1SMatthias Ringwald } 285b7d596c1SMatthias Ringwald 286b7d596c1SMatthias Ringwald 287528a4a3bSMatthias Ringwald static const btstack_run_loop_t btstack_run_loop_posix = { 288528a4a3bSMatthias Ringwald &btstack_run_loop_posix_init, 289528a4a3bSMatthias Ringwald &btstack_run_loop_posix_add_data_source, 290528a4a3bSMatthias Ringwald &btstack_run_loop_posix_remove_data_source, 291*9120e843SMatthias Ringwald &btstack_run_loop_posix_enable_data_source_callbacks, 292*9120e843SMatthias Ringwald &btstack_run_loop_posix_disable_data_source_callbacks, 293528a4a3bSMatthias Ringwald &btstack_run_loop_posix_set_timer, 294528a4a3bSMatthias Ringwald &btstack_run_loop_posix_add_timer, 295528a4a3bSMatthias Ringwald &btstack_run_loop_posix_remove_timer, 296528a4a3bSMatthias Ringwald &btstack_run_loop_posix_execute, 297528a4a3bSMatthias Ringwald &btstack_run_loop_posix_dump_timer, 298528a4a3bSMatthias Ringwald &btstack_run_loop_posix_get_time_ms, 299b7d596c1SMatthias Ringwald }; 300b7d596c1SMatthias Ringwald 301b7d596c1SMatthias Ringwald /** 302528a4a3bSMatthias Ringwald * Provide btstack_run_loop_posix instance 303b7d596c1SMatthias Ringwald */ 304528a4a3bSMatthias Ringwald const btstack_run_loop_t * btstack_run_loop_posix_get_instance(void){ 305528a4a3bSMatthias Ringwald return &btstack_run_loop_posix; 306b7d596c1SMatthias Ringwald } 307b7d596c1SMatthias Ringwald 308