From fb01677372a9eaad090abd47d3b867bda19baac3 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Wed, 20 Jul 2022 11:18:33 +0800 Subject: [PATCH] component/bt: add new OSI utility "fixed_pkt_queue", which has same functionality with "fixed_queue" --- components/bt/CMakeLists.txt | 1 + components/bt/common/osi/fixed_pkt_queue.c | 161 ++++++++++++++++++ .../common/osi/include/osi/fixed_pkt_queue.h | 79 +++++++++ 3 files changed, 241 insertions(+) create mode 100644 components/bt/common/osi/fixed_pkt_queue.c create mode 100644 components/bt/common/osi/include/osi/fixed_pkt_queue.h diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 6f23052610..9bb004a36d 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -37,6 +37,7 @@ if(CONFIG_BT_ENABLED) "common/osi/config.c" "common/osi/fixed_queue.c" "common/osi/pkt_queue.c" + "common/osi/fixed_pkt_queue.c" "common/osi/future.c" "common/osi/hash_functions.c" "common/osi/hash_map.c" diff --git a/components/bt/common/osi/fixed_pkt_queue.c b/components/bt/common/osi/fixed_pkt_queue.c new file mode 100644 index 0000000000..e98d454859 --- /dev/null +++ b/components/bt/common/osi/fixed_pkt_queue.c @@ -0,0 +1,161 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "osi/allocator.h" +#include "osi/pkt_queue.h" +#include "osi/fixed_pkt_queue.h" +#include "osi/osi.h" +#include "osi/semaphore.h" + +typedef struct fixed_pkt_queue_t { + struct pkt_queue *pkt_list; + osi_sem_t enqueue_sem; + osi_sem_t dequeue_sem; + size_t capacity; + fixed_pkt_queue_cb dequeue_ready; +} fixed_pkt_queue_t; + +fixed_pkt_queue_t *fixed_pkt_queue_new(size_t capacity) +{ + fixed_pkt_queue_t *ret = osi_calloc(sizeof(fixed_pkt_queue_t)); + if (!ret) { + goto error; + } + + ret->capacity = capacity; + ret->pkt_list = pkt_queue_create(); + if (!ret->pkt_list) { + goto error; + } + + osi_sem_new(&ret->enqueue_sem, capacity, capacity); + if (!ret->enqueue_sem) { + goto error; + } + + osi_sem_new(&ret->dequeue_sem, capacity, 0); + if (!ret->dequeue_sem) { + goto error; + } + + return ret; + +error: + fixed_pkt_queue_free(ret, NULL); + return NULL; +} + +void fixed_pkt_queue_free(fixed_pkt_queue_t *queue, fixed_pkt_queue_free_cb free_cb) +{ + if (queue == NULL) { + return; + } + + fixed_pkt_queue_unregister_dequeue(queue); + + pkt_queue_destroy(queue->pkt_list, (pkt_queue_free_cb)free_cb); + queue->pkt_list = NULL; + + if (queue->enqueue_sem) { + osi_sem_free(&queue->enqueue_sem); + } + if (queue->dequeue_sem) { + osi_sem_free(&queue->dequeue_sem); + } + osi_free(queue); +} + +bool fixed_pkt_queue_is_empty(fixed_pkt_queue_t *queue) +{ + if (queue == NULL) { + return true; + } + + return pkt_queue_is_empty(queue->pkt_list); +} + +size_t fixed_pkt_queue_length(fixed_pkt_queue_t *queue) +{ + if (queue == NULL) { + return 0; + } + return pkt_queue_length(queue->pkt_list); +} + +size_t fixed_pkt_queue_capacity(fixed_pkt_queue_t *queue) +{ + assert(queue != NULL); + + return queue->capacity; +} + +bool fixed_pkt_queue_enqueue(fixed_pkt_queue_t *queue, pkt_linked_item_t *linked_pkt, uint32_t timeout) +{ + bool ret = false; + + assert(queue != NULL); + assert(linked_pkt != NULL); + + if (osi_sem_take(&queue->enqueue_sem, timeout) != 0) { + return false; + } + + ret = pkt_queue_enqueue(queue->pkt_list, linked_pkt); + + assert(ret == true); + osi_sem_give(&queue->dequeue_sem); + + return ret; +} + +pkt_linked_item_t *fixed_pkt_queue_dequeue(fixed_pkt_queue_t *queue, uint32_t timeout) +{ + pkt_linked_item_t *ret = NULL; + + assert(queue != NULL); + + if (osi_sem_take(&queue->dequeue_sem, timeout) != 0) { + return NULL; + } + ret = pkt_queue_dequeue(queue->pkt_list); + + osi_sem_give(&queue->enqueue_sem); + + return ret; +} + +pkt_linked_item_t *fixed_pkt_queue_try_peek_first(fixed_pkt_queue_t *queue) +{ + if (queue == NULL) { + return NULL; + } + + return pkt_queue_try_peek_first(queue->pkt_list); +} + +void fixed_pkt_queue_register_dequeue(fixed_pkt_queue_t *queue, fixed_pkt_queue_cb ready_cb) +{ + assert(queue != NULL); + assert(ready_cb != NULL); + + queue->dequeue_ready = ready_cb; +} + +void fixed_pkt_queue_unregister_dequeue(fixed_pkt_queue_t *queue) +{ + assert(queue != NULL); + + queue->dequeue_ready = NULL; +} + +void fixed_pkt_queue_process(fixed_pkt_queue_t *queue) +{ + assert(queue != NULL); + + if (queue->dequeue_ready) { + queue->dequeue_ready(queue); + } +} diff --git a/components/bt/common/osi/include/osi/fixed_pkt_queue.h b/components/bt/common/osi/include/osi/fixed_pkt_queue.h new file mode 100644 index 0000000000..f4235ca5d9 --- /dev/null +++ b/components/bt/common/osi/include/osi/fixed_pkt_queue.h @@ -0,0 +1,79 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _FIXED_PKT_QUEUE_H_ +#define _FIXED_PKT_QUEUE_H_ + + +#include "osi/pkt_queue.h" +#include "osi/semaphore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef FIXED_PKT_QUEUE_SIZE_MAX +#define FIXED_PKT_QUEUE_SIZE_MAX 254 +#endif + +#define FIXED_PKT_QUEUE_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT + +struct fixed_pkt_queue_t; + +typedef struct fixed_pkt_queue_t fixed_pkt_queue_t; + +typedef void (*fixed_pkt_queue_free_cb)(pkt_linked_item_t *data); +typedef void (*fixed_pkt_queue_cb)(fixed_pkt_queue_t *queue); + +// Creates a new fixed queue with the given |capacity|. If more elements than +// |capacity| are added to the queue, the caller is blocked until space is +// made available in the queue. Returns NULL on failure. The caller must free +// the returned queue with |fixed_pkt_queue_free|. +fixed_pkt_queue_t *fixed_pkt_queue_new(size_t capacity); + +// Freeing a queue that is currently in use (i.e. has waiters +// blocked on it) results in undefined behaviour. +void fixed_pkt_queue_free(fixed_pkt_queue_t *queue, fixed_pkt_queue_free_cb free_cb); + +// Returns a value indicating whether the given |queue| is empty. If |queue| +// is NULL, the return value is true. +bool fixed_pkt_queue_is_empty(fixed_pkt_queue_t *queue); + +// Returns the length of the |queue|. If |queue| is NULL, the return value +// is 0. +size_t fixed_pkt_queue_length(fixed_pkt_queue_t *queue); + +// Returns the maximum number of elements this queue may hold. |queue| may +// not be NULL. +size_t fixed_pkt_queue_capacity(fixed_pkt_queue_t *queue); + +// Enqueues the given |data| into the |queue|. The caller will be blocked or immediately return or wait for timeout according to the parameter timeout. +// If enqueue failed, it will return false, otherwise return true +bool fixed_pkt_queue_enqueue(fixed_pkt_queue_t *queue, pkt_linked_item_t *linked_pkt, uint32_t timeout); + +// Dequeues the next element from |queue|. If the queue is currently empty, +// this function will block the caller until an item is enqueued or immediately return or wait for timeout according to the parameter timeout. +// If dequeue failed, it will return NULL, otherwise return a point. +pkt_linked_item_t *fixed_pkt_queue_dequeue(fixed_pkt_queue_t *queue, uint32_t timeout); + +// Returns the first element from |queue|, if present, without dequeuing it. +// This function will never block the caller. Returns NULL if there are no +// elements in the queue or |queue| is NULL. +pkt_linked_item_t *fixed_pkt_queue_try_peek_first(fixed_pkt_queue_t *queue); + +// Registers |queue| with |reactor| for dequeue operations. When there is an element +// in the queue, ready_cb will be called. The |context| parameter is passed, untouched, +// to the callback routine. Neither |queue|, nor |reactor|, nor |read_cb| may be NULL. +// |context| may be NULL. +void fixed_pkt_queue_register_dequeue(fixed_pkt_queue_t *queue, fixed_pkt_queue_cb ready_cb); + +// Unregisters the dequeue ready callback for |queue| from whichever reactor +// it is registered with, if any. This function is idempotent. +void fixed_pkt_queue_unregister_dequeue(fixed_pkt_queue_t *queue); + +void fixed_pkt_queue_process(fixed_pkt_queue_t *queue); + +#endif