From 8a8231d1824ebb5855fbcd2f6383101e9db57736 Mon Sep 17 00:00:00 2001 From: MacRsh Date: Tue, 22 Jul 2025 21:08:32 +0800 Subject: [PATCH] feat(wait): New wait function added. 1.The wait module is used to complete the interrupt notification of the upper-level sub-module (this wait module only implements the notification function, facilitating the upper-level to replace different asynchronous implementations). --- include/mr-X/Kconfig | 7 + include/mr-X/mr_irq.h | 8 +- include/mr-X/mr_wait.h | 158 ++++++++++++++++ include/mr_x.h | 1 + kernel/irq.c | 10 +- kernel/wait.c | 397 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 572 insertions(+), 9 deletions(-) create mode 100644 include/mr-X/mr_wait.h create mode 100644 kernel/wait.c diff --git a/include/mr-X/Kconfig b/include/mr-X/Kconfig index b728b67..e6c0c75 100644 --- a/include/mr-X/Kconfig +++ b/include/mr-X/Kconfig @@ -83,4 +83,11 @@ config MR_USE_IRQ_DEFER_HOOK bool "Use irq defer hook" default n +# ================================== +# WAIT +# ================================== +config MR_USE_WAIT + bool "Use irq" + default y + endmenu diff --git a/include/mr-X/mr_irq.h b/include/mr-X/mr_irq.h index ee0f8fb..a9ff668 100644 --- a/include/mr-X/mr_irq.h +++ b/include/mr-X/mr_irq.h @@ -87,8 +87,8 @@ typedef struct mr_irq_action { /* Irq descriptor type */ typedef struct mr_irq_desc { mr_irq_action_t *action; - mr_uint32_t priority; - mr_uint32_t flags; + mr_uint16_t priority; + mr_uint16_t flags; mr_atomic_t depth; mr_irq_t *irq; } mr_irq_desc_t; @@ -139,7 +139,7 @@ mr_err_t mr_irq_del(mr_irq_t *irq); * @return 0 on success, a negative error code on failure. */ mr_err_t mr_irq_request(mr_uint32_t irq, mr_irq_entry_t *entry, void *owner, - mr_uint32_t flags); + mr_uint16_t flags); #if defined(MR_USE_IRQ_DEFER) /** @@ -153,7 +153,7 @@ mr_err_t mr_irq_request(mr_uint32_t irq, mr_irq_entry_t *entry, void *owner, * @return 0 on success, a negative error code on failure. */ mr_err_t mr_irq_defer_request(mr_uint32_t irq, mr_irq_entry_t *entry, - void *owner, mr_uint32_t flags, + void *owner, mr_uint16_t flags, mr_irq_entry_t *defer_entry); #endif /* defined(MR_USE_IRQ_DEFER) */ diff --git a/include/mr-X/mr_wait.h b/include/mr-X/mr_wait.h new file mode 100644 index 0000000..7ef7d0f --- /dev/null +++ b/include/mr-X/mr_wait.h @@ -0,0 +1,158 @@ +/** + * @copyright (c) 2024-2025, MacRsh + * + * @license SPDX-License-Identifier: Apache-2.0 + * + * @date 2024-09-06 MacRsh First version + */ + +#ifndef __MR_WAIT_H__ +#define __MR_WAIT_H__ + +#include +#if defined(MR_USE_WAIT) +#include +#include +#endif /* defined(MR_USE_WAIT) */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @addtogroup Wait + * @{ + */ + +#if defined(MR_USE_WAIT) +/* Wait event definition */ +#define MR_WAIT_IN (0x10000000U) +#define MR_WAIT_OUT (0x20000000U) +#define MR_WAIT_ERR (0x40000000U) +#define MR_WAIT_EDGE (0x80000000U) + +/* Waitable type */ +typedef struct mr_waitable { + mr_object_t parent; + mr_uint32_t last; + mr_list_t list; + mr_ptr_t check; + mr_ptr_t param; +} mr_waitable_t; + +/* Wait check type */ +typedef mr_uint32_t(mr_waitable_check_t)(mr_waitable_t *waitable, void *param); + +/* Waiter type */ +typedef struct mr_waiter { + mr_object_t parent; + mr_uint32_t event; + mr_list_t list; + mr_ptr_t entry; + mr_ptr_t param; +} mr_waiter_t; + +/* Wait entry type */ +typedef void(mr_waiter_entry_t)(mr_waiter_t *waiter, void *param, + mr_uint32_t event); + +/** + * @brief This function initializes a waitable. + * + * @param waitable The waitable. + * @param check The waitable check. + * @param param The check parameter. + * @return 0 on success, a negative error code on failure. + */ +mr_err_t mr_waitable_init(mr_waitable_t *waitable, mr_waitable_check_t *check, + void *param); + +/** + * @brief This function creates a waitable. + * + * @param check The waitable check. + * @param param The check parameter. + * @return The waitable on success, NULL on failure. + */ +mr_waitable_t *mr_waitable_create(mr_waitable_check_t *check, void *param); + +/** + * @brief This function deletes a waitable. + * + * @param waitable The waitable. + * @return 0 on success, a negative error code on failure. + */ +mr_err_t mr_waitable_del(mr_waitable_t *waitable); + +/** + * @brief This function completes a waitable. + * + * @param waitable The waitable. + * @return 0 on success, a negative error code on failure. + */ +mr_err_t mr_waitable_complete(mr_waitable_t *waitable); + +/** + * @brief This function initializes a waiter. + * + * @param waiter The waiter. + * @param entry The wait entry. + * @param param The entry parameter. + * @param event The wait event('IN||OUT||ERR'). + * @return 0 on success, a negative error code on failure. + */ +mr_err_t mr_waiter_init(mr_waiter_t *waiter, mr_waiter_entry_t *entry, + void *param, mr_uint32_t event); + +/** + * @brief This function creates a waiter. + * + * @param entry The wait entry. + * @param param The entry parameter. + * @param event The wait event('IN||OUT||ERR'). + * @return The waiter on success, NULL on failure. + */ +mr_waiter_t *mr_waiter_create(mr_waiter_entry_t *entry, void *param, + mr_uint32_t event); + +/** + * @brief This function deletes a waiter. + * + * @param waiter The waiter. + * @return 0 on success, a negative error code on failure. + */ +mr_err_t mr_waiter_del(mr_waiter_t *waiter); + +/** + * @brief This function checks if a waiter is waiting. + * + * @param waiter The waiter. + * @return MR_TRUE if the waiter is waiting, false otherwise. + */ +#define MR_WAITER_IS_WAITING(_waiter) (!mr_list_is_empty(&(_waiter)->list)) + +/** + * @brief This function waits for a waitable. + * + * @param waiter The waiter. + * @param waitable The waitable. + * @return 0 on success, a negative error code on failure. + */ +mr_err_t mr_waiter_wait(mr_waiter_t *waiter, mr_waitable_t *waitable); + +/** + * @brief This function cancels a waiter. + * + * @param waiter The waiter. + * @return 0 on success, a negative error code on failure. + */ +mr_err_t mr_waiter_cancel(mr_waiter_t *waiter); +#endif /* defined(MR_USE_WAIT) */ + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MR_WAIT_H__ */ diff --git a/include/mr_x.h b/include/mr_x.h index 0e26faa..5968d1c 100644 --- a/include/mr_x.h +++ b/include/mr_x.h @@ -29,6 +29,7 @@ #include #include #include +#include #include /** @} */ diff --git a/kernel/irq.c b/kernel/irq.c index 412912d..cb49b9a 100644 --- a/kernel/irq.c +++ b/kernel/irq.c @@ -37,7 +37,7 @@ static mr_irq_defer_hook_t __hook = {.wakeup = MR_NULL, .suspend = MR_NULL}; /* Irq priority default definition */ #define IRQ_PRIORITY_DEFAULT (0) /* Irq flags definition */ -#define IRQ_FLAG_TYPE_MASK (0x0f) +#define IRQ_FLAG_TYPE_MASK (0x0fU) /* Irq action pending definition */ #define IRQ_ACTION_PENDING (1U << 31) @@ -296,7 +296,7 @@ static void irq_depth_enable(mr_uint32_t irq, mr_irq_desc_t *desc) { desc->irq->ops->enable(irq, desc->irq->param); } -static mr_err_t irq_request(mr_uint32_t irq, mr_uint32_t flags, +static mr_err_t irq_request(mr_uint32_t irq, mr_uint16_t flags, mr_irq_action_t *action) { mr_irq_action_t **a; mr_irq_desc_t *desc; @@ -361,7 +361,7 @@ _exit: } static mr_err_t irq_defer_request(mr_uint32_t irq, mr_irq_entry_t *entry, - mr_ptr_t owner, mr_uint32_t flags, + mr_ptr_t owner, mr_uint16_t flags, mr_irq_entry_t *defer_entry) { mr_irq_action_t *action; mr_err_t ret; @@ -382,7 +382,7 @@ static mr_err_t irq_defer_request(mr_uint32_t irq, mr_irq_entry_t *entry, } mr_err_t mr_irq_request(mr_uint32_t irq, mr_irq_entry_t *entry, void *owner, - mr_uint32_t flags) { + mr_uint16_t flags) { /* Check parameter */ MR_ASSERT(irq < MR_CFG_IRQ_TABLE_SIZE); MR_ASSERT((entry != MR_NULL) && (owner != MR_NULL)); @@ -393,7 +393,7 @@ mr_err_t mr_irq_request(mr_uint32_t irq, mr_irq_entry_t *entry, void *owner, } mr_err_t mr_irq_defer_request(mr_uint32_t irq, mr_irq_entry_t *entry, - void *owner, mr_uint32_t flags, + void *owner, mr_uint16_t flags, mr_irq_entry_t *defer_entry) { /* Check parameter */ MR_ASSERT(irq < MR_CFG_IRQ_TABLE_SIZE); diff --git a/kernel/wait.c b/kernel/wait.c new file mode 100644 index 0000000..d801f1a --- /dev/null +++ b/kernel/wait.c @@ -0,0 +1,397 @@ +/** + * @copyright (c) 2024-2025, MacRsh + * + * @license SPDX-License-Identifier: Apache-2.0 + * + * @date 2024-09-06 MacRsh First version + */ + +#include +#if defined(MR_USE_WAIT) +#include +#include + +/* Waitable clazz(static & dynamic) */ +static void able_obj_release1(mr_object_t *obj); +static void able_obj_release2(mr_object_t *obj); +static const mr_clazz_t __able_clazz1 + = MR_CLAZZ_INIT("waitable", able_obj_release1); +static const mr_clazz_t __able_clazz2 + = MR_CLAZZ_INIT("waitable", able_obj_release2); + +/* Waiter clazz(static & dynamic) */ +static void wait_obj_release1(mr_object_t *obj); +static void wait_obj_release2(mr_object_t *obj); +static const mr_clazz_t __wait_clazz1 + = MR_CLAZZ_INIT("waiter", wait_obj_release1); +static const mr_clazz_t __wait_clazz2 + = MR_CLAZZ_INIT("waiter", wait_obj_release2); + +/* Wait lock */ +static mr_spinlock_t __lock = MR_SPINLOCK_INIT(); + +/* Wait event mask definition */ +#define WAIT_TYPE_MASK (0x70000000U) +#define WAIT_MASK (0x7fffffffU) + +static mr_err_t waitable_init(mr_waitable_t *waitable, const mr_clazz_t *class, + mr_ptr_t check, mr_ptr_t param) { + /* Init waitable */ + mr_list_init(&waitable->list); + waitable->check = check; + waitable->param = param; + waitable->last = 0; + + /* Init object */ + return mr_object_init((mr_object_t *)waitable, class); +} + +mr_err_t mr_waitable_init(mr_waitable_t *waitable, mr_waitable_check_t *check, + void *param) { + /* Check parameter */ + MR_ASSERT((waitable != MR_NULL) && (!MR_OBJECT_IS_INITED(waitable))); + MR_ASSERT(check != MR_NULL); + + /* Init waitable */ + return waitable_init(waitable, &__able_clazz1, check, param); +} + +mr_waitable_t *mr_waitable_create(mr_waitable_check_t *check, void *param) { + mr_waitable_t *waitable; + mr_err_t ret; + + /* Check parameter */ + MR_ASSERT(check != MR_NULL); + + /* Create waitable */ + waitable = mr_malloc(sizeof(mr_waitable_t)); + if (!waitable) { + return MR_NULL; + } + + /* Init waitable */ + ret = waitable_init(waitable, &__able_clazz2, check, param); + if (ret != 0) { + mr_free(waitable); + return MR_NULL; + } + return waitable; +} + +static void waitable_remove(mr_waitable_t *waitable) { + mr_waiter_t *waiter; + int mask; + + /* Lock */ + mask = mr_spinlock_lock_irqsave(&__lock); + + /* Clear waiting list */ + while (!mr_list_is_empty(&waitable->list)) { + waiter = MR_LIST_ENTRY(waitable->list.next, mr_waiter_t, list); + + /* Remove waiter from waiting list */ + mr_list_del(&waiter->list); + } + + /* Unlock */ + mr_spinlock_unlock_irqrestore(&__lock, mask); +} + +mr_err_t mr_waitable_del(mr_waitable_t *waitable) { + /* Check parameter */ + MR_ASSERT((waitable != MR_NULL) && MR_OBJECT_IS_INITED(waitable)); + MR_ASSERT(MR_OBJECT_CLAZZ_IS_OR(waitable, &__able_clazz1, &__able_clazz2)); + + /* Remove waitable */ + waitable_remove(waitable); + + /* Delete object */ + mr_object_del((mr_object_t *)waitable); + return 0; +} + +static mr_uint32_t waitable_check(mr_waitable_t *waitable) { + mr_waitable_check_t *check; + mr_uint32_t event; + void *param; + + /* Save waitable check and param */ + check = (mr_waitable_check_t *)waitable->check; + param = (void *)waitable->param; + + /* Call waitable check */ + event = check(waitable, param); + event &= WAIT_MASK; + return event; +} + +mr_err_t mr_waitable_complete(mr_waitable_t *waitable) { + mr_uint32_t event, event_level, event_edge; + mr_waiter_entry_t *entry; + mr_waiter_t *waiter; + mr_list_t oplist; + void *param; + int mask; + + /* Check parameter */ + MR_ASSERT((waitable != MR_NULL) && MR_OBJECT_IS_INITED(waitable)); + MR_ASSERT(MR_OBJECT_CLAZZ_IS_OR(waitable, &__able_clazz1, &__able_clazz2)); + + /* Reduce unnecessary check operations */ + if (mr_list_is_empty(&waitable->list)) { + return 0; + } + + /* Get waitable event */ + event = waitable_check(waitable); + if ((event & WAIT_TYPE_MASK) == 0) { + /* No waitable event(untyped events will be discarded) */ + return 0; + } + + /* Init operation list */ + mr_list_init(&oplist); + + /* Lock */ + mask = mr_spinlock_lock_irqsave(&__lock); + + /* Get edge and level event */ + event_edge = event & ~waitable->last; + event_level = event; + + /* Replace the waiting list with the operation list (to prevent node removal + * in the middle) */ + mr_list_replace(&oplist, &waitable->list); + + /* Check operation list */ + while (!mr_list_is_empty(&oplist)) { + waiter = MR_LIST_ENTRY(oplist.next, mr_waiter_t, list); + + /* Move waiter to waiting list */ + mr_list_move(&waiter->list, &waitable->list); + + /* Check if waiter is triggered */ + event = (waiter->event & MR_WAIT_EDGE) ? event_edge : event_level; + if (!(waiter->event & event)) { + /* Not triggered */ + continue; + } + + /* Save waiter entry and param */ + entry = (mr_waiter_entry_t *)waiter->entry; + param = (void *)waiter->param; + + /* Unlock */ + mr_spinlock_unlock_irqrestore(&__lock, mask); + + /* Call waiter entry */ + entry(waiter, param, event); + + /* Lock */ + mask = mr_spinlock_lock_irqsave(&__lock); + } + + /* Update waitable last event */ + waitable->last = event; + + /* Unlock */ + mr_spinlock_unlock_irqrestore(&__lock, mask); + return 0; +} + +static mr_waitable_t *able_obj_release(mr_object_t *obj) { + mr_waitable_t *waitable; + + /* Get waitable */ + waitable = MR_CONTAINER_OF(obj, mr_waitable_t, parent); + + /* Remove waitable */ + waitable_remove(waitable); + return waitable; +} + +static void able_obj_release1(mr_object_t *obj) { + /* Release waitable */ + able_obj_release(obj); +} + +static void able_obj_release2(mr_object_t *obj) { + mr_waitable_t *waitable; + + /* Release waitable */ + waitable = able_obj_release(obj); + + /* Free waitable */ + mr_free(waitable); +} + +static mr_err_t waiter_init(mr_waiter_t *waiter, const mr_clazz_t *class, + mr_ptr_t entry, mr_ptr_t param, mr_uint32_t event) { + /* Init waiter */ + mr_list_init(&waiter->list); + waiter->event = event; + waiter->entry = entry; + waiter->param = param; + + /* Init object */ + return mr_object_init((mr_object_t *)waiter, class); +} + +mr_err_t mr_waiter_init(mr_waiter_t *waiter, mr_waiter_entry_t *entry, + void *param, mr_uint32_t event) { + /* Check parameter */ + MR_ASSERT((waiter != MR_NULL) && (!MR_OBJECT_IS_INITED(waiter))); + MR_ASSERT((entry != MR_NULL) && ((event & WAIT_TYPE_MASK) != 0)); + + /* Init waiter */ + return waiter_init(waiter, &__wait_clazz1, entry, param, event); +} + +mr_waiter_t *mr_waiter_create(mr_waiter_entry_t *entry, void *param, + mr_uint32_t event) { + mr_waiter_t *waiter; + mr_err_t ret; + + /* Check parameter */ + MR_ASSERT((entry != MR_NULL) && ((event & WAIT_TYPE_MASK) != 0)); + + /* Create waiter */ + waiter = mr_malloc(sizeof(mr_waiter_t)); + if (!waiter) { + return MR_NULL; + } + + /* Init waiter */ + ret = waiter_init(waiter, &__wait_clazz2, entry, param, event); + if (ret != 0) { + mr_free(waiter); + return MR_NULL; + } + return waiter; +} + +static void waiter_remove(mr_waiter_t *waiter) { + int mask; + + /* Lock */ + mask = mr_spinlock_lock_irqsave(&__lock); + + /* Remove waiter from waiting list */ + mr_list_del(&waiter->list); + + /* Unlock */ + mr_spinlock_unlock_irqrestore(&__lock, mask); +} + +mr_err_t mr_waiter_del(mr_waiter_t *waiter) { + /* Check parameter */ + MR_ASSERT((waiter != MR_NULL) && MR_OBJECT_IS_INITED(waiter)); + MR_ASSERT(MR_OBJECT_CLAZZ_IS_OR(waiter, &__wait_clazz1, &__wait_clazz2)); + + /* Remove waiter */ + waiter_remove(waiter); + + /* Delete object */ + mr_object_del((mr_object_t *)waiter); + return 0; +} + +mr_err_t mr_waiter_wait(mr_waiter_t *waiter, mr_waitable_t *waitable) { + mr_waiter_entry_t *entry; + mr_uint32_t event; + mr_err_t ret; + void *param; + int mask; + + /* Check parameter */ + MR_ASSERT((waiter != MR_NULL) && MR_OBJECT_IS_INITED(waiter)); + MR_ASSERT(MR_OBJECT_CLAZZ_IS_OR(waiter, &__wait_clazz1, &__wait_clazz2)); + MR_ASSERT((waitable != MR_NULL) && MR_OBJECT_IS_INITED(waitable)); + MR_ASSERT(MR_OBJECT_CLAZZ_IS_OR(waitable, &__able_clazz1, &__able_clazz2)); + + /* Lock */ + mask = mr_spinlock_lock_irqsave(&__lock); + + /* Check if waiter is waiting */ + if (MR_WAITER_IS_WAITING(waiter)) { + ret = -MR_EBUSY; + goto _exit; + } + + /* Add waiter to waitable waiting list */ + mr_list_add(&waitable->list, &waiter->list); + + /* Check if waiter is waiting for edge event */ + if (waiter->event & MR_WAIT_EDGE) { + /* Edge triggering is not related to the previous one */ + ret = 0; + goto _exit; + } + + /* Get waitable event */ + event = waitable_check(waitable); + if ((event & WAIT_TYPE_MASK) == 0) { + /* No waitable event(untyped events will be discarded) */ + ret = 0; + goto _exit; + } + + /* Check if waiter is triggered */ + if (!(waiter->event & event)) { + /* Not triggered */ + ret = 0; + goto _exit; + } + + /* Save waiter entry and param */ + entry = (mr_waiter_entry_t *)waiter->entry; + param = (void *)waiter->param; + + /* Unlock */ + mr_spinlock_unlock_irqrestore(&__lock, mask); + + /* Call waiter entry */ + entry(waiter, param, event); + return 0; +_exit: + /* Unlock */ + mr_spinlock_unlock_irqrestore(&__lock, mask); + return ret; +} + +mr_err_t mr_waiter_cancel(mr_waiter_t *waiter) { + /* Check parameter */ + MR_ASSERT((waiter != MR_NULL) && MR_OBJECT_IS_INITED(waiter)); + MR_ASSERT(MR_OBJECT_CLAZZ_IS_OR(waiter, &__wait_clazz1, &__wait_clazz2)); + + /* Remove waiter */ + waiter_remove(waiter); + return 0; +} + +static mr_waiter_t *wait_obj_release(mr_object_t *obj) { + mr_waiter_t *waiter; + + /* Get waiter */ + waiter = MR_CONTAINER_OF(obj, mr_waiter_t, parent); + + /* Remove waiter */ + waiter_remove(waiter); + return waiter; +} + +static void wait_obj_release1(mr_object_t *obj) { + /* Release waiter */ + wait_obj_release(obj); +} + +static void wait_obj_release2(mr_object_t *obj) { + mr_waiter_t *waiter; + + /* Release waiter */ + waiter = wait_obj_release(obj); + + /* Free waiter */ + mr_free(waiter); +} +#endif /* defined(MR_USE_WAIT) */