diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 3c5490b185..bdce5b4650 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -53,6 +53,7 @@ if(CONFIG_BT_ENABLED) "common/osi/buffer.c" "common/osi/config.c" "common/osi/fixed_queue.c" + "common/osi/pkt_queue.c" "common/osi/future.c" "common/osi/hash_functions.c" "common/osi/hash_map.c" diff --git a/components/bt/common/osi/include/osi/pkt_queue.h b/components/bt/common/osi/include/osi/pkt_queue.h new file mode 100644 index 0000000000..96277c3e18 --- /dev/null +++ b/components/bt/common/osi/include/osi/pkt_queue.h @@ -0,0 +1,88 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _PKT_LIST_H_ +#define _PKT_LIST_H_ + +#include "sys/queue.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct pkt_queue; + +typedef struct pkt_linked_item { + STAILQ_ENTRY(pkt_linked_item) next; + uint8_t data[]; +} pkt_linked_item_t; + +#define BT_PKT_LINKED_HDR_SIZE (sizeof (pkt_linked_item_t)) + +typedef void (*pkt_queue_free_cb)(pkt_linked_item_t *item); + +/* + * brief: create a pkt_queue instance. pkt_queue is a wrapper class of a FIFO implemented by single linked list. + * The enqueue and dequeue operations of the FIFO are protected against race conditions of multiple tasks + * return: NULL if not enough memory, otherwise a valid pointer + */ +struct pkt_queue *pkt_queue_create(void); + +/* + * brief: enqueue one item to the FIFO + * param queue: pkt_queue instance created using pkt_queue_create + * param item: the item to be enqueued to the FIFO + * return: true if enqueued successfully, false when the arguments passed in are invalid + */ +bool pkt_queue_enqueue(struct pkt_queue *queue, pkt_linked_item_t *item); + +/* + * brief: dequeue one item for the FIFO + * param queue: pkt_queue instance created using pkt_queue_create + * return: pointer of type pkt_linked_item_t dequeued, NULL if the queue is empty or upon exception + */ +pkt_linked_item_t *pkt_queue_dequeue(struct pkt_queue *queue); + +/* + * brief: get the pointer of the first item from the FIFO but not get it dequeued + * param queue: pkt_queue instance created using pkt_queue_create + * return: pointer of the first item in the FIFO, NULL if the FIFO is empty + */ +pkt_linked_item_t *pkt_queue_try_peek_first(struct pkt_queue *queue); + +/* + * brief: retrieve the number of items existing in the FIFO + * param queue: pkt_queue instance created using pkt_queue_create + * return: total number of items in the FIFO + */ +size_t pkt_queue_length(const struct pkt_queue *queue); + +/* + * brief: retrieve the status whether the FIFO is empty + * param queue: pkt_queue instance created using pkt_queue_create + * return: false if the FIFO is not empty, otherwise true + */ +bool pkt_queue_is_empty(const struct pkt_queue *queue); + +/* + * brief: delete the item in the FIFO one by one + * param free_cb: destructor function for each item in the FIFO, if set to NULL, will use osi_free_func by default + */ +void pkt_queue_flush(struct pkt_queue *queue, pkt_queue_free_cb free_cb); + +/* + * brief: delete the items in the FIFO and then destroy the pkt_queue instance. + * param free_cb: destructor function for each item in the FIFO, if set to NULL, will use osi_free_func by default + */ +void pkt_queue_destroy(struct pkt_queue *queue, pkt_queue_free_cb free_cb); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/bt/common/osi/pkt_queue.c b/components/bt/common/osi/pkt_queue.c new file mode 100644 index 0000000000..81abd1f043 --- /dev/null +++ b/components/bt/common/osi/pkt_queue.c @@ -0,0 +1,144 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "osi/pkt_queue.h" +#include "osi/allocator.h" +#include "osi/mutex.h" + + +STAILQ_HEAD(pkt_queue_header, pkt_linked_item); + +struct pkt_queue { + osi_mutex_t lock; + size_t length; + struct pkt_queue_header header; +} pkt_queue_t; + +struct pkt_queue *pkt_queue_create(void) +{ + struct pkt_queue *queue = calloc(1, sizeof(struct pkt_queue)); + if (queue == NULL) { + return NULL; + } + if (osi_mutex_new(&queue->lock) != 0) { + osi_free(queue); + } + struct pkt_queue_header *p = &queue->header; + STAILQ_INIT(p); + + return queue; +} + +static void pkt_queue_cleanup(struct pkt_queue *queue, pkt_queue_free_cb free_cb) +{ + if (queue == NULL) { + return; + } + + struct pkt_queue_header *header = &queue->header; + pkt_linked_item_t *item = STAILQ_FIRST(header); + pkt_linked_item_t *tmp; + + pkt_queue_free_cb free_func = (free_cb != NULL) ? free_cb : (pkt_queue_free_cb)osi_free_func; + + while (item != NULL) { + tmp = STAILQ_NEXT(item, next); + free_func(item); + item = tmp; + queue->length--; + } + STAILQ_INIT(header); + queue->length = 0; +} + +void pkt_queue_flush(struct pkt_queue *queue, pkt_queue_free_cb free_cb) +{ + if (queue == NULL) { + return; + } + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + pkt_queue_cleanup(queue, free_cb); + osi_mutex_unlock(&queue->lock); +} + +void pkt_queue_destroy(struct pkt_queue *queue, pkt_queue_free_cb free_cb) +{ + if (queue == NULL) { + return; + } + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + pkt_queue_cleanup(queue, free_cb); + osi_mutex_unlock(&queue->lock); + + osi_mutex_free(&queue->lock); + osi_free(queue); +} + +pkt_linked_item_t *pkt_queue_dequeue(struct pkt_queue *queue) +{ + if (queue == NULL || queue->length == 0) { + return NULL; + } + + struct pkt_linked_item *item; + struct pkt_queue_header *header; + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + header = &queue->header; + item = STAILQ_FIRST(header); + if (item != NULL) { + STAILQ_REMOVE_HEAD(header, next); + if (queue->length > 0) { + queue->length--; + } + } + osi_mutex_unlock(&queue->lock); + + return item; +} + +bool pkt_queue_enqueue(struct pkt_queue *queue, pkt_linked_item_t *item) +{ + if (queue == NULL || item == NULL) { + return false; + } + + struct pkt_queue_header *header; + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + header = &queue->header; + STAILQ_INSERT_TAIL(header, item, next); + queue->length++; + osi_mutex_unlock(&queue->lock); + + return true; +} + +size_t pkt_queue_length(const struct pkt_queue *queue) +{ + if (queue == NULL) { + return 0; + } + return queue->length; +} + +bool pkt_queue_is_empty(const struct pkt_queue *queue) +{ + return pkt_queue_length(queue) == 0; +} + +pkt_linked_item_t *pkt_queue_try_peek_first(struct pkt_queue *queue) +{ + if (queue == NULL) { + return NULL; + } + + struct pkt_queue_header *header = &queue->header; + pkt_linked_item_t *item; + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + item = STAILQ_FIRST(header); + osi_mutex_unlock(&queue->lock); + + return item; +}