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).
This commit is contained in:
MacRsh
2025-07-22 21:08:32 +08:00
parent e4e822295d
commit 8a8231d182
6 changed files with 572 additions and 9 deletions

View File

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

View File

@@ -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) */

158
include/mr-X/mr_wait.h Normal file
View File

@@ -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 <mr_config.h>
#if defined(MR_USE_WAIT)
#include <mr-X/mr_object.h>
#include <mr-X/mr_list.h>
#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__ */

View File

@@ -29,6 +29,7 @@
#include <mr-X/mr_spinlock.h>
#include <mr-X/mr_timer.h>
#include <mr-X/mr_version.h>
#include <mr-X/mr_wait.h>
#include <mr-X/mr_workqueue.h>
/** @} */

View File

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

397
kernel/wait.c Normal file
View File

@@ -0,0 +1,397 @@
/**
* @copyright (c) 2024-2025, MacRsh
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2024-09-06 MacRsh First version
*/
#include <mr-X/mr_wait.h>
#if defined(MR_USE_WAIT)
#include <mr-X/mr_spinlock.h>
#include <libc/mr_malloc.h>
/* 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) */