mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 20:24:32 +02:00
component/bt: add new OSI utility "osi_event" to support the scenario that event need only to be handle once.
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
#define OSI_THREAD_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT
|
#define OSI_THREAD_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT
|
||||||
|
|
||||||
struct osi_thread;
|
struct osi_thread;
|
||||||
|
struct osi_event;
|
||||||
|
|
||||||
typedef struct osi_thread osi_thread_t;
|
typedef struct osi_thread osi_thread_t;
|
||||||
|
|
||||||
@@ -88,4 +89,42 @@ const char *osi_thread_name(osi_thread_t *thread);
|
|||||||
*/
|
*/
|
||||||
int osi_thread_queue_wait_size(osi_thread_t *thread, int wq_idx);
|
int osi_thread_queue_wait_size(osi_thread_t *thread, int wq_idx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* brief: Create an osi_event struct and register the handler function and its argument
|
||||||
|
* An osi_event is a kind of work that can be posted to the workqueue of osi_thread to process,
|
||||||
|
* but the work can have at most one instance the thread workqueue before it is processed. This
|
||||||
|
* allows the "single post, multiple data processing" jobs.
|
||||||
|
* param func: the handler to process the job
|
||||||
|
* param context: the argument to be passed to the handler function when the job is being processed
|
||||||
|
* return: NULL if no memory, otherwise a valid struct pointer
|
||||||
|
*/
|
||||||
|
struct osi_event *osi_event_create(osi_thread_func_t func, void *context);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* brief: Bind an osi_event to a specific work queue for an osi_thread.
|
||||||
|
* After binding is completed, a function call of API osi_thread_post_event will send a work
|
||||||
|
* to the workqueue of the thread, with specified queue index.
|
||||||
|
* param func: event: the pointer to osi_event that is created using osi_event_create
|
||||||
|
* param thread: the pointer to osi_thread that is created using osi_thread_create
|
||||||
|
* param queue_idx: the index of the workqueue of the specified osi_thread, with range starting from 0 to work_queue_num - 1
|
||||||
|
* return: true if osi_event binds to the thread's workqueue successfully, otherwise false
|
||||||
|
*/
|
||||||
|
bool osi_event_bind(struct osi_event* event, osi_thread_t *thread, int queue_idx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* brief: Destroy the osi_event struct created by osi_event_create and free the allocated memory
|
||||||
|
* param event: the pointer to osi_event
|
||||||
|
*/
|
||||||
|
void osi_event_delete(struct osi_event* event);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* brief: try sending a work to the binded thread's workqueue, so that it can be handled by the worker thread
|
||||||
|
* param event: pointer to osi_event, created by osi_event_create
|
||||||
|
* param timeout: post timeout, OSI_THREAD_MAX_TIMEOUT means blocking forever, 0 means never blocking, others means block millisecond
|
||||||
|
* return: true if the message is enqueued to the thread workqueue, otherwise failed
|
||||||
|
* note: if the return value of function is false, it is the case that the workqueue of the thread is full, and users
|
||||||
|
* are expected to post the event sometime later to get the work handled.
|
||||||
|
*/
|
||||||
|
bool osi_thread_post_event(struct osi_event *event, uint32_t timeout);
|
||||||
|
|
||||||
#endif /* __THREAD_H__ */
|
#endif /* __THREAD_H__ */
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
#include "freertos/queue.h"
|
#include "freertos/queue.h"
|
||||||
#include "osi/semaphore.h"
|
#include "osi/semaphore.h"
|
||||||
#include "osi/thread.h"
|
#include "osi/thread.h"
|
||||||
|
#include "osi/mutex.h"
|
||||||
|
|
||||||
struct work_item {
|
struct work_item {
|
||||||
osi_thread_func_t func;
|
osi_thread_func_t func;
|
||||||
@@ -50,6 +51,14 @@ struct osi_thread_start_arg {
|
|||||||
int error;
|
int error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct osi_event {
|
||||||
|
struct work_item item;
|
||||||
|
osi_mutex_t lock;
|
||||||
|
uint16_t is_queued;
|
||||||
|
uint16_t queue_idx;
|
||||||
|
osi_thread_t *thread;
|
||||||
|
};
|
||||||
|
|
||||||
static const size_t DEFAULT_WORK_QUEUE_CAPACITY = 100;
|
static const size_t DEFAULT_WORK_QUEUE_CAPACITY = 100;
|
||||||
|
|
||||||
static struct work_queue *osi_work_queue_create(size_t capacity)
|
static struct work_queue *osi_work_queue_create(size_t capacity)
|
||||||
@@ -364,3 +373,81 @@ int osi_thread_queue_wait_size(osi_thread_t *thread, int wq_idx)
|
|||||||
|
|
||||||
return (int)(osi_thead_work_queue_len(thread->work_queues[wq_idx]));
|
return (int)(osi_thead_work_queue_len(thread->work_queues[wq_idx]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct osi_event *osi_event_create(osi_thread_func_t func, void *context)
|
||||||
|
{
|
||||||
|
struct osi_event *event = osi_calloc(sizeof(struct osi_event));
|
||||||
|
if (event != NULL) {
|
||||||
|
if (osi_mutex_new(&event->lock) == 0) {
|
||||||
|
event->item.func = func;
|
||||||
|
event->item.context = context;
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
osi_free(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void osi_event_delete(struct osi_event* event)
|
||||||
|
{
|
||||||
|
if (event != NULL) {
|
||||||
|
osi_mutex_free(&event->lock);
|
||||||
|
memset(event, 0, sizeof(struct osi_event));
|
||||||
|
osi_free(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool osi_event_bind(struct osi_event* event, osi_thread_t *thread, int queue_idx)
|
||||||
|
{
|
||||||
|
if (event == NULL || event->thread != NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread == NULL || queue_idx >= thread->work_queue_num) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
event->thread = thread;
|
||||||
|
event->queue_idx = queue_idx;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void osi_thread_generic_event_handler(void *context)
|
||||||
|
{
|
||||||
|
struct osi_event *event = (struct osi_event *)context;
|
||||||
|
if (event != NULL && event->item.func != NULL) {
|
||||||
|
osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||||
|
event->is_queued = 0;
|
||||||
|
osi_mutex_unlock(&event->lock);
|
||||||
|
event->item.func(event->item.context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool osi_thread_post_event(struct osi_event *event, uint32_t timeout)
|
||||||
|
{
|
||||||
|
assert(event != NULL && event->thread != NULL);
|
||||||
|
assert(event->queue_idx >= 0 && event->queue_idx < event->thread->work_queue_num);
|
||||||
|
bool ret = false;
|
||||||
|
if (event->is_queued == 0) {
|
||||||
|
uint16_t acquire_cnt = 0;
|
||||||
|
osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||||
|
event->is_queued += 1;
|
||||||
|
acquire_cnt = event->is_queued;
|
||||||
|
osi_mutex_unlock(&event->lock);
|
||||||
|
|
||||||
|
if (acquire_cnt == 1) {
|
||||||
|
ret = osi_thread_post(event->thread, osi_thread_generic_event_handler, event, event->queue_idx, timeout);
|
||||||
|
if (!ret) {
|
||||||
|
// clear "is_queued" when post failure, to allow for following event posts
|
||||||
|
osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||||
|
event->is_queued = 0;
|
||||||
|
osi_mutex_unlock(&event->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user