From 04694f6013bc38b3a320a3d6a08d44fc5645be56 Mon Sep 17 00:00:00 2001 From: SheldonDai Date: Thu, 10 Oct 2019 14:15:25 +0800 Subject: [PATCH] add countdownlatch and completion --- kernel/core/include/tos.h | 2 + kernel/core/include/tos_completion.h | 151 ++++++++++++++++++ kernel/core/include/tos_config_default.h | 26 ++++ kernel/core/include/tos_countdownlatch.h | 116 ++++++++++++++ kernel/core/include/tos_err.h | 4 + kernel/core/include/tos_ktypes.h | 1 + kernel/core/include/tos_mutex.h | 2 +- kernel/core/include/tos_pend.h | 16 +- kernel/core/tos_completion.c | 189 +++++++++++++++++++++++ kernel/core/tos_countdownlatch.c | 159 +++++++++++++++++++ kernel/core/tos_mutex.c | 35 ++--- kernel/core/tos_pend.c | 7 +- kernel/core/tos_sched.c | 3 +- kernel/core/tos_task.c | 7 +- kernel/core/tos_timer.c | 1 + 15 files changed, 688 insertions(+), 31 deletions(-) create mode 100644 kernel/core/include/tos_completion.h create mode 100644 kernel/core/include/tos_countdownlatch.h create mode 100644 kernel/core/tos_completion.c create mode 100644 kernel/core/tos_countdownlatch.c diff --git a/kernel/core/include/tos.h b/kernel/core/include/tos.h index d13b77a8..31e6fb25 100644 --- a/kernel/core/include/tos.h +++ b/kernel/core/include/tos.h @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/kernel/core/include/tos_completion.h b/kernel/core/include/tos_completion.h new file mode 100644 index 00000000..744e2974 --- /dev/null +++ b/kernel/core/include/tos_completion.h @@ -0,0 +1,151 @@ +/*---------------------------------------------------------------------------- + * Tencent is pleased to support the open source community by making TencentOS + * available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * If you have downloaded a copy of the TencentOS binary from Tencent, please + * note that the TencentOS binary is licensed under the BSD 3-Clause License. + * + * If you have downloaded a copy of the TencentOS source code from Tencent, + * please note that TencentOS source code is licensed under the BSD 3-Clause + * License, except for the third-party components listed below which are + * subject to different license terms. Your integration of TencentOS into your + * own projects may require compliance with the BSD 3-Clause License, as well + * as the other licenses applicable to the third-party components included + * within TencentOS. + *---------------------------------------------------------------------------*/ + +#ifndef _TOS_COMPLETION_H_ +#define _TOS_COMPLETION_H_ + +#if TOS_CFG_COMPLETION_EN > 0u + +typedef uint16_t completion_done_t; + +typedef struct k_completion_st { + pend_obj_t pend_obj; + completion_done_t done; +} k_completion_t; + +/** + * @brief Create a completion. + * create a completion. + * + * @attention None + * + * @param[in] completion pointer to the handler of the completion. + * + * @return errcode + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_completion_create(k_completion_t *completion); + +/** + * @brief Destroy a completion. + * destroy a completion. + * + * @attention None + * + * @param[in] completion pointer to the handler of the completion. + * + * @return errcode + * @retval #K_ERR_OBJ_INVALID completion is not a valid pointer to completion + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_completion_destroy(k_completion_t *completion); + +/** + * @brief Pend a completion. + * pend a completion. + * + * @attention None + * + * @param[in] completion pointer to the handler of the completion. + * @param[in] timeout how much time(in k_tick_t) we would like to wait. + * + * @return errcode + * @retval #K_ERR_PEND_NOWAIT we get nothing, and we don't wanna wait. + * @retval #K_ERR_PEND_SCHED_LOCKED we can wait, but scheduler is locked. + * @retval #K_ERR_PEND_TIMEOUT the time we wait is up, we get nothing. + * @retval #K_ERR_PEND_DESTROY the completion we are pending is destroyed. + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_completion_pend_timed(k_completion_t *completion, k_tick_t timeout); + +/** + * @brief Pend a completion. + * pend a completion. + * + * @attention None + * + * @param[in] completion pointer to the handler of the completion. + * @param[in] timeout how much time(in k_tick_t) we would like to wait. + * + * @return errcode + * @retval #K_ERR_PEND_NOWAIT we get nothing, and we don't wanna wait. + * @retval #K_ERR_PEND_SCHED_LOCKED we can wait, but scheduler is locked. + * @retval #K_ERR_PEND_TIMEOUT the time we wait is up, we get nothing. + * @retval #K_ERR_PEND_DESTROY the completion we are pending is destroyed. + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_completion_pend(k_completion_t *completion); + +/** + * @brief Post a completion. + * post a completion and wakeup one pending task. + * + * @attention when tos_completion_post return successfully, only one task who are waitting for the completion will be woken up. + * + * @param[in] completion pointer to the handler of the completion. + * + * @return errcode + * @retval #K_ERR_COMPLETION_OVERFLOW we are nesting post a completion too much. + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_completion_post(k_completion_t *completion); + +/** + * @brief Post a completion. + * post a completion and wakeup all the pending task. + * + * @attention when tos_completion_post_all return successfully, all of the tasks who are waitting for the completion will be woken up. + * + * @param[in] completion pointer to the handler of the completion. + * + * @return errcode + * @retval #K_ERR_COMPLETION_OVERFLOW we are nesting post a completion too much. + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_completion_post_all(k_completion_t *completion); + +/** + * @brief Reset a completion. + * reset a completion to un-done. + * + * @attention None. + * + * @param[in] completion pointer to the handler of the completion. + * + * @return errcode + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_completion_reset(k_completion_t *completion); + +/** + * @brief Test whether a completion is done. + * test whether a completion is done. + * + * @attention None + * + * @param[in] completion pointer to the handler of the completion. + * + * @return whether a completion is done + * @retval K_TRUE the completion is done. + * @retval K_FALSE the completion is not done. + */ +__API__ int tos_completion_is_done(k_completion_t *completion); + +#endif + +#endif + diff --git a/kernel/core/include/tos_config_default.h b/kernel/core/include/tos_config_default.h index d10b5b0a..5e035e2d 100644 --- a/kernel/core/include/tos_config_default.h +++ b/kernel/core/include/tos_config_default.h @@ -69,6 +69,24 @@ ///////////////////////////////////////// +///////////////////////////////////////// +// disable countdownlatch +#ifdef TOS_CFG_COUNTDOWNLATCH_EN +#undef TOS_CFG_COUNTDOWNLATCH_EN +#endif +#define TOS_CFG_COUNTDOWNLATCH_EN 0u +///////////////////////////////////////// + + +///////////////////////////////////////// +// disable completion +#ifdef TOS_CFG_COMPLETION_EN +#undef TOS_CFG_COMPLETION_EN +#endif +#define TOS_CFG_COMPLETION_EN 0u +///////////////////////////////////////// + + ///////////////////////////////////////// // disable the "traditional" timer #ifdef TOS_CFG_TIMER_EN @@ -172,6 +190,14 @@ #define TOS_CFG_SEM_EN 0u #endif +#ifndef TOS_CFG_COUNTDOWNLATCH_EN +#define TOS_CFG_COUNTDOWNLATCH_EN 0u +#endif + +#ifndef TOS_CFG_COMPLETION_EN +#define TOS_CFG_COMPLETION_EN 0u +#endif + #ifndef TOS_CFG_MMHEAP_EN #define TOS_CFG_MMHEAP_EN 0u #endif diff --git a/kernel/core/include/tos_countdownlatch.h b/kernel/core/include/tos_countdownlatch.h new file mode 100644 index 00000000..79b2d951 --- /dev/null +++ b/kernel/core/include/tos_countdownlatch.h @@ -0,0 +1,116 @@ +/*---------------------------------------------------------------------------- + * Tencent is pleased to support the open source community by making TencentOS + * available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * If you have downloaded a copy of the TencentOS binary from Tencent, please + * note that the TencentOS binary is licensed under the BSD 3-Clause License. + * + * If you have downloaded a copy of the TencentOS source code from Tencent, + * please note that TencentOS source code is licensed under the BSD 3-Clause + * License, except for the third-party components listed below which are + * subject to different license terms. Your integration of TencentOS into your + * own projects may require compliance with the BSD 3-Clause License, as well + * as the other licenses applicable to the third-party components included + * within TencentOS. + *---------------------------------------------------------------------------*/ + +#ifndef _TOS_COUNTDOWNLATCH_H_ +#define _TOS_COUNTDOWNLATCH_H_ + +#if TOS_CFG_COUNTDOWNLATCH_EN > 0u + +typedef struct k_countdownlatch_st { + pend_obj_t pend_obj; + k_countdownlatch_cnt_t count; +} k_countdownlatch_t; + +/** + * @brief Create a countdown-latch. + * create a countdown latch. + * + * @attention the count is how many posts have been done the pender would wakeup. + * + * @param[in] countdownlatch pointer to the handler of the countdown-latch. + * @param[in] count the count to wait of the countdown-latch. + * + * @return errcode + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_countdownlatch_create(k_countdownlatch_t *countdownlatch, k_countdownlatch_cnt_t count); + +/** + * @brief Destroy a countdown-latch. + * destroy a countdown-latch. + * + * @attention None + * + * @param[in] countdownlatch pointer to the handler of the countdown-latch. + * + * @return errcode + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_countdownlatch_destroy(k_countdownlatch_t *countdownlatch); + +/** + * @brief Pend a countdown-latch. + * pend a countdown-latch. + * + * @attention The task will keep blocked until the countdown-latch is obtained or a timeout comes. + * + * @param[in] countdownlatch pointer to the handler of the countdown-latch. + * @param[in] timeout how much time(in k_tick_t) we would like to wait. + * + * @return errcode + * @retval #K_ERR_PEND_NOWAIT we get nothing, and we don't wanna wait. + * @retval #K_ERR_PEND_SCHED_LOCKED we can wait, but scheduler is locked. + * @retval #K_ERR_PEND_TIMEOUT the time we wait is up, we get nothing. + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_countdownlatch_pend_timed(k_countdownlatch_t *countdownlatch, k_tick_t timeout); + +/** + * @brief Pend a countdown-latch. + * pend a countdown latch. + * + * @attention until (countdownlatch->count) of tasks have done the post, the pender would wake up. + * + * @param[in] countdownlatch pointer to the handler of the countdown-latch. + * + * @return errcode + * @retval #K_ERR_PEND_SCHED_LOCKED the schedule is locked. + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_countdownlatch_pend(k_countdownlatch_t *countdownlatch); + +/** + * @brief Post a countdown-latch. + * post a countdown-latch. + * + * @attention until (countdownlatch->count) of tasks have done the post, the pender would wake up. + * + * @param[in] countdownlatch pointer to the handler of the countdown-latch. + * + * @return errcode + * @retval #K_ERR_COUNTDOWNLATCH_OVERFLOW we are posting the countdown-latch too much. + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_countdownlatch_post(k_countdownlatch_t *countdownlatch); + +/** + * @brief Reset a countdown-latch. + * reset a countdown-latch's count. + * + * @attention None. + * + * @param[in] countdownlatch pointer to the handler of the countdown-latch. + * + * @return errcode + * @retval #K_ERR_NONE return successfully. + */ +__API__ k_err_t tos_countdownlatch_reset(k_countdownlatch_t *countdownlatch, k_countdownlatch_cnt_t count); + +#endif + +#endif + diff --git a/kernel/core/include/tos_err.h b/kernel/core/include/tos_err.h index 4d1122d3..47ff9352 100644 --- a/kernel/core/include/tos_err.h +++ b/kernel/core/include/tos_err.h @@ -21,6 +21,10 @@ typedef enum k_err_en { K_ERR_NONE = 0u, + K_ERR_COMPLETION_OVERFLOW = 25u, + + K_ERR_COUNTDOWNLATCH_OVERFLOW = 50u, + K_ERR_DELAY_ZERO = 100u, K_ERR_DELAY_FOREVER, diff --git a/kernel/core/include/tos_ktypes.h b/kernel/core/include/tos_ktypes.h index cf09ccc8..cc1d91d7 100644 --- a/kernel/core/include/tos_ktypes.h +++ b/kernel/core/include/tos_ktypes.h @@ -29,6 +29,7 @@ typedef uint8_t k_nesting_t; typedef uint16_t k_opt_t; typedef uint16_t k_sem_cnt_t; typedef uint32_t k_event_flag_t; +typedef uint16_t k_countdownlatch_cnt_t; typedef uint32_t k_time_t; typedef uint32_t k_timeslice_t; diff --git a/kernel/core/include/tos_mutex.h b/kernel/core/include/tos_mutex.h index c036d326..7a97adf9 100644 --- a/kernel/core/include/tos_mutex.h +++ b/kernel/core/include/tos_mutex.h @@ -25,7 +25,7 @@ typedef struct k_mutex_st { k_nesting_t pend_nesting; k_task_t *owner; k_prio_t owner_orig_prio; - k_list_t owner_list; + k_list_t owner_anchor; } k_mutex_t; /** diff --git a/kernel/core/include/tos_pend.h b/kernel/core/include/tos_pend.h index b387e197..98449fe9 100644 --- a/kernel/core/include/tos_pend.h +++ b/kernel/core/include/tos_pend.h @@ -37,11 +37,13 @@ typedef enum pend_state_en { is initialized, or whether user pass the correct parameter. */ typedef enum pend_type_en { - PEND_TYPE_NONE = 0x0000, - PEND_TYPE_SEM = 0x1BEE, - PEND_TYPE_MUTEX = 0x2BEE, - PEND_TYPE_EVENT = 0x3BEE, - PEND_TYPE_QUEUE = 0x4BEE, + PEND_TYPE_NONE = 0x0000, + PEND_TYPE_SEM = 0x1BEE, + PEND_TYPE_MUTEX = 0x2BEE, + PEND_TYPE_EVENT = 0x3BEE, + PEND_TYPE_QUEUE = 0x4BEE, + PEND_TYPE_COUNTDOWNLATCH = 0x5BEE, + PEND_TYPE_COMPLETION = 0x6BEE, } pend_type_t; typedef enum opt_post_en { @@ -62,7 +64,9 @@ __KERNEL__ int pend_object_verify(pend_obj_t *object, pend_type_t type); __KERNEL__ int pend_is_nopending(pend_obj_t *object); -__KERNEL__ k_prio_t pend_highest_prio_get(pend_obj_t *object); +__KERNEL__ k_prio_t pend_highest_pending_prio_get(pend_obj_t *object); + +__KERNEL__ k_task_t *pend_highest_pending_task_get(pend_obj_t *object); __KERNEL__ void pend_list_remove(k_task_t *task); diff --git a/kernel/core/tos_completion.c b/kernel/core/tos_completion.c new file mode 100644 index 00000000..2f100335 --- /dev/null +++ b/kernel/core/tos_completion.c @@ -0,0 +1,189 @@ +/*---------------------------------------------------------------------------- + * Tencent is pleased to support the open source community by making TencentOS + * available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * If you have downloaded a copy of the TencentOS binary from Tencent, please + * note that the TencentOS binary is licensed under the BSD 3-Clause License. + * + * If you have downloaded a copy of the TencentOS source code from Tencent, + * please note that TencentOS source code is licensed under the BSD 3-Clause + * License, except for the third-party components listed below which are + * subject to different license terms. Your integration of TencentOS into your + * own projects may require compliance with the BSD 3-Clause License, as well + * as the other licenses applicable to the third-party components included + * within TencentOS. + *---------------------------------------------------------------------------*/ + +#include "tos.h" + +#if TOS_CFG_COMPLETION_EN > 0u + +__API__ k_err_t tos_completion_create(k_completion_t *completion) +{ + TOS_PTR_SANITY_CHECK(completion); + + pend_object_init(&completion->pend_obj, PEND_TYPE_COMPLETION); + completion->done = (completion_done_t)0u; + + return K_ERR_NONE; +} + +__API__ k_err_t tos_completion_destroy(k_completion_t *completion) +{ + TOS_CPU_CPSR_ALLOC(); + + TOS_PTR_SANITY_CHECK(completion); + +#if TOS_CFG_OBJECT_VERIFY_EN > 0u + if (!pend_object_verify(&completion->pend_obj, PEND_TYPE_COMPLETION)) { + return K_ERR_OBJ_INVALID; + } +#endif + + TOS_CPU_INT_DISABLE(); + + if (!pend_is_nopending(&completion->pend_obj)) { + pend_wakeup_all(&completion->pend_obj, PEND_STATE_DESTROY); + } + + pend_object_deinit(&completion->pend_obj); + + TOS_CPU_INT_ENABLE(); + knl_sched(); + + return K_ERR_NONE; +} + +__API__ k_err_t tos_completion_pend_timed(k_completion_t *completion, k_tick_t timeout) +{ + TOS_CPU_CPSR_ALLOC(); + + TOS_PTR_SANITY_CHECK(completion); + +#if TOS_CFG_OBJECT_VERIFY_EN > 0u + if (!pend_object_verify(&completion->pend_obj, PEND_TYPE_COMPLETION)) { + return K_ERR_OBJ_INVALID; + } +#endif + + TOS_CPU_INT_DISABLE(); + + if (completion->done > (completion_done_t)0u) { + TOS_CPU_INT_ENABLE(); + return K_ERR_NONE; + } + + if (timeout == TOS_TIME_NOWAIT) { // no wait, return immediately + TOS_CPU_INT_ENABLE(); + return K_ERR_PEND_NOWAIT; + } + + if (knl_is_inirq()) { + TOS_CPU_INT_ENABLE(); + return K_ERR_PEND_IN_IRQ; + } + + if (knl_is_sched_locked()) { + TOS_CPU_INT_ENABLE(); + return K_ERR_PEND_SCHED_LOCKED; + } + + pend_task_block(k_curr_task, &completion->pend_obj, timeout); + + TOS_CPU_INT_ENABLE(); + knl_sched(); + + return pend_state2errno(k_curr_task->pend_state); +} + +__API__ k_err_t tos_completion_pend(k_completion_t *completion) +{ + return tos_completion_pend_timed(completion, TOS_TIME_FOREVER); +} + +__STATIC__ k_err_t completion_do_post(k_completion_t *completion, opt_post_t opt) +{ + TOS_CPU_CPSR_ALLOC(); + + TOS_PTR_SANITY_CHECK(completion); + +#if TOS_CFG_OBJECT_VERIFY_EN > 0u + if (!pend_object_verify(&completion->pend_obj, PEND_TYPE_COMPLETION)) { + return K_ERR_OBJ_INVALID; + } +#endif + + TOS_CPU_INT_DISABLE(); + + if (completion->done == (completion_done_t)-1) { + TOS_CPU_INT_ENABLE(); + return K_ERR_COMPLETION_OVERFLOW; + } + + ++completion->done; + + if (pend_is_nopending(&completion->pend_obj)) { + TOS_CPU_INT_ENABLE(); + return K_ERR_NONE; + } + + pend_wakeup(&completion->pend_obj, PEND_STATE_POST, opt); + + TOS_CPU_INT_ENABLE(); + knl_sched(); + + return K_ERR_NONE; +} + +__API__ k_err_t tos_completion_post(k_completion_t *completion) +{ + return completion_do_post(completion, OPT_POST_ONE); +} + +__API__ k_err_t tos_completion_post_all(k_completion_t *completion) +{ + return completion_do_post(completion, OPT_POST_ALL); +} + +__API__ k_err_t tos_completion_reset(k_completion_t *completion) +{ + TOS_CPU_CPSR_ALLOC(); + + TOS_PTR_SANITY_CHECK(completion); + +#if TOS_CFG_OBJECT_VERIFY_EN > 0u + if (!pend_object_verify(&completion->pend_obj, PEND_TYPE_COMPLETION)) { + return K_ERR_OBJ_INVALID; + } +#endif + + TOS_CPU_INT_DISABLE(); + completion->done = (completion_done_t)0u; + TOS_CPU_INT_ENABLE(); + + return K_ERR_NONE; +} + +__API__ int tos_completion_is_done(k_completion_t *completion) +{ + TOS_CPU_CPSR_ALLOC(); + int is_done = K_FALSE; + + TOS_PTR_SANITY_CHECK(completion); + +#if TOS_CFG_OBJECT_VERIFY_EN > 0u + if (!pend_object_verify(&completion->pend_obj, PEND_TYPE_COMPLETION)) { + return K_ERR_OBJ_INVALID; + } +#endif + + TOS_CPU_INT_DISABLE(); + is_done = (completion->done > (completion_done_t)0u ? K_TRUE : K_FALSE); + TOS_CPU_INT_ENABLE(); + + return is_done; +} + +#endif + diff --git a/kernel/core/tos_countdownlatch.c b/kernel/core/tos_countdownlatch.c new file mode 100644 index 00000000..9a772f8c --- /dev/null +++ b/kernel/core/tos_countdownlatch.c @@ -0,0 +1,159 @@ +/*---------------------------------------------------------------------------- + * Tencent is pleased to support the open source community by making TencentOS + * available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * If you have downloaded a copy of the TencentOS binary from Tencent, please + * note that the TencentOS binary is licensed under the BSD 3-Clause License. + * + * If you have downloaded a copy of the TencentOS source code from Tencent, + * please note that TencentOS source code is licensed under the BSD 3-Clause + * License, except for the third-party components listed below which are + * subject to different license terms. Your integration of TencentOS into your + * own projects may require compliance with the BSD 3-Clause License, as well + * as the other licenses applicable to the third-party components included + * within TencentOS. + *---------------------------------------------------------------------------*/ + +#include "tos.h" + +#if TOS_CFG_COUNTDOWNLATCH_EN > 0u + +__API__ k_err_t tos_countdownlatch_create(k_countdownlatch_t *countdownlatch, k_countdownlatch_cnt_t count) +{ + TOS_PTR_SANITY_CHECK(countdownlatch); + + pend_object_init(&countdownlatch->pend_obj, PEND_TYPE_COUNTDOWNLATCH); + countdownlatch->count = count; + + return K_ERR_NONE; +} + +__API__ k_err_t tos_countdownlatch_destroy(k_countdownlatch_t *countdownlatch) +{ + TOS_CPU_CPSR_ALLOC(); + + TOS_PTR_SANITY_CHECK(countdownlatch); + +#if TOS_CFG_OBJECT_VERIFY_EN > 0u + if (!pend_object_verify(&countdownlatch->pend_obj, PEND_TYPE_COUNTDOWNLATCH)) { + return K_ERR_OBJ_INVALID; + } +#endif + + TOS_CPU_INT_DISABLE(); + + if (!pend_is_nopending(&countdownlatch->pend_obj)) { + pend_wakeup_all(&countdownlatch->pend_obj, PEND_STATE_DESTROY); + } + + pend_object_deinit(&countdownlatch->pend_obj); + + TOS_CPU_INT_ENABLE(); + knl_sched(); + + return K_ERR_NONE; +} + +__API__ k_err_t tos_countdownlatch_pend_timed(k_countdownlatch_t *countdownlatch, k_tick_t timeout) +{ + TOS_CPU_CPSR_ALLOC(); + + TOS_PTR_SANITY_CHECK(countdownlatch); + +#if TOS_CFG_OBJECT_VERIFY_EN > 0u + if (!pend_object_verify(&countdownlatch->pend_obj, PEND_TYPE_COUNTDOWNLATCH)) { + return K_ERR_OBJ_INVALID; + } +#endif + + TOS_CPU_INT_DISABLE(); + + if (countdownlatch->count == (k_countdownlatch_cnt_t)0u) { + TOS_CPU_INT_ENABLE(); + return K_ERR_NONE; + } + + if (timeout == TOS_TIME_NOWAIT) { // no wait, return immediately + TOS_CPU_INT_ENABLE(); + return K_ERR_PEND_NOWAIT; + } + + if (knl_is_inirq()) { + TOS_CPU_INT_ENABLE(); + return K_ERR_PEND_IN_IRQ; + } + + if (knl_is_sched_locked()) { + TOS_CPU_INT_ENABLE(); + return K_ERR_PEND_SCHED_LOCKED; + } + + pend_task_block(k_curr_task, &countdownlatch->pend_obj, timeout); + + TOS_CPU_INT_ENABLE(); + knl_sched(); + + return pend_state2errno(k_curr_task->pend_state); +} + +__API__ k_err_t tos_countdownlatch_pend(k_countdownlatch_t *countdownlatch) +{ + return tos_countdownlatch_pend_timed(countdownlatch, TOS_TIME_FOREVER); +} + +__API__ k_err_t tos_countdownlatch_post(k_countdownlatch_t *countdownlatch) +{ + TOS_CPU_CPSR_ALLOC(); + + TOS_PTR_SANITY_CHECK(countdownlatch); + +#if TOS_CFG_OBJECT_VERIFY_EN > 0u + if (!pend_object_verify(&countdownlatch->pend_obj, PEND_TYPE_COUNTDOWNLATCH)) { + return K_ERR_OBJ_INVALID; + } +#endif + + TOS_CPU_INT_DISABLE(); + + if (countdownlatch->count == (k_countdownlatch_cnt_t)0) { + TOS_CPU_INT_ENABLE(); + return K_ERR_COUNTDOWNLATCH_OVERFLOW; + } + + --countdownlatch->count; + + if (countdownlatch->count > (k_countdownlatch_cnt_t)0) { + TOS_CPU_INT_ENABLE(); + return K_ERR_NONE; + } + + pend_wakeup_one(&countdownlatch->pend_obj, PEND_STATE_POST); + + TOS_CPU_INT_ENABLE(); + knl_sched(); + + return K_ERR_NONE; +} + +__API__ k_err_t tos_countdownlatch_reset(k_countdownlatch_t *countdownlatch, k_countdownlatch_cnt_t count) +{ + TOS_CPU_CPSR_ALLOC(); + + TOS_PTR_SANITY_CHECK(countdownlatch); + +#if TOS_CFG_OBJECT_VERIFY_EN > 0u + if (!pend_object_verify(&countdownlatch->pend_obj, PEND_TYPE_COUNTDOWNLATCH)) { + return K_ERR_OBJ_INVALID; + } +#endif + + TOS_CPU_INT_DISABLE(); + countdownlatch->count = count; + TOS_CPU_INT_ENABLE(); + + return K_ERR_NONE; +} + +#endif + diff --git a/kernel/core/tos_mutex.c b/kernel/core/tos_mutex.c index ac7c52b2..e1d31c8a 100644 --- a/kernel/core/tos_mutex.c +++ b/kernel/core/tos_mutex.c @@ -25,8 +25,9 @@ __STATIC_INLINE__ void mutex_old_owner_release(k_mutex_t *mutex) owner = mutex->owner; - tos_list_del(&mutex->owner_list); - mutex->owner = K_NULL; + tos_list_del(&mutex->owner_anchor); + mutex->owner = K_NULL; + mutex->pend_nesting = (k_nesting_t)0u; // the right time comes! let's do it! if (owner->prio_pending != K_TASK_PRIO_INVALID) { @@ -40,11 +41,11 @@ __STATIC_INLINE__ void mutex_old_owner_release(k_mutex_t *mutex) __STATIC_INLINE__ void mutex_fresh_owner_mark(k_mutex_t *mutex, k_task_t *task) { - mutex->pend_nesting = (k_nesting_t)1u; mutex->owner = task; mutex->owner_orig_prio = task->prio; + mutex->pend_nesting = (k_nesting_t)1u; - tos_list_add(&mutex->owner_list, &task->mutex_own_list); + tos_list_add(&mutex->owner_anchor, &task->mutex_own_list); } __STATIC_INLINE__ void mutex_new_owner_mark(k_mutex_t *mutex, k_task_t *task) @@ -54,7 +55,7 @@ __STATIC_INLINE__ void mutex_new_owner_mark(k_mutex_t *mutex, k_task_t *task) mutex_fresh_owner_mark(mutex, task); // we own the mutex now, make sure our priority is higher than any one in the pend list. - highest_pending_prio = pend_highest_prio_get(&mutex->pend_obj); + highest_pending_prio = pend_highest_pending_prio_get(&mutex->pend_obj); if (task->prio > highest_pending_prio) { tos_task_prio_change(task, highest_pending_prio); } @@ -76,7 +77,7 @@ __API__ k_err_t tos_mutex_create(k_mutex_t *mutex) mutex->pend_nesting = (k_nesting_t)0u; mutex->owner = K_NULL; mutex->owner_orig_prio = K_TASK_PRIO_INVALID; - tos_list_init(&mutex->owner_list); + tos_list_init(&mutex->owner_anchor); return K_ERR_NONE; } @@ -101,7 +102,6 @@ __API__ k_err_t tos_mutex_destroy(k_mutex_t *mutex) } pend_object_deinit(&mutex->pend_obj); - mutex->pend_nesting = (k_nesting_t)0u; if (mutex->owner) { mutex_old_owner_release(mutex); @@ -116,7 +116,6 @@ __API__ k_err_t tos_mutex_destroy(k_mutex_t *mutex) __API__ k_err_t tos_mutex_pend_timed(k_mutex_t *mutex, k_tick_t timeout) { TOS_CPU_CPSR_ALLOC(); - k_err_t err; TOS_PTR_SANITY_CHECK(mutex); TOS_IN_IRQ_CHECK(); @@ -166,16 +165,7 @@ __API__ k_err_t tos_mutex_pend_timed(k_mutex_t *mutex, k_tick_t timeout) TOS_CPU_INT_ENABLE(); knl_sched(); - err = pend_state2errno(k_curr_task->pend_state); - - if (err == K_ERR_NONE) { - // good, we are the owner now. - TOS_CPU_INT_DISABLE(); - mutex_new_owner_mark(mutex, k_curr_task); - TOS_CPU_INT_ENABLE(); - } - - return err; + return pend_state2errno(k_curr_task->pend_state); } __API__ k_err_t tos_mutex_pend(k_mutex_t *mutex) @@ -186,6 +176,7 @@ __API__ k_err_t tos_mutex_pend(k_mutex_t *mutex) __API__ k_err_t tos_mutex_post(k_mutex_t *mutex) { TOS_CPU_CPSR_ALLOC(); + k_task_t *pending_task; TOS_PTR_SANITY_CHECK(mutex); TOS_IN_IRQ_CHECK(); @@ -215,6 +206,14 @@ __API__ k_err_t tos_mutex_post(k_mutex_t *mutex) return K_ERR_NONE; } + /* must do the mutex owner switch right here + if the pender don't get a chance to schedule, the poster(old owner) may obtain the mutex immediately again + but the pender already get ready(already in the critical section). + we switch the owner right here to avoid the old owner obtain the mutex again + */ + pending_task = pend_highest_pending_task_get(&mutex->pend_obj); + mutex_new_owner_mark(mutex, pending_task); + pend_wakeup_one(&mutex->pend_obj, PEND_STATE_POST); TOS_CPU_INT_ENABLE(); knl_sched(); diff --git a/kernel/core/tos_pend.c b/kernel/core/tos_pend.c index 1f021d38..2fc619d7 100644 --- a/kernel/core/tos_pend.c +++ b/kernel/core/tos_pend.c @@ -39,7 +39,7 @@ __STATIC__ void pend_list_add(k_task_t *task, pend_obj_t *pend_obj) task_state_set_pend(task); } -__KERNEL__ k_prio_t pend_highest_prio_get(pend_obj_t *object) +__KERNEL__ k_prio_t pend_highest_pending_prio_get(pend_obj_t *object) { k_task_t *task; @@ -48,6 +48,11 @@ __KERNEL__ k_prio_t pend_highest_prio_get(pend_obj_t *object) return task ? task->prio : K_TASK_PRIO_INVALID; } +__KERNEL__ k_task_t *pend_highest_pending_task_get(pend_obj_t *object) +{ + return TOS_LIST_FIRST_ENTRY(&object->list, k_task_t, pend_list); +} + __KERNEL__ void pend_list_remove(k_task_t *task) { tos_list_del(&task->pend_list); diff --git a/kernel/core/tos_sched.c b/kernel/core/tos_sched.c index 8dd44fc3..76cf4aee 100644 --- a/kernel/core/tos_sched.c +++ b/kernel/core/tos_sched.c @@ -78,8 +78,7 @@ __KERNEL__ k_task_t *readyqueue_highest_ready_task_get(void) k_list_t *task_list; task_list = &k_rdyq.task_list_head[k_rdyq.highest_prio]; - k_task_t *fuck = TOS_LIST_FIRST_ENTRY(task_list, k_task_t, pend_list); - return fuck; + return TOS_LIST_FIRST_ENTRY(task_list, k_task_t, pend_list); } __KERNEL__ void readyqueue_init(void) diff --git a/kernel/core/tos_task.c b/kernel/core/tos_task.c index 18abede0..e54dcecf 100644 --- a/kernel/core/tos_task.c +++ b/kernel/core/tos_task.c @@ -53,8 +53,8 @@ __STATIC__ k_prio_t task_highest_pending_prio_get(k_task_t *task) k_prio_t prio, highest_prio_pending = K_TASK_PRIO_INVALID; TOS_LIST_FOR_EACH(curr, &task->mutex_own_list) { - mutex = TOS_LIST_ENTRY(curr, k_mutex_t, owner_list); - prio = pend_highest_prio_get(&mutex->pend_obj); + mutex = TOS_LIST_ENTRY(curr, k_mutex_t, owner_anchor); + prio = pend_highest_pending_prio_get(&mutex->pend_obj); if (prio < highest_prio_pending) { highest_prio_pending = prio; } @@ -67,7 +67,7 @@ __STATIC__ void task_mutex_release(k_task_t *task) k_list_t *curr, *next; TOS_LIST_FOR_EACH_SAFE(curr, next, &task->mutex_own_list) { - mutex_release(TOS_LIST_ENTRY(curr, k_mutex_t, owner_list)); + mutex_release(TOS_LIST_ENTRY(curr, k_mutex_t, owner_anchor)); } } #endif @@ -358,6 +358,7 @@ __API__ k_err_t tos_task_delay(k_tick_t delay) if (tick_list_add(k_curr_task, delay) != K_ERR_NONE) { TOS_CPU_INT_ENABLE(); + // if you wanna delay your task forever, why don't just suspend? return K_ERR_DELAY_FOREVER; } diff --git a/kernel/core/tos_timer.c b/kernel/core/tos_timer.c index c0cb77b0..9d260564 100644 --- a/kernel/core/tos_timer.c +++ b/kernel/core/tos_timer.c @@ -113,6 +113,7 @@ __API__ k_err_t tos_timer_create(k_timer_t *tmr, } if (opt == TOS_OPT_TIMER_ONESHOT && delay == (k_tick_t)0u) { + // if you create a oneshot timer and delay 0 to trigger, why don't just call the timer_callback? return K_ERR_TIMER_INVALID_DELAY; }