component/bt: add new OSI utility "fixed_pkt_queue", which has same functionality with "fixed_queue"

This commit is contained in:
wangmengyang 2022-07-20 11:18:33 +08:00
parent 3c14e739f0
commit fb01677372
3 changed files with 241 additions and 0 deletions

View File

@ -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"

View File

@ -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);
}
}

View File

@ -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