feat(async): async supports thread, eventqueue, and real-time mode.
This commit is contained in:
@@ -29,14 +29,16 @@ static void irq_defer_hook_wakeup(void *param);
|
||||
static mr_irq_defer_hook_t __hook
|
||||
= {.suspend = irq_defer_hook_suspend, .wakeup = irq_defer_hook_wakeup};
|
||||
#endif /* defined(MR_USE_IRQ_DEFER_HOOK) */
|
||||
static mr_uint8_t __irqn[] = {
|
||||
WWDG_IRQn,
|
||||
};
|
||||
|
||||
#if defined(MR_USE_IRQ)
|
||||
static void irq_priority_set(mr_uint32_t irq, mr_uint8_t priority,
|
||||
void *param) {
|
||||
MR_UNUSED(param);
|
||||
|
||||
/* Set irq priority */
|
||||
NVIC_SetPriority((IRQn_Type)irq, priority);
|
||||
NVIC_SetPriority((IRQn_Type)__irqn[irq], priority);
|
||||
}
|
||||
|
||||
static void irq_type_set(mr_uint32_t irq, mr_uint8_t type, void *param) {
|
||||
@@ -49,7 +51,7 @@ static void irq_enable(mr_uint32_t irq, void *param) {
|
||||
MR_UNUSED(param);
|
||||
|
||||
/* Enable irq */
|
||||
NVIC_EnableIRQ((IRQn_Type)irq);
|
||||
NVIC_EnableIRQ((IRQn_Type)__irqn[irq]);
|
||||
}
|
||||
|
||||
static void irq_unmask(mr_uint32_t irq, void *param) {
|
||||
@@ -61,14 +63,13 @@ static void irq_disable(mr_uint32_t irq, void *param) {
|
||||
MR_UNUSED(param);
|
||||
|
||||
/* Disable irq */
|
||||
NVIC_DisableIRQ((IRQn_Type)irq);
|
||||
NVIC_DisableIRQ((IRQn_Type)__irqn[irq]);
|
||||
}
|
||||
|
||||
static void irq_mask(mr_uint32_t irq, void *param) {
|
||||
MR_UNUSED(irq);
|
||||
MR_UNUSED(param);
|
||||
}
|
||||
#endif /* defined(MR_USE_IRQ) */
|
||||
|
||||
#if defined(MR_USE_IRQ_DEFER_HOOK)
|
||||
static void irq_defer_hook_suspend(void *param) {
|
||||
@@ -94,12 +95,10 @@ void SW_Handler(void) {
|
||||
void mr_board_irq_init(void) {
|
||||
mr_err_t ret;
|
||||
|
||||
#if (MR_CFG_WCH_IRQ_END == MR_CFG_IRQ_TABLE_SIZE)
|
||||
#error "IRQ size exceed IRQ table, adjust 'MR_CFG_WCH_IRQ_END'"
|
||||
#endif /* (MR_CFG_WCH_IRQ_END == MR_CFG_IRQ_TABLE_SIZE) */
|
||||
/* Init irq */
|
||||
ret = mr_irq_init(&__irq, MR_CFG_WCH_IRQ_BEGIN, MR_CFG_WCH_IRQ_END, &__ops,
|
||||
MR_NULL);
|
||||
ret = mr_irq_init(&__irq, 0,
|
||||
MR_MIN(MR_ARRAY_SIZE(__irqn), MR_CFG_IRQ_TABLE_SIZE - 1),
|
||||
&__ops, MR_NULL);
|
||||
if (ret != 0) {
|
||||
MR_ASSERT(ret == 0);
|
||||
return;
|
||||
|
||||
@@ -42,27 +42,8 @@ config MR_CFG_WCH_IRQ_DEFER_PRIORITY
|
||||
default 2
|
||||
range MR_CFG_WCH_SYSTICK_IRQ_PRIORITY 15
|
||||
|
||||
config MR_CFG_WCH_IRQ_BEGIN
|
||||
int "IRQ begin"
|
||||
default 16
|
||||
range 2 MR_CFG_IRQ_TABLE_SIZE
|
||||
|
||||
config MR_CFG_WCH_IRQ_END
|
||||
int "IRQ end"
|
||||
default 38 if MR_USE_SERIES_V00X
|
||||
default 59 if MR_USE_SERIES_V10X
|
||||
default 69 if MR_USE_SERIES_V20X
|
||||
default 103 if MR_USE_SERIES_V30X
|
||||
range MR_CFG_WCH_IRQ_BEGIN MR_CFG_IRQ_TABLE_SIZE
|
||||
|
||||
if MR_CFG_WCH_IRQ_END=MR_CFG_IRQ_TABLE_SIZE
|
||||
comment "IRQ size exceed IRQ table, adjust 'Irq table size'"
|
||||
endif
|
||||
|
||||
if MR_CFG_WCH_IRQ_END<MR_CFG_IRQ_TABLE_SIZE
|
||||
config MR_USE_WCH_IRQ_DEFER_HOOK
|
||||
select MR_USE_IRQ_DEFER_HOOK
|
||||
def_bool y
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -34,23 +34,15 @@ extern "C" {
|
||||
typedef atomic_int mr_atomic_t;
|
||||
#define MR_ATOMIC_INIT(_val) ATOMIC_VAR_INIT(_val)
|
||||
#define mr_atomic_init(_a, _val) atomic_init(_a, _val)
|
||||
#define mr_atomic_load(_a) \
|
||||
atomic_load_explicit(_a, memory_order_seq_cst)
|
||||
#define mr_atomic_store(_a, _val) \
|
||||
atomic_store_explicit(_a, _val, memory_order_seq_cst)
|
||||
#define mr_atomic_exchange(_a, _val) \
|
||||
atomic_exchange_explicit(_a, _val, memory_order_seq_cst)
|
||||
#define mr_atomic_load(_a) atomic_load(_a)
|
||||
#define mr_atomic_store(_a, _val) atomic_store(_a, _val)
|
||||
#define mr_atomic_exchange(_a, _val) atomic_exchange(_a, _val)
|
||||
#define mr_atomic_compare_exchange(_a, _val, _desired) \
|
||||
atomic_compare_exchange_strong_explicit( \
|
||||
_a, _val, _desired, memory_order_seq_cst, memory_order_seq_cst)
|
||||
#define mr_atomic_fetch_add(_a, _val) \
|
||||
atomic_fetch_add_explicit(_a, _val, memory_order_seq_cst)
|
||||
#define mr_atomic_fetch_sub(_a, _val) \
|
||||
atomic_fetch_sub_explicit(_a, _val, memory_order_seq_cst)
|
||||
#define mr_atomic_fetch_and(_a, _val) \
|
||||
atomic_fetch_and_explicit(_a, _val, memory_order_seq_cst)
|
||||
#define mr_atomic_fetch_or(_a, _val) \
|
||||
atomic_fetch_or_explicit(_a, _val, memory_order_seq_cst)
|
||||
atomic_compare_exchange_strong(_a, _val, _desired)
|
||||
#define mr_atomic_fetch_add(_a, _val) atomic_fetch_add(_a, _val)
|
||||
#define mr_atomic_fetch_sub(_a, _val) atomic_fetch_sub(_a, _val)
|
||||
#define mr_atomic_fetch_and(_a, _val) atomic_fetch_and(_a, _val)
|
||||
#define mr_atomic_fetch_or(_a, _val) atomic_fetch_or(_a, _val)
|
||||
#elif defined(MR_USE_3PARTY_ATOMIC)
|
||||
/* In '3party/libc/mr_atomic.h' */
|
||||
#else
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
#if defined(MR_USE_STRING_LIBC)
|
||||
#include <string.h>
|
||||
#else
|
||||
#include <libc/mr_types.h>
|
||||
#endif /* defined(MR_USE_STRING_LIBC) */
|
||||
#include <libc/mr_compiler.h>
|
||||
#include <libc/mr_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -68,8 +68,8 @@ config MR_USE_IRQ
|
||||
config MR_CFG_IRQ_TABLE_SIZE
|
||||
depends on MR_USE_IRQ
|
||||
int "Irq table size"
|
||||
default 32
|
||||
range 4 1024
|
||||
default 16
|
||||
range 2 1024
|
||||
|
||||
config MR_USE_IRQ_DEFER
|
||||
depends on MR_USE_IRQ
|
||||
@@ -91,9 +91,9 @@ config MR_USE_ASYNC
|
||||
bool "Use async"
|
||||
default y
|
||||
|
||||
config MR_USE_ASYNC_SYNC
|
||||
config MR_USE_ASYNC_THREAD
|
||||
depends on MR_USE_ASYNC
|
||||
bool "Use async sync"
|
||||
bool "Use async thread"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -34,10 +34,21 @@ typedef struct mr_await {
|
||||
mr_list_t list;
|
||||
} mr_await_t;
|
||||
|
||||
/* Async mode type */
|
||||
typedef enum mr_async_mode {
|
||||
#if defined(MR_USE_ASYNC_THREAD)
|
||||
MR_ASYNC_THREAD,
|
||||
#endif /* defined(MR_USE_ASYNC_THREAD) */
|
||||
MR_ASYNC_QUEUE,
|
||||
MR_ASYNC_RTM,
|
||||
} mr_async_mode_t;
|
||||
|
||||
/* Async type */
|
||||
typedef struct mr_async {
|
||||
mr_object_t parent;
|
||||
#if defined(MR_USE_ASYNC_THREAD)
|
||||
mr_await_t await;
|
||||
#endif /* defined(MR_USE_ASYNC_THREAD) */
|
||||
mr_int32_t label;
|
||||
mr_list_t list;
|
||||
mr_work_t work;
|
||||
@@ -139,13 +150,16 @@ mr_async_t *mr_async_create(mr_async_entry_t *entry, void *param);
|
||||
mr_err_t mr_async_del(mr_async_t *async);
|
||||
|
||||
/**
|
||||
* @brief This macro function binds an async to a workqueue.
|
||||
* @brief This function runs an async.
|
||||
*
|
||||
* @param _async The async.
|
||||
* @param _queue The workqueue.
|
||||
* @param async The async.
|
||||
* @param mode The async mode.
|
||||
* @param queue The async workqueue(use on 'MR_ASYNC_QUEUE' or
|
||||
* 'MR_ASYNC_THREAD').
|
||||
* @return 0 on success, a negative error code on failure.
|
||||
*/
|
||||
#define mr_async_bind(_async, _queue) \
|
||||
mr_workqueue_bind(_queue, &(_async)->work)
|
||||
mr_err_t mr_async_run(mr_async_t *async, mr_async_mode_t mode,
|
||||
mr_workqueue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief This macro function checks if an async is waiting.
|
||||
@@ -160,10 +174,12 @@ mr_err_t mr_async_del(mr_async_t *async);
|
||||
* @param async The async.
|
||||
* @return 0 on success, a negative error code on failure.
|
||||
*
|
||||
* @note All async-io may generate asynchronous behaviors, which can be cancelled by this function.
|
||||
* @note All async-io may generate asynchronous behaviors, which can be
|
||||
* cancelled by this function.
|
||||
*/
|
||||
mr_err_t mr_async_cancel(mr_async_t *async);
|
||||
|
||||
#if defined(MR_USE_ASYNC_THREAD)
|
||||
/**
|
||||
* @brief This macro function waits for an async.
|
||||
*
|
||||
@@ -174,21 +190,15 @@ mr_err_t mr_async_cancel(mr_async_t *async);
|
||||
*/
|
||||
#define mr_async_wait_async(_async, _wait_async) \
|
||||
mr_await_wait(&(_wait_async)->await, _async)
|
||||
#endif /* defined(MR_USE_ASYNC_THREAD) */
|
||||
|
||||
#if defined(MR_USE_ASYNC_SYNC)
|
||||
/**
|
||||
* @brief This macro function runs an async.
|
||||
*
|
||||
* @param _async The async.
|
||||
* @param _queue The workqueue.
|
||||
*/
|
||||
#define mr_async_run(_async, _queue) \
|
||||
mr_workqueue_work(_queue, &(_async)->work)
|
||||
|
||||
#if defined(MR_USE_ASYNC_THREAD)
|
||||
/**
|
||||
* @brief This macro function begins an async.
|
||||
*
|
||||
* @param _async The async.
|
||||
*
|
||||
* @note It can only be used async thread mode.
|
||||
*/
|
||||
#define mr_async_begin(_async) \
|
||||
switch ((_async)->label) { \
|
||||
@@ -199,6 +209,8 @@ mr_err_t mr_async_cancel(mr_async_t *async);
|
||||
* @brief This macro function ends an async.
|
||||
*
|
||||
* @param _async The async.
|
||||
*
|
||||
* @note It can only be used async thread mode.
|
||||
*/
|
||||
#define mr_async_end(_async) \
|
||||
(_async)->label = -1; \
|
||||
@@ -278,7 +290,7 @@ mr_err_t mr_async_cancel(mr_async_t *async);
|
||||
mr_async_cancel(_async); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif /* defined(MR_USE_ASYNC_SYNC) */
|
||||
#endif /* defined(MR_USE_ASYNC_THREAD) */
|
||||
|
||||
/**
|
||||
* @brief This function gets an async.
|
||||
|
||||
@@ -78,11 +78,11 @@ static void await_remove(mr_await_t *await) {
|
||||
while (!mr_list_is_empty(&await->list)) {
|
||||
async = MR_CONTAINER_OF(await->list.next, mr_async_t, list);
|
||||
|
||||
/* Resume async */
|
||||
mr_work_schedule(&async->work);
|
||||
|
||||
/* Remove async from waiting list */
|
||||
mr_list_del(&async->list);
|
||||
|
||||
/* Resume async */
|
||||
mr_work_schedule(&async->work);
|
||||
}
|
||||
|
||||
/* Unlock */
|
||||
@@ -131,7 +131,10 @@ mr_err_t mr_await_wait(mr_await_t *await, mr_async_t *async) {
|
||||
}
|
||||
|
||||
mr_err_t mr_await_complete(mr_await_t *await) {
|
||||
mr_async_entry_t *entry;
|
||||
mr_async_t *async;
|
||||
mr_list_t rtmlist;
|
||||
void *param;
|
||||
int mask;
|
||||
|
||||
/* Check parameter */
|
||||
@@ -143,6 +146,9 @@ mr_err_t mr_await_complete(mr_await_t *await) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Init real-time list */
|
||||
mr_list_init(&rtmlist);
|
||||
|
||||
/* Lock */
|
||||
mask = mr_spinlock_lock_irqsave(&__lock);
|
||||
|
||||
@@ -153,9 +159,31 @@ mr_err_t mr_await_complete(mr_await_t *await) {
|
||||
/* Remove async from waiting list */
|
||||
mr_list_del(&async->list);
|
||||
|
||||
/* Force resume async(it might be running a timer) */
|
||||
mr_work_cancel(&async->work);
|
||||
mr_work_schedule(&async->work);
|
||||
/* Check if async is in thread or queue mode */
|
||||
if (async->work.queue) {
|
||||
/* Force resume async(it might be running a timer) */
|
||||
mr_work_cancel(&async->work);
|
||||
mr_work_schedule(&async->work);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Move async to real-time list */
|
||||
mr_list_move(&async->list, &rtmlist);
|
||||
}
|
||||
|
||||
/* Check real-time list */
|
||||
while (!mr_list_is_empty(&rtmlist)) {
|
||||
async = MR_LIST_ENTRY(rtmlist.next, mr_async_t, list);
|
||||
|
||||
/* Remove async from real-time list */
|
||||
mr_list_del(&async->list);
|
||||
|
||||
/* Save async entry and param */
|
||||
entry = (mr_async_entry_t *)async->entry;
|
||||
param = (void *)async->work.param;
|
||||
|
||||
/* Call async entry */
|
||||
entry(async, param);
|
||||
}
|
||||
|
||||
/* Unlock */
|
||||
@@ -207,7 +235,9 @@ static mr_err_t async_init(mr_async_t *async, const mr_class_t *class,
|
||||
mr_ptr_t entry, mr_ptr_t param) {
|
||||
/* Init async */
|
||||
mr_work_init(&async->work, async_work_entry, param);
|
||||
#if defined(MR_USE_ASYNC_THREAD)
|
||||
mr_await_init(&async->await, 1);
|
||||
#endif /* defined(MR_USE_ASYNC_THREAD) */
|
||||
mr_list_init(&async->list);
|
||||
async->entry = entry;
|
||||
async->label = 0;
|
||||
@@ -275,6 +305,55 @@ mr_err_t mr_async_del(mr_async_t *async) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mr_err_t mr_async_run(mr_async_t *async, mr_async_mode_t mode,
|
||||
mr_workqueue_t *queue) {
|
||||
mr_err_t ret;
|
||||
|
||||
/* Check parameter */
|
||||
MR_ASSERT((async != MR_NULL) && MR_OBJECT_IS_INITED(async));
|
||||
MR_ASSERT((mode < MR_ASYNC_RTM) && (queue != MR_NULL));
|
||||
MR_ASSERT(mode <= MR_ASYNC_RTM);
|
||||
|
||||
/* Check if mode is workqueue mode */
|
||||
if (mode == MR_ASYNC_QUEUE
|
||||
#if defined(MR_USE_ASYNC_THREAD)
|
||||
|| mode == MR_ASYNC_THREAD
|
||||
#endif /* defined(MR_USE_ASYNC_THREAD) */
|
||||
) {
|
||||
/* Get workqueue */
|
||||
queue = mr_workqueue_get(queue);
|
||||
if (!queue) {
|
||||
return -MR_ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
#if defined(MR_USE_ASYNC_THREAD)
|
||||
case MR_ASYNC_THREAD: {
|
||||
ret = mr_workqueue_work(queue, &async->work);
|
||||
break;
|
||||
}
|
||||
#endif /* defined(MR_USE_ASYNC_THREAD) */
|
||||
case MR_ASYNC_QUEUE: {
|
||||
ret = mr_work_bind(&async->work, queue);
|
||||
break;
|
||||
}
|
||||
case MR_ASYNC_RTM: {
|
||||
/* Real-time mode */
|
||||
mr_work_cancel(&async->work);
|
||||
async->work.queue = MR_NULL;
|
||||
return 0;
|
||||
}
|
||||
default: {
|
||||
return -MR_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Put workqueue */
|
||||
mr_workqueue_put(queue);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mr_err_t mr_async_cancel(mr_async_t *async) {
|
||||
/* Check parameter */
|
||||
MR_ASSERT((async != MR_NULL) && MR_OBJECT_IS_INITED(async));
|
||||
@@ -292,8 +371,10 @@ static mr_async_t *async_obj_release(mr_object_t *obj) {
|
||||
/* Get async */
|
||||
async = MR_CONTAINER_OF(obj, mr_async_t, parent);
|
||||
|
||||
#if defined(MR_USE_ASYNC_THREAD)
|
||||
/* Complete await */
|
||||
mr_await_complete(&async->await);
|
||||
#endif /* defined(MR_USE_ASYNC_THREAD) */
|
||||
|
||||
/* Delete async */
|
||||
mr_work_del(&async->work);
|
||||
|
||||
@@ -215,7 +215,7 @@ static mr_tick_t timer_timeout_check(void) {
|
||||
void *param;
|
||||
int mask;
|
||||
|
||||
/* Init operation list and tick */
|
||||
/* Init operation list */
|
||||
mr_list_init(&oplist);
|
||||
|
||||
/* Lock */
|
||||
|
||||
Reference in New Issue
Block a user