Szymon Janc <ext.szymon.janc@...>
Hi Luiz, On Monday 18 of April 2016 18:16:01 Luiz Augusto von Dentz wrote: From: Luiz Augusto von Dentz <luiz.von.dentz(a)intel.com>
This adds a timer fiber which can be used track timeouts removing the need to use one delayed fiber per timeout.
Change-Id: Id13347fbc69b1e83bca22094fbeb741e045ed516 Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz(a)intel.com> --- net/bluetooth/Kconfig | 9 +++ net/bluetooth/Makefile | 1 + net/bluetooth/timer.c | 211 +++++++++++++++++++++++++++++++++++++++++++++++++ net/bluetooth/timer.h | 48 +++++++++++ 4 files changed, 269 insertions(+) create mode 100644 net/bluetooth/timer.c create mode 100644 net/bluetooth/timer.h
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 2ffb0e0..2d703e3 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -20,6 +20,7 @@ menuconfig BLUETOOTH bool "Bluetooth support" default n select NANO_TIMEOUTS + select NANO_TIMERS select NET_BUF select BLUETOOTH_LE if !BLUETOOTH_STACK_NBLE help @@ -132,6 +133,14 @@ config BLUETOOTH_CONN default n
if BLUETOOTH_CONN +config BLUETOOTH_TIMER_STACK_SIZE + int "Size of the timer fiber stack" + default 512 + range 512 65536 + help + Size of the timer fiber stack. This is the context from + which all timer callbacks occur. I think it would be better to have kconfig option for callback needed stack and add overhead internally. This should be easier to estimate for user. + config BLUETOOTH_ACL_IN_COUNT int "Number of incoming ACL data buffers" default 5 diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 160ba34..18f9231 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_BLUETOOTH_STACK_HCI) = \
ifeq ($(CONFIG_BLUETOOTH_CONN),y) obj-y += conn.o \ + timer.o \ l2cap.o \ att.o \ gatt.o diff --git a/net/bluetooth/timer.c b/net/bluetooth/timer.c new file mode 100644 index 0000000..608ee4f --- /dev/null +++ b/net/bluetooth/timer.c @@ -0,0 +1,211 @@ +/** @file + * @brief Internal APIs for Bluetooth timer handling. + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <nanokernel.h> +#include <toolchain.h> +#include <sections.h> +#include <string.h> +#include <errno.h> +#include <misc/stack.h> + +#include <bluetooth/log.h> + +#include "timer.h" + +struct timer_queue { + struct bt_timer_queue tq; + + BT_STACK(stack, CONFIG_BLUETOOTH_TIMER_STACK_SIZE); +}; + +static struct timer_queue global_tq = { + .tq.stack_size = CONFIG_BLUETOOTH_TIMER_STACK_SIZE, +}; + +struct bt_timer_queue *__global_tq = &global_tq.tq; + +static void timer_expired(struct bt_timer *t) +{ + BT_DBG("t %p", t); + + /* Just to be safe stop the timer */ + nano_fiber_timer_stop(&t->__nano_timer); + + t->func(t->user_data); +} + +static int32_t timer_queue_ticks_remains(struct bt_timer_queue *tq) +{ + int32_t ticks; + + stack_analyze("timer queue stack", tq->stack, tq->stack_size); + + while (tq->__head) { + struct bt_timer *cur; + + /* If head is not expired sleep the remaining ticks */ + ticks = nano_timer_ticks_remain(&tq->__head->__nano_timer); + if (ticks > 0) + goto done; + + /* Remove head since it has expired */ + cur = tq->__head; + tq->__head = tq->__head->__next; + + /* Execute callback */ + timer_expired(cur); + } + + /* No timers left, abort fiber */ + ticks = 0; + +done: + BT_DBG("tq %p ticks %d", tq, ticks); + + return ticks; +} + +static void timer_queue_fiber(struct bt_timer_queue *tq) +{ + int32_t ticks; + + BT_DBG("tq %p thread_id %d started", tq, tq->__thread_id); + + while ((ticks = timer_queue_ticks_remains(tq))) { + fiber_sleep(ticks); + } + + BT_DBG("tq %p thread_id %d stopped", tq, tq->__thread_id); + + tq->__thread_id = 0; + fiber_abort(); +} + +static int timer_queue_start(struct bt_timer_queue *tq) +{ + if (tq->__thread_id) { + return 0; + } + + tq->__thread_id = fiber_start(tq->stack, tq->stack_size, + (nano_fiber_entry_t) timer_queue_fiber, + (int) tq, 0, 7, 0); + + return 0; +} + +int bt_timer_queue_init(struct bt_timer_queue *tq, size_t stack_size) +{ + if (!tq || !stack_size) { + return -EINVAL; + } + + tq->stack_size = stack_size; + + return 0; +} + +static inline void timer_queue_wakeup(struct bt_timer_queue *tq) +{ + if (sys_thread_self_get() != tq->__thread_id) + fiber_wakeup(tq->__thread_id); +} + +int bt_timer_queue_add(struct bt_timer_queue *tq, struct bt_timer *t, int ticks) +{ + struct bt_timer *cur, *prev; + + BT_DBG("tq %p t %p ticks %d", tq, t, ticks); + + if (!t || !t->func) + return -EINVAL; + + timer_queue_start(tq); + nano_timer_start(&t->__nano_timer, ticks); + + /* Sort the list of timers */ + for (cur = tq->__head, prev = NULL; cur; + prev = cur, cur = cur->__next) { + if (ticks < nano_timer_ticks_remain(&cur->__nano_timer)) { + break; + } + } + + t->__next = cur; + + if (prev) { + prev->__next = t; + } else { + tq->__head = t; + /* Wakeup timer queue fiber since there is a new head */ + timer_queue_wakeup(tq); + } + + return 0; +} + +int bt_timer_queue_cancel(struct bt_timer_queue *tq, struct bt_timer *t) +{ + struct bt_timer *cur, *prev; + + BT_DBG("tq %p t %p", tq, t); + + if (!t) { + return -EINVAL; + } + + /* Lookup existing timers */ + for (cur = tq->__head, prev = NULL; cur; + prev = cur, cur = cur->__next) { + if (cur == t) { + break; + } + } + + if (!cur) { + return -ENOENT; + } + + nano_timer_stop(&t->__nano_timer); + + /* Remove timer for the queue */ + if (prev) { + prev->__next = t->__next; + } else { + tq->__head = t->__next; + /* Wakeup timer queue fiber since there is a new head */ + timer_queue_wakeup(tq); + } + + return 0; +} + +int bt_timer_init(struct bt_timer *t, bt_timer_func func, void *user_data) +{ + if (!t || !func) { + return -EINVAL; + } + + t->func = func; + t->user_data = user_data; + nano_timer_init(&t->__nano_timer, t); + + return 0; +} diff --git a/net/bluetooth/timer.h b/net/bluetooth/timer.h new file mode 100644 index 0000000..82bee8f --- /dev/null +++ b/net/bluetooth/timer.h @@ -0,0 +1,48 @@ +/** @file + * @brief Internal APIs for Bluetooth timer handling. + */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern struct bt_timer_queue *__global_tq; + +struct bt_timer_queue { + nano_thread_id_t __thread_id; + struct bt_timer *__head; + size_t stack_size; + char stack[0]; +}; + +typedef void (*bt_timer_func)(void *user_data); + +struct bt_timer { + struct nano_timer __nano_timer; + bt_timer_func func; + void *user_data; + struct bt_timer *__next; +}; + +int bt_timer_queue_init(struct bt_timer_queue *tq, size_t stack_size); + +int bt_timer_queue_add(struct bt_timer_queue *tq, struct bt_timer *t, + int ticks); +int bt_timer_queue_cancel(struct bt_timer_queue *tq, struct bt_timer *t); + +int bt_timer_init(struct bt_timer *t, bt_timer_func func, void *user_data); + +#define bt_timer_add(_t, _ticks) bt_timer_queue_add(__global_tq, _t, _ticks) +#define bt_timer_cancel(_t) bt_timer_queue_cancel(__global_tq, _t) -- BR Szymon Janc
|