os_task.c
2026/7/19大约 14 分钟附录源码附录
os_task.c
路径: kernel\source\os_task.c
/**
***********************************************************************************************************************
* Copyright (c) 2020, China Mobile Communications Group Co.,Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @file os_task.c
*
* @brief This file implements the task functions.
*
* @revision
* Date Author Notes
* 2020-04-06 OneOS team First Version
* 2020-11-10 OneOS team Refactor task implementation.
***********************************************************************************************************************
*/
#include <oneos_config.h>
#include <os_types.h>
#include <os_stddef.h>
#include <os_assert.h>
#include <arch_interrupt.h>
#include <os_errno.h>
#include <os_clock.h>
#include <string.h>
#include <os_spinlock.h>
#include <arch_misc.h>
#include <arch_exception.h>
#include <os_safety.h>
#include "os_kernel_internal.h"
#define TASK_TAG "TASK"
/* The stack and control block of recycle-task */
static OS_TASK_STACK_DEFINE(gs_os_recycle_task_stack, OS_RECYCLE_TASK_STACK_SIZE);
static os_task_t gs_os_recycle_task;
static os_list_node_t gs_os_task_resource_list_head = OS_LIST_INIT(gs_os_task_resource_list_head);
static OS_DEFINE_SPINLOCK(gs_os_task_resource_list_lock);
static os_list_node_t gs_os_task_recycle_list_head = OS_LIST_INIT(gs_os_task_recycle_list_head);
/* When in interrupt context or when scheduler is not started, it is used to record the error code */
static os_err_t gs_os_err_code = OS_SUCCESS;
#ifdef OS_USING_TASK_HOOK
os_task_switch_hook_t gs_os_task_switch_hook;
/**
***********************************************************************************************************************
* @brief This function add a hook function called at the between two task switch.
*
* @param[in] hook The hook function is complemented by user.
*
* @return Whether to add the hook function successfully.
* @retval OS_TRUE Add the hook function successfully.
* @retval OS_FALSE There is no remaining space to add hook functions.
***********************************************************************************************************************
*/
os_bool_t os_task_switch_hook_add(os_task_switch_hook_t hook)
{
if (OS_NULL == gs_os_task_switch_hook)
{
gs_os_task_switch_hook = hook;
return OS_TRUE;
}
else
{
return OS_FALSE;
}
}
/**
***********************************************************************************************************************
* @brief This function delete a hook function called at the between two task switch.
*
* @param[in] hook The hook function is complemented by user.
*
* @return Whether to delete the hook function successfully.
* @retval OS_TRUE Delete the hook function successfully.
* @retval OS_FALSE This hook function was not found.
***********************************************************************************************************************
*/
os_bool_t os_task_switch_hook_delete(os_task_switch_hook_t hook)
{
if (hook == gs_os_task_switch_hook)
{
gs_os_task_switch_hook = OS_NULL;
return OS_TRUE;
}
else
{
return OS_FALSE;
}
}
#endif /* OS_USING_TASK_HOOK */
#ifdef OS_USING_OVERFLOW_CHECK
static void _k_task_stack_check(const os_task_t *from_task, const os_task_t *to_task)
{
os_bool_t is_overflow;
OS_ASSERT((OS_NULL != from_task));
OS_ASSERT((OS_NULL != to_task));
is_overflow = os_task_stack_is_overflow(from_task->stack_top, from_task->stack_begin, from_task->stack_end);
if (OS_TRUE == is_overflow)
{
OS_KERN_LOG(KERN_ERROR,
TASK_TAG,
"Stack overflow, switch from task(%s), sp is 0x%p stack_begin is %p stack_end is %p.\r\n",
from_task->name,
from_task->stack_top,
from_task->stack_begin,
from_task->stack_end);
os_safety_task_stack_overflow_process();
}
is_overflow = os_task_stack_is_overflow(to_task->stack_top, to_task->stack_begin, to_task->stack_end);
if (OS_TRUE == is_overflow)
{
OS_KERN_LOG(KERN_ERROR,
TASK_TAG,
"Stack overflow, switch to task(%s), sp is 0x%p stack_begin is %p stack_end is %p.\r\n",
to_task->name,
to_task->stack_top,
to_task->stack_begin,
to_task->stack_end);
os_safety_task_stack_overflow_process();
}
return;
}
#endif /* OS_USING_OVERFLOW_CHECK */
/*
* If define OS_USING_OVERFLOW_CHECK or OS_USING_TASK_HOOK, OS_TASK_SWITCH_NOTIFY is defined
* in gcc(-DOS_TASK_SWITCH_NOTIFY).
*/
#ifdef OS_TASK_SWITCH_NOTIFY
/**
***********************************************************************************************************************
* @brief This function is called at the between two task switch.
*
* @param None.
*
* @return None
***********************************************************************************************************************
*/
void os_task_switch_notify(void)
{
os_task_t *current_task;
os_task_t *next_task;
#ifdef OS_USING_SMP
int32_t current_cpu_index;
current_cpu_index = os_cpu_id_get();
current_task = g_os_current_task[current_cpu_index];
next_task = g_os_next_task[current_cpu_index];
#else
current_task = g_os_current_task;
next_task = g_os_next_task;
#endif
#ifdef OS_USING_OVERFLOW_CHECK
_k_task_stack_check(current_task, next_task);
#endif
#ifdef OS_USING_SMP
OS_TASK_HOOK_CALL(
gs_os_task_switch_hook,
(OS_TYPE_CONVERT(os_task_id, current_task), OS_TYPE_CONVERT(os_task_id, next_task), current_cpu_index));
#else
OS_TASK_HOOK_CALL(gs_os_task_switch_hook,
(OS_TYPE_CONVERT(os_task_id, current_task), OS_TYPE_CONVERT(os_task_id, next_task)));
#endif
}
#endif /* OS_TASK_SWITCH_NOTIFY */
static void _k_recycle_task_entry(void *arg)
{
os_task_t *iter_task;
os_task_t *current_task;
uint8_t object_alloc_type;
OS_KERNEL_INIT();
OS_UNREFERENCE(arg);
while (1)
{
OS_KERNEL_ENTER();
iter_task = OS_NULL;
while (1)
{
if (os_list_empty(&gs_os_task_recycle_list_head))
{
break;
}
iter_task = os_list_first_entry(&gs_os_task_recycle_list_head, os_task_t, resource_node);
os_list_del(&iter_task->resource_node);
OS_KERNEL_EXIT();
OS_KERN_LOG(KERN_INFO, TASK_TAG, "Recycle task(%s)", iter_task->name);
/*
* iter_task memory maybe in user_data, in this case, iter_task memory will be freed at cleanup function.
* So, object_alloc_type of iter_task is stored at the temporary variable, avoiding illegal memory access.
*
* In addition, if iter_task memory is in user_data, the variabe object_alloc_type of iter_task can't be
* OS_KOBJ_ALLOC_TYPE_DYNAMIC. Otherwise, there is a bug.
*/
object_alloc_type = iter_task->object_alloc_type;
if (OS_NULL != iter_task->cleanup)
{
iter_task->cleanup(iter_task->user_data);
}
#ifdef OS_USING_HEAP
if (OS_KDATA_ALLOC_TYPE_DYNAMIC == (object_alloc_type & OS_KDATA_ALLOC_TYPE_DYNAMIC))
{
OS_KERNEL_FREE(iter_task->stack_begin);
}
if (OS_KOBJ_ALLOC_TYPE_DYNAMIC == (object_alloc_type & OS_KOBJ_ALLOC_TYPE_DYNAMIC))
{
OS_KERNEL_FREE(iter_task);
}
#endif
OS_KERNEL_ENTER();
}
/* Suspend myself */
current_task = _k_task_self();
k_readyq_remove(current_task);
current_task->state &= ~OS_TASK_STATE_READY;
current_task->state |= OS_TASK_STATE_SUSPEND;
OS_KERNEL_EXIT_SCHED();
}
}
void k_recycle_task_init(void)
{
os_err_t ret;
os_task_id tid;
tid = os_task_create((os_task_dummy_t *)&gs_os_recycle_task,
OS_TASK_STACK_BEGIN_ADDR(gs_os_recycle_task_stack),
OS_RECYCLE_TASK_STACK_SIZE,
OS_RECYCLE_TASK_NAME,
_k_recycle_task_entry,
OS_NULL,
0U);
OS_ASSERT_EX((tid != OS_NULL), "Why initialize recycle task failed?");
ret = os_task_startup(tid);
#ifdef OS_USING_ASSERT
OS_ASSERT_EX((OS_SUCCESS == ret), "Why startup recycle task failed?");
#else
OS_UNREFERENCE(ret);
#endif
return;
}
static void _k_wakeup_recycle_task(void)
{
if (OS_TASK_STATE_SUSPEND == gs_os_recycle_task.state)
{
gs_os_recycle_task.state &= ~OS_TASK_STATE_SUSPEND;
gs_os_recycle_task.state |= OS_TASK_STATE_READY;
k_readyq_put(&gs_os_recycle_task);
}
return;
}
void k_task_exit(void)
{
os_task_t *current_task;
OS_KERNEL_INIT();
current_task = k_task_self();
os_spin_lock(&gs_os_task_resource_list_lock);
os_list_del(¤t_task->resource_node);
os_spin_unlock(&gs_os_task_resource_list_lock);
OS_KERNEL_ENTER();
current_task->object_inited = OS_KOBJ_DEINITED;
k_readyq_remove(current_task);
current_task->state &= ~OS_TASK_STATE_READY;
current_task->state |= OS_TASK_STATE_CLOSE;
#ifndef OS_USING_SMP
if ((OS_KDATA_ALLOC_TYPE_DYNAMIC == (current_task->object_alloc_type & OS_KDATA_ALLOC_TYPE_DYNAMIC)) ||
(OS_KOBJ_ALLOC_TYPE_DYNAMIC == (current_task->object_alloc_type & OS_KOBJ_ALLOC_TYPE_DYNAMIC)) ||
(OS_NULL != current_task->cleanup))
{
os_list_add_tail(&gs_os_task_recycle_list_head, ¤t_task->resource_node);
_k_wakeup_recycle_task();
}
#endif
OS_KERNEL_EXIT_SCHED();
return;
}
static void _k_task_init(os_task_t *task,
const char *name,
void (*entry)(void *arg),
void *arg,
void *stack_begin,
uint32_t stack_size,
uint8_t priority,
uint8_t object_alloc_type)
{
if (OS_NULL != name)
{
(void)strncpy(task->name, name, OS_NAME_MAX);
task->name[OS_NAME_MAX] = '\0';
}
else
{
task->name[0] = '\0';
}
task->object_alloc_type = object_alloc_type;
task->err_code = OS_SUCCESS;
task->switch_retval = OS_SUCCESS;
task->backup_priority = priority;
task->current_priority = priority;
task->time_slice = OS_SCHEDULE_TIME_SLICE;
task->remaining_time_slice = OS_SCHEDULE_TIME_SLICE;
task->user_data = OS_NULL;
task->block_list_head = OS_NULL;
task->stack_begin = stack_begin;
task->stack_end = (void *)((uint8_t *)stack_begin + stack_size);
task->stack_top = os_hw_stack_init(entry, arg, stack_begin, stack_size, k_task_exit);
os_list_init(&task->task_node);
os_list_init(&task->tick_node);
#ifdef OS_USING_MUTEX
os_list_init(&task->hold_mutex_list_head);
#endif
#ifdef OS_USING_EVENT
task->event_set = 0U;
task->event_option = 0U;
#endif
task->swap_data = 0U;
task->cleanup = OS_NULL;
task->user_data = OS_NULL;
#ifdef OS_USING_CPU_MONITOR
task->usage_info.start_time = 0;
task->usage_info.total_time = 0;
#endif
#ifdef OS_USING_SMP
os_list_init(&task->join_node);
task->cpu_index = -1;
task->cpu_affinity = -1;
#endif
return;
}
static void _k_task_deinit(os_task_t *task)
{
/* Task is at ready queue */
if ((task->state & OS_TASK_STATE_READY) != 0)
{
k_readyq_remove(task);
task->state &= ~OS_TASK_STATE_READY;
}
/* Task is not at ready queue */
else
{
/* Task is sleep state */
if ((task->state & OS_TASK_STATE_SLEEP) != 0)
{
k_tickq_remove(task);
task->state &= ~OS_TASK_STATE_SLEEP;
}
/* Task is block state */
if ((task->state & OS_TASK_STATE_BLOCK) != 0)
{
/* Remove from ipc list head */
os_list_del(&task->task_node);
task->state &= ~OS_TASK_STATE_BLOCK;
}
if ((task->state & OS_TASK_STATE_INIT) != 0)
{
task->state &= ~OS_TASK_STATE_INIT;
}
if ((task->state & OS_TASK_STATE_SUSPEND) != 0)
{
task->state &= ~OS_TASK_STATE_SUSPEND;
}
/* Here, if task is running state, do nothing. */
}
return;
}
#ifdef OS_USING_SMP
/**
***********************************************************************************************************************
* @brief Close a task.
*
* @details When deinitializing or destroying a running task, this function needs to be called
* at the exit scheduling point.
*
* @param[in] task Task control block.
*
* @return None
***********************************************************************************************************************
*/
void _k_task_close(os_task_t *task)
{
os_task_t *iter_task;
/* The destroyed/deinited task was preparing to block when it was destroyed/deinited.*/
if ((task->state & OS_TASK_STATE_BLOCK) != 0)
{
/* Remove from ipc list head */
os_list_del(&task->task_node);
task->state &= ~OS_TASK_STATE_BLOCK;
}
if ((task->state & OS_TASK_STATE_SLEEP) != 0)
{
k_tickq_remove(task);
task->state &= ~OS_TASK_STATE_SLEEP;
}
if ((task->state & OS_TASK_STATE_READY) != 0)
{
task->state &= ~OS_TASK_STATE_READY;
}
if ((task->state & OS_TASK_STATE_SUSPEND) != 0)
{
task->state &= ~OS_TASK_STATE_SUSPEND;
}
if (((OS_ALLOC_TYPE_STATIC != task->object_alloc_type) || (OS_NULL != task->cleanup)) != 0)
{
os_list_add_tail(&gs_os_task_recycle_list_head, &task->resource_node);
_k_wakeup_recycle_task();
}
/* delete join node */
while (!os_list_empty(&task->join_node))
{
iter_task = os_list_first_entry(&task->join_node, os_task_t, task_node);
os_list_del(&iter_task->task_node);
iter_task->state &= ~OS_TASK_STATE_BLOCK;
/* The task state may be suspend, empty. */
if (OS_TASK_STATE_SUSPEND != iter_task->state)
{
iter_task->state |= OS_TASK_STATE_READY;
k_readyq_put(iter_task);
}
}
}
#endif
/**
***********************************************************************************************************************
* @brief This function creates a task with dynamic memory allocation.
*
* @details Both control block and stack of the task are allocated in memory heap.
*
* @attention This interface is not allowed in the following cases:
* 1. In interrupt context.
* 2. Interrupt is disabled.
* 3. Scheduler is locked.
*
* @param[in] task_cb The pointer of task control block.
* @param[in] stack_begin The beginning address of stack memory.
* @param[in] stack_size Stack size in bytes.
* @param[in] name Task name.
* @param[in] entry Entry function of the task.
* @param[in] arg Argument of entry function.
* @param[in] priority Priority of task.
*
* @return The ID of task.
* @retval The ID of task.
***********************************************************************************************************************
*/
/* clang-format off */
os_task_id os_task_create(os_task_dummy_t *task_cb,
void *stack_begin,
uint32_t stack_size,
const char *name,
void (*entry)(void *arg),
void *arg,
uint8_t priority)
{
os_task_t *task;
uint8_t object_alloc_type;
os_task_t *iter_task;
os_list_node_t *pos;
os_bool_t exist;
OS_ASSERT(OS_NULL != entry);
OS_ASSERT(stack_size > 0);
OS_ASSERT(priority < OS_TASK_PRIORITY_MAX);
OS_ASSERT(OS_FALSE == os_is_irq_active());
#ifndef OS_USING_HEAP
OS_ASSERT(OS_NULL != stack_begin);
OS_ASSERT(OS_NULL != task_cb);
#endif
object_alloc_type = 0;
#ifdef OS_USING_HEAP
if (OS_NULL == task_cb)
{
task = (os_task_t *)OS_KERNEL_MALLOC(sizeof(os_task_t));
object_alloc_type |= OS_KOBJ_ALLOC_TYPE_DYNAMIC;
}
else
#endif
{
task = OS_TYPE_CONVERT(os_task_t *, task_cb);
}
#ifdef OS_USING_HEAP
if (OS_NULL == stack_begin)
{
stack_size = OS_ALIGN_UP(stack_size, OS_ARCH_STACK_ALIGN_SIZE);
stack_begin = OS_KERNEL_MALLOC_ALIGN(OS_ARCH_STACK_ALIGN_SIZE, stack_size);
object_alloc_type |= OS_KDATA_ALLOC_TYPE_DYNAMIC;
}
if ((OS_NULL == stack_begin) || (OS_NULL == task))
{
OS_KERN_LOG(KERN_ERROR, TASK_TAG, "Malloc failed, stack_begin(%p), task(%p)", stack_begin, task);
if (OS_KOBJ_ALLOC_TYPE_DYNAMIC == (object_alloc_type & OS_KOBJ_ALLOC_TYPE_DYNAMIC))
{
if (OS_NULL != task)
{
OS_KERNEL_FREE(task);
}
}
/* If the space malloc fails, the return task must be NULL. */
task = OS_NULL;
if (OS_KDATA_ALLOC_TYPE_DYNAMIC == (object_alloc_type & OS_KDATA_ALLOC_TYPE_DYNAMIC))
{
if (OS_NULL != stack_begin)
{
OS_KERNEL_FREE(stack_begin);
stack_begin = OS_NULL;
}
}
}
else
#endif
{
exist = OS_FALSE;
os_spin_lock(&gs_os_task_resource_list_lock);
if (0 == (object_alloc_type & OS_KOBJ_ALLOC_TYPE_DYNAMIC))
{
os_list_for_each(pos, &gs_os_task_resource_list_head)
{
iter_task = os_list_entry(pos, os_task_t, resource_node);
if (iter_task == task)
{
task = OS_NULL;
OS_KERN_LOG(KERN_ERROR, TASK_TAG, "The task(addr: 0x%p, name: %s) has been exist",
iter_task,
iter_task->name);
exist = OS_TRUE;
break;
}
}
}
if (OS_FALSE == exist)
{
os_list_add_tail(&gs_os_task_resource_list_head, &task->resource_node);
os_spin_unlock(&gs_os_task_resource_list_lock);
_k_task_init(task, name, entry, arg, stack_begin, stack_size, priority, object_alloc_type);
task->state = OS_TASK_STATE_INIT;
task->object_inited = OS_KOBJ_INITED;
}
else
{
os_spin_unlock(&gs_os_task_resource_list_lock);
#ifdef OS_USING_HEAP
if (OS_KDATA_ALLOC_TYPE_DYNAMIC == (object_alloc_type & OS_KDATA_ALLOC_TYPE_DYNAMIC))
{
OS_KERNEL_FREE(stack_begin);
stack_begin = OS_NULL;
}
#endif
}
}
return OS_TYPE_CONVERT(os_task_id, task);
}
/* clang-format on */
/**
***********************************************************************************************************************
* @brief Destroy a task.
*
* @details If the task to be destroyed is the current task, the resource will be recycled in recycle-task.
*
* @attention This interface is not allowed in the following cases:
* 1. In interrupt context.
*
* @param[in] tid The ID of task control block.
*
* @return The result of destroying the task.
* @retval OS_SUCCESS Destroy the task successfully.
* @retval else Destroy the task failed.
***********************************************************************************************************************
*/
os_err_t os_task_destroy(os_task_id tid)
{
os_task_t *current_task;
os_bool_t need_sched;
os_bool_t task_hold_mutex;
os_err_t ret;
os_task_t *task;
uint8_t object_alloc_type;
OS_KERNEL_INIT();
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(OS_NULL != task);
OS_ASSERT(OS_KOBJ_INITED == task->object_inited);
OS_ASSERT((task->state & OS_TASK_STATE_CLOSE) == OS_TASK_STATE_EMPTY);
OS_ASSERT(OS_FALSE == os_is_irq_active());
#ifndef OS_USING_HEAP
OS_ASSERT(OS_ALLOC_TYPE_STATIC == (task->object_alloc_type & OS_KDATA_ALLOC_TYPE_DYNAMIC));
OS_ASSERT(OS_ALLOC_TYPE_STATIC == (task->object_alloc_type & OS_KOBJ_ALLOC_TYPE_DYNAMIC));
#endif
need_sched = OS_FALSE;
ret = OS_SUCCESS;
OS_KERNEL_ENTER();
#if defined(OS_USING_MUTEX)
task_hold_mutex = !os_list_empty(&task->hold_mutex_list_head);
#else
task_hold_mutex = OS_FALSE;
#endif
if (OS_TRUE == task_hold_mutex)
{
ret = OS_BUSY;
}
else
{
/* Modify the status to prevent other tasks from performing operations on this task. */
task->object_inited = OS_KOBJ_DEINITED;
OS_KERNEL_EXIT();
os_spin_lock(&gs_os_task_resource_list_lock);
os_list_del(&task->resource_node);
os_spin_unlock(&gs_os_task_resource_list_lock);
OS_KERNEL_ENTER();
task->state |= OS_TASK_STATE_CLOSE;
#ifdef OS_USING_SMP
if (task->cpu_index == os_cpu_id_get())
{
OS_ASSERT(((task->state & OS_TASK_STATE_READY) != 0));
k_readyq_remove(task);
task->state &= ~OS_TASK_STATE_READY;
need_sched = OS_TRUE;
}
/*
The task to be destroyed on other cores,There may be the following scenarios:
1.The task is locked for scheduling and needs to be destroyed after release scheduling lock;
2.Waiting for the scheduling lock (closed interrupt). When the scheduling lock is released,
it enters the critical area of the scheduling lock and is destroyed after the scheduling lock is released;
3.other scenarios, destroy after receiving the scheduling IPI;
*/
else if (task->cpu_index != -1)
{
k_readyq_remove(task);
task->state &= ~OS_TASK_STATE_READY;
current_task = _k_task_self();
k_readyq_remove(current_task);
current_task->state &= ~OS_TASK_STATE_READY;
current_task->state |= OS_TASK_STATE_BLOCK;
current_task->block_list_head = OS_NULL;
os_list_add_tail(&task->join_node, ¤t_task->task_node);
need_sched = OS_TRUE;
}
#else
_k_task_deinit(task);
current_task = _k_task_self();
if (task == current_task)
{
os_list_add_tail(&gs_os_task_recycle_list_head, &task->resource_node);
_k_wakeup_recycle_task();
need_sched = OS_TRUE;
}
#endif
else
{
_k_task_deinit(task);
OS_KERNEL_EXIT();
object_alloc_type = task->object_alloc_type;
if (OS_NULL != task->cleanup)
{
task->cleanup(task->user_data);
}
#ifdef OS_USING_HEAP
if (OS_KDATA_ALLOC_TYPE_DYNAMIC == (object_alloc_type & OS_KDATA_ALLOC_TYPE_DYNAMIC))
{
OS_KERNEL_FREE(task->stack_begin);
}
if (OS_KOBJ_ALLOC_TYPE_DYNAMIC == (object_alloc_type & OS_KOBJ_ALLOC_TYPE_DYNAMIC))
{
OS_KERNEL_FREE(task);
}
#endif
OS_KERNEL_ENTER();
}
}
if (OS_TRUE == need_sched)
{
OS_KERNEL_EXIT_SCHED();
}
else
{
OS_KERNEL_EXIT();
}
return ret;
}
/**
***********************************************************************************************************************
* @brief This function to set the cleanup callback function
*
* @param[in] tid The id of task.
* @param[in] cleanup Cleanup function.
*
* @return None.
* @retval None.
***********************************************************************************************************************
*/
os_err_t os_task_set_cleanup_callback(os_task_id tid, void (*cleanup)(void *user_data))
{
os_task_t *task;
OS_KERNEL_INIT();
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(OS_NULL != task);
OS_ASSERT(OS_KOBJ_INITED == task->object_inited);
OS_KERNEL_ENTER();
task->cleanup = cleanup;
OS_KERNEL_EXIT();
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief This function to set the user data
*
* @param[in] tid The id of task.
* @param[in] user_data User data.
*
* @return None.
* @retval None.
***********************************************************************************************************************
*/
os_err_t os_task_set_user_data(os_task_id tid, void *user_data)
{
os_task_t *task;
OS_KERNEL_INIT();
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(OS_NULL != task);
OS_ASSERT(OS_KOBJ_INITED == task->object_inited);
OS_KERNEL_ENTER();
task->user_data = user_data;
OS_KERNEL_EXIT();
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief This function to get the user data
*
* @param[in] tid The id of task.
*
* @return user data.
* @retval user data.
***********************************************************************************************************************
*/
void *os_task_get_user_data(os_task_id tid)
{
os_task_t *task;
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(OS_NULL != task);
return task->user_data;
}
#ifdef OS_USING_SMP
/**
***********************************************************************************************************************
* @brief This function to set the cpu affinity.
*
* @details Bind tasks to specific cores.
*
* @param[in] tid The ID of task control block.
* @param[in] new_affinity Core number to bind.
*
* @return The result of setting the cpu affinity.
* @retval OS_SUCCESS Set successfully.
* @retval else Set failed.
***********************************************************************************************************************
*/
os_err_t os_task_set_cpu_affinity(os_task_id tid, int32_t new_affinity)
{
os_err_t ret;
os_task_t *task;
OS_KERNEL_INIT();
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(OS_NULL != task);
OS_ASSERT(OS_KOBJ_INITED == task->object_inited);
OS_KERNEL_ENTER();
if ((new_affinity >= -1) && (new_affinity < OS_SMP_MAX_CPUS))
{
if (((task->state & OS_TASK_STATE_READY) != 0) && (task->cpu_index == -1))
{
if (task->cpu_affinity != new_affinity)
{
k_readyq_remove(task);
task->cpu_affinity = new_affinity;
k_readyq_put(task);
}
}
else
{
task->cpu_affinity = new_affinity;
}
ret = OS_SUCCESS;
}
else
{
ret = OS_INVAL;
}
OS_KERNEL_EXIT();
return ret;
}
os_err_t os_task_get_cpu_affinity(os_task_id tid, int32_t *affinity)
{
os_task_t *task;
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(OS_NULL != task);
OS_ASSERT(OS_KOBJ_INITED == task->object_inited);
OS_ASSERT(OS_NULL != affinity);
*affinity = task->cpu_affinity;
return OS_SUCCESS;
}
#endif
/**
***********************************************************************************************************************
* @brief Startup a task.
*
* @details Put the task into the ready queue and trigger a schedule.
*
* @param[in] tid The ID of task control block.
*
* @return The result of starting the task.
* @retval OS_SUCCESS Startup the task successfully.
* @retval else Startup the task failed.
***********************************************************************************************************************
*/
os_err_t os_task_startup(os_task_id tid)
{
os_task_t *task;
OS_KERNEL_INIT();
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(OS_NULL != task);
OS_ASSERT(OS_KOBJ_INITED == task->object_inited);
OS_ASSERT(OS_TASK_STATE_INIT == task->state);
OS_KERNEL_ENTER();
task->state &= ~OS_TASK_STATE_INIT;
task->state |= OS_TASK_STATE_READY;
k_readyq_put(task);
OS_KERNEL_EXIT_SCHED();
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief Suspend a task.
*
* @param[in] tid The ID of task control block.
*
* @return The result of suspending the task.
* @retval OS_SUCCESS Suspend the task successfully.
* @retval else Suspend the task failed.
***********************************************************************************************************************
*/
os_err_t os_task_suspend(os_task_id tid)
{
os_err_t ret;
os_task_t *task;
OS_KERNEL_INIT();
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(OS_NULL != task);
OS_ASSERT(OS_KOBJ_INITED == task->object_inited);
OS_ASSERT((OS_FALSE == os_is_irq_disabled()) || (task != k_task_self()));
OS_ASSERT((OS_FALSE == os_is_schedule_locked()) || (task != k_task_self()));
ret = OS_SUCCESS;
OS_KERNEL_ENTER();
if (task->state & ~(OS_TASK_STATE_READY | OS_TASK_STATE_SLEEP | OS_TASK_STATE_BLOCK))
{
OS_KERNEL_EXIT();
OS_KERN_LOG(KERN_ERROR,
TASK_TAG,
"Incorrect task(%s) state(0x%04X), not allow to suspend.",
task->name,
task->state);
ret = OS_FAILURE;
}
else
{
/* The task is at ready queue */
if (task->state & OS_TASK_STATE_READY)
{
k_readyq_remove(task);
task->state &= ~OS_TASK_STATE_READY;
}
task->state |= OS_TASK_STATE_SUSPEND;
#ifdef OS_USING_SMP
if (task->cpu_index != -1)
{
OS_KERNEL_EXIT_SCHED();
}
#else
if (task == _k_task_self())
{
OS_KERNEL_EXIT_SCHED();
}
#endif
else
{
OS_KERNEL_EXIT();
}
}
return ret;
}
/**
***********************************************************************************************************************
* @brief Resume a task from suspended state.
*
* @param[in] tid The ID of task control block.
*
* @return The result of suspending the task.
* @retval OS_SUCCESS Resume the task successfully.
* @retval else Resume the task failed.
***********************************************************************************************************************
*/
os_err_t os_task_resume(os_task_id tid)
{
os_err_t ret;
os_task_t *task;
OS_KERNEL_INIT();
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(OS_NULL != task);
OS_ASSERT(OS_KOBJ_INITED == task->object_inited);
ret = OS_SUCCESS;
OS_KERNEL_ENTER();
if ((task->state & OS_TASK_STATE_SUSPEND) == 0)
{
OS_KERNEL_EXIT();
OS_KERN_LOG(KERN_ERROR, TASK_TAG, "Task(%s) state is not suspend, not allow to resume.", task->name);
ret = OS_FAILURE;
}
else
{
task->state &= ~OS_TASK_STATE_SUSPEND;
if ((task->state & (OS_TASK_STATE_SLEEP | OS_TASK_STATE_BLOCK)) != 0)
{
/*
* When the task sleep or block, only clear the suspend state.
* In this case, the resume is also considered successful.
*/
OS_KERNEL_EXIT();
}
else
{
task->state |= OS_TASK_STATE_READY;
k_readyq_put(task);
OS_KERNEL_EXIT_SCHED();
}
}
return ret;
}
/**
***********************************************************************************************************************
* @brief Task actively give up cpu to tasks of equal priority.
*
* @attention This interface is not allowed in the following cases:
* 1. In interrupt context.
* 2. Interrupt is disabled.
* 3. Scheduler is locked.
*
* @param[in] None.
*
* @return The result of yield the task.
* @retval OS_SUCCESS Yield the task successfully.
* @retval else Yield the task failed.
***********************************************************************************************************************
*/
os_err_t os_task_yield(void)
{
os_task_t *current_task;
OS_KERNEL_INIT();
OS_ASSERT(OS_FALSE == os_is_irq_active());
OS_ASSERT(OS_FALSE == os_is_irq_disabled());
OS_ASSERT(OS_FALSE == os_is_schedule_locked());
OS_KERNEL_ENTER();
current_task = _k_task_self();
OS_ASSERT((current_task != OS_NULL));
if (OS_TRUE == k_readyq_move_tail(current_task))
{
OS_KERNEL_EXIT_SCHED();
}
else
{
OS_KERNEL_EXIT();
}
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief Change time slice of task
*
* @param[in] tid The ID of task control block.
* @param[in] new_time_slice New time slice.
*
* @return The result of setting new time slice.
* @retval OS_SUCCESS Set new time slice successfully.
* @retval else Set new time slice failed.
***********************************************************************************************************************
*/
os_err_t os_task_set_time_slice(os_task_id tid, os_tick_t new_time_slice)
{
os_task_t *task;
OS_KERNEL_INIT();
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(task != OS_NULL);
OS_ASSERT(task->object_inited == OS_KOBJ_INITED);
OS_ASSERT((new_time_slice > 0) && (new_time_slice < 100));
OS_KERNEL_ENTER();
task->time_slice = new_time_slice;
if ((task->state & OS_TASK_STATE_INIT) != 0)
{
task->remaining_time_slice = new_time_slice;
}
OS_KERNEL_EXIT();
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief Get time slice of task
*
* @param[in] tid The ID of task control block.
*
* @return Time slice of the task.
***********************************************************************************************************************
*/
os_err_t os_task_get_time_slice(os_task_id tid, os_tick_t *time_slice)
{
os_task_t *task;
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(task != OS_NULL);
OS_ASSERT(task->object_inited == OS_KOBJ_INITED);
OS_ASSERT(time_slice != OS_NULL);
*time_slice = task->time_slice;
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief Get remaining time slice of task
*
* @param[in] tid The ID of task control block.
*
* @return Remaining time slice of the task.
***********************************************************************************************************************
*/
os_err_t os_task_get_remaining_time_slice(os_task_id tid, os_tick_t *time_slice)
{
os_task_t *task;
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(task != OS_NULL);
OS_ASSERT(task->object_inited == OS_KOBJ_INITED);
OS_ASSERT(time_slice != OS_NULL);
*time_slice = task->remaining_time_slice;
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief Change priority of task
*
* @param[in] tid The ID of task control block.
* @param[in] new_priority New priority.
*
* @return The result of setting priority.
* @retval OS_SUCCESS Set new priority successfully.
* @retval else Set new priority failed.
***********************************************************************************************************************
*/
os_err_t os_task_set_priority(os_task_id tid, uint8_t new_priority)
{
os_bool_t need_schedule;
os_bool_t task_hold_mutex;
os_task_t *task;
OS_KERNEL_INIT();
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(task != OS_NULL);
OS_ASSERT(new_priority < OS_TASK_PRIORITY_MAX);
OS_ASSERT(task->object_inited == OS_KOBJ_INITED);
need_schedule = OS_FALSE;
OS_KERNEL_ENTER();
#if defined(OS_USING_MUTEX)
task_hold_mutex = !os_list_empty(&task->hold_mutex_list_head);
#else
task_hold_mutex = OS_FALSE;
#endif
task->backup_priority = new_priority;
/* Task does not hold mutex */
if (OS_FALSE == task_hold_mutex)
{
if ((task->state & OS_TASK_STATE_READY) != 0)
{
k_readyq_remove(task);
task->current_priority = new_priority;
k_readyq_put(task);
need_schedule = OS_TRUE;
}
else if ((task->state & OS_TASK_STATE_BLOCK) != 0)
{
#ifdef OS_USING_SMP
if ((OS_NULL != task->block_list_head) && (OS_TRUE == task->is_wake_prio))
#else
OS_ASSERT((OS_NULL != task->block_list_head));
if (OS_TRUE == task->is_wake_prio)
#endif
{
os_list_del(&task->task_node);
task->current_priority = new_priority;
k_blockq_insert(task->block_list_head, task);
}
else
{
task->current_priority = new_priority;
}
}
else
{
task->current_priority = new_priority;
}
}
if (OS_TRUE == need_schedule)
{
OS_KERNEL_EXIT_SCHED();
}
else
{
OS_KERNEL_EXIT();
}
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief Get priority of task
*
* @param[in] tid The ID of task control block.
*
* @return Priority of the task.
***********************************************************************************************************************
*/
os_err_t os_task_get_priority(os_task_id tid, uint8_t *priority)
{
os_task_t *task;
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(task != OS_NULL);
OS_ASSERT(task->object_inited == OS_KOBJ_INITED);
OS_ASSERT(OS_NULL != priority);
*priority = task->current_priority;
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief Get current task control block.
*
* @param None.
*
* @return The ID of current task.
***********************************************************************************************************************
*/
os_task_id os_get_current_task(void)
{
#ifdef OS_USING_SMP
os_ubase_t irq_save;
const os_task_t *task;
irq_save = os_irq_lock();
task = g_os_current_task[os_cpu_id_get()];
os_irq_unlock(irq_save);
return OS_TYPE_CONVERT(os_task_id, task);
#else
return OS_TYPE_CONVERT(os_task_id, g_os_current_task);
#endif
}
/**
***********************************************************************************************************************
* @brief Get task control block by name.
*
* @attention Because the idle-task and recycle-task are built-in tasks, they cannot be found.
*
* @param[in] name Task name.
*
* @return The address of task control block to be found.
* @retval OS_NULL Task with the specified name was not found.
* @retval else The address of task control block to be found by name.
***********************************************************************************************************************
*/
os_task_id os_task_get_id(const char *name)
{
os_list_node_t *pos;
os_task_t *iter_task;
os_task_t *found_task;
OS_ASSERT(OS_NULL != name);
found_task = OS_NULL;
/*
* Because recycle task and idle task are system tasks,
* They don't want to be accessed by the application layer.
*/
if ((name[0] != '\0') && (strncmp(name, OS_RECYCLE_TASK_NAME, OS_NAME_MAX) != 0) &&
(strncmp(name, OS_IDLE_TASK_NAME, OS_NAME_MAX) != 0))
{
os_spin_lock(&gs_os_task_resource_list_lock);
os_list_for_each(pos, &gs_os_task_resource_list_head)
{
iter_task = os_list_entry(pos, os_task_t, resource_node);
if (strncmp(name, iter_task->name, OS_NAME_MAX) == 0)
{
found_task = iter_task;
break;
}
}
os_spin_unlock(&gs_os_task_resource_list_lock);
}
return OS_TYPE_CONVERT(os_task_id, found_task);
}
/**
***********************************************************************************************************************
* @brief Query whether the specified task exists.
*
* @param[in] tid The ID of task control block.
*
* @return Whether the specified task exists.
* @retval OS_TRUE The specified task exists.
* @retval OS_FALSE The specified task doesn't exists.
***********************************************************************************************************************
*/
os_bool_t os_task_check_exist(os_task_id tid)
{
os_task_t *iter_task;
os_list_node_t *node;
os_bool_t exist;
os_task_t *task;
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(OS_NULL != task);
exist = OS_FALSE;
os_spin_lock(&gs_os_task_resource_list_lock);
os_list_for_each(node, &gs_os_task_resource_list_head)
{
iter_task = os_list_entry(node, os_task_t, resource_node);
if (task == iter_task)
{
exist = OS_TRUE;
break;
}
}
os_spin_unlock(&gs_os_task_resource_list_lock);
return exist;
}
/**
***********************************************************************************************************************
* @brief Get the name of the specified task.
*
* @param[in] tid The ID of task control block.
*
* @return The name of the specified task.
***********************************************************************************************************************
*/
const char *os_task_get_name(os_task_id tid)
{
os_task_t *task;
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(task != OS_NULL);
return task->name;
}
/**
***********************************************************************************************************************
* @brief Get the state of the specified task.
*
* @param[in] tid The ID of task control block.
*
* @return The state of the specified task.
***********************************************************************************************************************
*/
os_err_t os_task_get_state(os_task_id tid, uint16_t *status)
{
os_task_t *task;
OS_KERNEL_INIT();
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(task != OS_NULL);
OS_ASSERT(OS_NULL != status);
OS_KERNEL_ENTER();
#ifdef OS_USING_SMP
if (task->cpu_index == -1)
#else
if (task != _k_task_self())
#endif
{
*status = task->state;
}
else
{
*status = OS_TASK_STATE_RUNNING;
}
OS_KERNEL_EXIT();
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief Get the stack top of the specified task.
*
* @param[in] tid The ID of task control block.
*
* @return The stack top of the specified task.
***********************************************************************************************************************
*/
void *os_task_get_stack_top(os_task_id tid)
{
os_task_t *task;
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(task != OS_NULL);
return task->stack_top;
}
/**
***********************************************************************************************************************
* @brief Get the stack begin of the specified task.
*
* @param[in] tid The ID of task control block.
*
* @return The stack begin of the specified task.
***********************************************************************************************************************
*/
void *os_task_get_stack_begin(os_task_id tid)
{
os_task_t *task;
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(task != OS_NULL);
return task->stack_begin;
}
/**
***********************************************************************************************************************
* @brief Get the stack end of the specified task.
*
* @param[in] tid The ID of task control block.
*
* @return The stack end of the specified task.
***********************************************************************************************************************
*/
void *os_task_get_stack_end(os_task_id tid)
{
os_task_t *task;
task = OS_TYPE_CONVERT(os_task_t *, tid);
OS_ASSERT(task != OS_NULL);
return task->stack_end;
}
/**
***********************************************************************************************************************
* @brief Get the task total count of the system.
*
* @param[in] none.
*
* @return The task total count of the system.
***********************************************************************************************************************
*/
uint32_t os_task_get_total_count(void)
{
uint32_t task_count;
os_spin_lock(&gs_os_task_resource_list_lock);
task_count = os_list_len(&gs_os_task_resource_list_head);
OS_ASSERT((0U != task_count));
os_spin_unlock(&gs_os_task_resource_list_lock);
return task_count;
}
/**
***********************************************************************************************************************
* @brief Force the current task to sleep.
*
* @details If the tick is 0, giveup the cpu.
*
* @attention This interface is not allowed in the following cases:
* 1. In interrupt context.
* 2. Interrupt is disabled.
* 3. Scheduler is locked.
*
* @param[in] tick The value of task sleep in tick.
*
* @return The result of forcing current task to sleep.
* @retval OS_SUCCESS Force current task to sleep successfully.
* @retval else Force current task to sleep failed.
***********************************************************************************************************************
*/
os_err_t os_task_tsleep(os_tick_t tick)
{
os_task_t *current_task;
OS_KERNEL_INIT();
OS_ASSERT(OS_FALSE == os_is_irq_active());
OS_ASSERT(OS_FALSE == os_is_irq_disabled());
OS_ASSERT(OS_FALSE == os_is_schedule_locked());
OS_ASSERT(tick < (OS_TICK_MAX / 2));
current_task = k_task_self();
OS_ASSERT((OS_NULL != current_task));
OS_KERNEL_ENTER();
if (tick > 0)
{
k_readyq_remove(current_task);
current_task->state &= ~OS_TASK_STATE_READY;
current_task->state |= OS_TASK_STATE_SLEEP;
k_tickq_put(current_task, tick);
OS_KERNEL_EXIT_SCHED();
}
else
{
if (OS_TRUE == k_readyq_move_tail(current_task))
{
OS_KERNEL_EXIT_SCHED();
}
else
{
OS_KERNEL_EXIT();
}
}
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief Force the current task to sleep.
*
* @details If the time is 0, giveup the cpu.
*
* @attention This function actually calls os_task_tsleep, so the minimum precision is tick.
* This interface is not allowed in the following cases:
* 1. In interrupt context.
* 2. Interrupt is disabled.
* 3. Scheduler is locked.
*
* @param[in] ms The value of task sleep in millisecond.
*
* @return The result of forcing current task to sleep.
* @retval OS_SUCCESS Force current task to sleep successfully.
* @retval else Force current task to sleep failed.
***********************************************************************************************************************
*/
os_err_t os_task_msleep(uint32_t ms)
{
os_tick_t tick;
os_err_t ret;
tick = os_tick_from_ms(ms);
ret = os_task_tsleep(tick);
return ret;
}
/**
***********************************************************************************************************************
* @brief This function will return address of variable that save the last error number.
*
* @details If in the task context, get from the current task. Otherwise, get from the "gs_os_errno".
*
* @param None.
*
* @return The address of variable that save the last error number.
***********************************************************************************************************************
*/
os_err_t *os_errno(void)
{
os_task_t *current_task;
os_err_t *err_code;
os_bool_t irq_active;
irq_active = os_is_irq_active();
if (irq_active)
{
err_code = &gs_os_err_code;
}
else
{
current_task = k_task_self();
/* The schduler is not start. */
if (OS_NULL == current_task)
{
err_code = &gs_os_err_code;
}
/* The schduler is start and is not in interrupt context */
else
{
err_code = ¤t_task->err_code;
}
}
return err_code;
}
/**
***********************************************************************************************************************
* @brief This function will return address of gs_os_task_resource_list_lock.
*
* @param None.
*
* @return The address of gs_os_task_resource_list_lock.
***********************************************************************************************************************
*/
os_spinlock_t *k_task_resource_list_lock_get(void)
{
return &gs_os_task_resource_list_lock;
}
/**
***********************************************************************************************************************
* @brief This function will return address of gs_os_task_resource_list_head.
*
* @param None.
*
* @return The address of gs_os_task_resource_list_head.
***********************************************************************************************************************
*/
os_list_node_t *k_task_resource_list_head_get(void)
{
return &gs_os_task_resource_list_head;
}
#if defined(OS_USING_SHELL)
#include <shell.h>
typedef struct
{
os_task_t *task;
void *stack_top;
void *stack_begin;
void *stack_end;
uint32_t stack_max_used;
os_tick_t time_slice;
os_tick_t remaining_time_slice;
uint8_t current_priority;
uint16_t state;
} sh_task_info_t;
os_err_t os_task_show(os_task_t *task)
{
sh_task_info_t task_info;
os_ubase_t state_len;
os_ubase_t tmp;
const static char *state_table[16] =
{"Init", "Ready", "Running", "Sleep", "Block", "Suspend", "", "", "", "", "", "", "", "", "", "Close"};
char str_state[20];
uint16_t int_state;
uint32_t stack_size;
os_ubase_t state_idx;
os_task_t *current_task;
OS_KERNEL_INIT();
if ((OS_KOBJ_INITED != task->object_inited) || (OS_NULL == task))
{
return OS_FAILURE;
}
OS_KERNEL_ENTER();
task_info.task = task;
task_info.stack_top = task->stack_top;
task_info.stack_begin = task->stack_begin;
task_info.stack_end = task->stack_end;
task_info.stack_max_used =
os_hw_stack_max_used(task->stack_begin, (os_ubase_t)task->stack_end - (os_ubase_t)task->stack_begin);
task_info.time_slice = task->time_slice;
task_info.remaining_time_slice = task->remaining_time_slice;
task_info.current_priority = task->current_priority;
task_info.state = task->state;
OS_KERNEL_EXIT();
os_kprintf("%-*s 0x%-10x %-8u",
OS_NAME_MAX,
(task_info.task->name[0] != '\0') ? task_info.task->name : "-",
task_info.task,
task_info.task->current_priority);
int_state = task_info.task->state;
#ifdef OS_USING_SMP
if (task->cpu_index != -1)
#else
if ((task == _k_task_self()) && (int_state & OS_TASK_STATE_READY))
#endif
{
int_state = OS_TASK_STATE_RUNNING;
}
str_state[0] = '\0';
state_len = 0;
while (int_state)
{
state_idx = os_ffs(int_state) - 1;
tmp = strlen(state_table[state_idx]);
if ((tmp + state_len + 1) <= sizeof(str_state))
{
strncat(str_state, state_table[state_idx], 7);
state_len += (tmp < 7 ? tmp : 7);
}
int_state = int_state & (~(1 << state_idx));
if (int_state)
{
if ((1 + state_len + 1) <= sizeof(str_state))
{
strcat(str_state, "|");
state_len++;
}
}
}
os_kprintf(" %-20s", str_state);
current_task = k_task_self();
if (task_info.task == current_task)
{
os_kprintf(" 0x%p", os_get_current_task_sp());
}
else
{
os_kprintf(" 0x%p", task_info.stack_top);
}
stack_size = (os_ubase_t)task_info.stack_end - (os_ubase_t)task_info.stack_begin;
os_kprintf(" 0x%p %-10u %3u%% %4lu/%-4lu\r\n",
task_info.stack_begin,
stack_size,
(task_info.stack_max_used * 100) / stack_size,
task_info.remaining_time_slice,
task_info.time_slice);
return OS_SUCCESS;
}
/**
***********************************************************************************************************************
* @brief Show all tasks info.
*
* @param[in] argc Command arguments count.
* @param[in] argv Command arguments
*
* @return The state of executting command.
* @retval OS_SUCCESS Execute command success.
* @retval else Execute command failed.
***********************************************************************************************************************
*/
os_err_t sh_show_task_info(int32_t argc, char **argv)
{
os_task_t *iter_task;
os_task_t *task_tmp;
uint16_t len;
OS_UNREFERENCE(argc);
OS_UNREFERENCE(argv);
/* clang-format off */
os_kprintf("[Tips]: \r\n"
"Priority: Range is [0, %d], 0 is the highest priority, %d is the lowest priority.\r\n",
OS_TASK_PRIORITY_MAX-1,
OS_TASK_PRIORITY_MAX-1);
os_kprintf("Stack size: It is described in bytes.\r\n");
os_kprintf("Timeslice: The numerator describes the remaining time slice of the task,"
"and the denominator describes the total time slice of the task.\r\n"
"\r\n");
os_kprintf("%-*s Task ID Priority State Stack top Stack addr Stack size Max used "
"Timeslice\r\n",
OS_NAME_MAX,
"Task");
/* clang-format on */
len = OS_NAME_MAX;
while (len--)
{
os_kprintf("-");
}
os_kprintf(
" ------------ -------- -------------------- ---------- ---------- ---------- -------- ---------\r\n");
if (argc >= 2)
{
if (argv[1])
{
task_tmp = (os_task_t *)strtoul(argv[1], 0, 0);
os_spin_lock(&gs_os_task_resource_list_lock);
os_list_for_each_entry(iter_task, &gs_os_task_resource_list_head, os_task_t, resource_node)
{
if (task_tmp == iter_task)
{
os_task_show(task_tmp);
os_spin_unlock(&gs_os_task_resource_list_lock);
return OS_SUCCESS;
}
}
os_spin_unlock(&gs_os_task_resource_list_lock);
}
os_kprintf("Invalid Task Object.\r\n");
return OS_FAILURE;
}
os_spin_lock(&gs_os_task_resource_list_lock);
os_list_for_each_entry(iter_task, &gs_os_task_resource_list_head, os_task_t, resource_node)
{
os_task_show(iter_task);
}
os_spin_unlock(&gs_os_task_resource_list_lock);
return OS_SUCCESS;
}
SH_CMD_EXPORT(show_task, sh_show_task_info, "Show task information");
#endif /* defined(OS_USING_SHELL) */