www.pudn.com > r&s1.10°æ±¾£«Îĵµ.rar > task.c
/*
===============================================================================
| Copyright (C) 2004 RuanHaiShen, All rights reserved.
| SUMMARY:
| Task implementation.
|
| DESCRIPTION:
| See http://www.01s.org for documentation, latest information, license
| and contact details.
| email:ruanhaishen@01s.org
=============================================================================*/
/*===========================================================================*/
#include "arch/arch.h"
#include "inc/queue.h"
#include "inc/kernel.h"
#include "inc/memory.h"
#include "inc/ipc.h"
#include "inc/kapi.h"
task_t _tasks[CFG_MAX_TASKS];
static byte _idle_task_stack[CFG_IDLE_STACKSZ];
#if ARCH_STACK_GROW == UPWARDS
# define IDLE_STK_TOP &_idle_task_stack[0]
#else
# define IDLE_STK_TOP &_idle_task_stack[CFG_IDLE_STACKSZ - 1]
#endif
#if CFG_TASK_INFO_EN > 0
static u32 _idle_counter;
static info_t _task_info;
static byte _info_task_stack[CFG_INFO_STACKSZ];
#if ARCH_STACK_GROW == UPWARDS
# define STATUS_STK_TOP &_info_task_stack[0]
#else
# define STATUS_STK_TOP &_info_task_stack[CFG_INFO_STACKSZ - 1]
#endif
#endif
#if CFG_PRIO_MODE > 1
# define __nprio_init(prio) \
do { \
_tasks[prio].prio.normal = prio; \
_tasks[prio].lock = 0; \
} while (0)
#else
# define __nprio_init(prio) __MPT
#endif
#if CFG_IPC_EN > 0
# define __pend_q_init(prio) _tasks[prio].pend_q = NULL
#else
# define __pend_q_init(prio) __MPT
#endif
#define __tcb_init(prio, stack_base) \
do { \
_tasks[prio].stack = stack_base; \
_tasks[prio].delay = 0; \
__nprio_init(prio); \
__pend_q_init(prio); \
} while(0)
#define __tcb_free(prio) \
do { \
_tasks[prio].delay = 0; \
_tasks[prio].state = STATE_NONE; \
} while(0)
void task_lock(void)
{
CRITICAL_ENTER;
if (_sched_lock < 0xff) {
_sched_lock++;
}
CRITICAL_EXIT;
}
void task_unlock(void)
{
CRITICAL_ENTER;
if (_sched_lock > 0x00) {
_sched_lock--;
}
CRITICAL_EXIT;
__schedule();
}
err_t __task_create(
u8 prio, /* task priority */
entry_t entry, /* entry point function */
arg_t entry_arg, /* entry data */
sp_t stack_base /* stack base */
)
{
u8* pstk;
__ASSERT(entry != NULL);
__ASSERT(stack_base != NULL);
#if TASK_IDLE_PRIO < 0xff && CFG_ARG_CHK > 1
if (prio > TASK_IDLE_PRIO) {
return EOUTRANGE;
}
#elif TASK_IDLE_PRIO < 0xff
__ASSERT(prio <= TASK_IDLE_PRIO);
#endif
CRITICAL_ENTER;
if (_tasks[prio].state != STATE_NONE) {
CRITICAL_EXIT;
return EEXIST;
}
_tasks[prio].state = STATE_ZOMBIE;
CRITICAL_EXIT;
hook_task_create(prio);
pstk = __stack_init(entry, entry_arg, stack_base);
__tcb_init(prio, pstk);
CRITICAL_ENTER;
_tasks[prio].state = STATE_READY;
__ready_que_add(prio);
CRITICAL_EXIT;
__schedule();
return EOK;
}
#if CFG_TASK_DEL_EN > 0 && CFG_PRIO_MODE < 2
err_t task_delete(u8 prio)
{
#if CFG_ARG_CHK > 1
if (prio >= TASK_IDLE_PRIO && prio != SELF_PRIO) {
return EOUTRANGE;
}
#else
__ASSERT(prio < TASK_IDLE_PRIO || prio == SELF_PRIO);
#endif
CRITICAL_ENTER;
if (prio == SELF_PRIO) {
prio = _current_prio;
}
if (!(_tasks[prio].state & STATE_READY)) {
CRITICAL_EXIT;
return ENOTEXIST;
}
#if CFG_IPC_EN > 0
if (_tasks[prio].pend_q != NULL) {
__queue_remove_f(_tasks[prio].pend_q, prio);
} else
#endif
{ __ready_que_remove(prio); }
_sched_lock++;
CRITICAL_EXIT;
__tcb_free(prio);
hook_task_delete(prio);
CRITICAL_ENTER;
if (prio == _current_prio) {
_sched_lock = 0;
} else {
_sched_lock--;
}
CRITICAL_EXIT;
__schedule();
return EOK;
}
#elif CFG_TASK_DEL_EN > 0
err_t task_delete(u8 prio)
{
register u8 cprio;
#if CFG_ARG_CHK > 1
if (prio >= TASK_IDLE_PRIO && prio != SELF_PRIO) {
return EOUTRANGE;
}
#else
__ASSERT(prio < TASK_IDLE_PRIO || prio == SELF_PRIO);
#endif
CRITICAL_ENTER;
if (prio == SELF_PRIO) {
prio = _tasks[_current_prio].prio.normal;
} else if (!__prio_if_normal(prio)) {
CRITICAL_EXIT;
return ENOTEXIST;
}
cprio = _tasks[prio].prio.current;
__nprio_lock(cprio); /*prevent normal-prio being changed*/
CRITICAL_EXIT;
__dummy();
CRITICAL_ENTER;
cprio = _tasks[prio].prio.current;
#if CFG_IPC_EN > 0
if (_tasks[cprio].pend_q != NULL) {
__queue_remove_f(_tasks[cprio].pend_q, cprio);
} else
#endif
{ __ready_que_remove(cprio); }
_sched_lock++;
CRITICAL_EXIT;
__tcb_free(cprio);
hook_task_delete(prio);
CRITICAL_ENTER;
if (cprio == _current_prio) {
_sched_lock = 0;
} else {
_sched_lock--;
}
CRITICAL_EXIT;
__schedule();
return EOK;
}
#endif
#if CFG_PRIO_MODE == 1
err_t task_change_prio(u8 old_prio, u8 new_prio)
{
#if CFG_ARG_CHK > 1
if ((old_prio >= TASK_IDLE_PRIO && old_prio != SELF_PRIO) ||
new_prio >= TASK_IDLE_PRIO) {
return EOUTRANGE;
}
#else
__ASSERT((old_prio < TASK_IDLE_PRIO || old_prio == SELF_PRIO) &&
new_prio < TASK_IDLE_PRIO);
#endif
CRITICAL_ENTER;
if (_tasks[new_prio].state != STATE_NONE) {
CRITICAL_EXIT;
return EEXIST;
}
_tasks[new_prio].state = STATE_ZOMBIE;
CRITICAL_EXIT;
__dummy();
CRITICAL_ENTER;
if (old_prio == SELF_PRIO) {
old_prio = _current_prio;
}
if (!(_tasks[old_prio].state & STATE_READY)) {
_tasks[new_prio].state &= ~STATE_ZOMBIE;
CRITICAL_EXIT;
return ENOTEXIST;
}
__memcpy(&_tasks[new_prio], &_tasks[old_prio], sizeof(task_t));
__tcb_free(old_prio);
#if CFG_IPC_EN > 0
if (_tasks[new_prio].pend_q != NULL) {
__queue_remove_f(_tasks[new_prio].pend_q, old_prio);
__queue_add_f(_tasks[new_prio].pend_q, new_prio);
} else
#endif
{ __ready_que_move(old_prio, new_prio); }
if (_current_prio == old_prio) {
_current_prio = new_prio;
}
CRITICAL_EXIT;
__schedule();
return EOK;
}
#endif
#if CFG_PRIO_MODE == 2
err_t task_change_prio(u8 old_prio, u8 new_prio)
{
register u8 cprio;
#if CFG_ARG_CHK > 1
if ((old_prio >= TASK_IDLE_PRIO && old_prio != SELF_PRIO) ||
new_prio >= TASK_IDLE_PRIO) {
return EOUTRANGE;
}
#else
__ASSERT((old_prio < TASK_IDLE_PRIO || old_prio == SELF_PRIO) &&
new_prio < TASK_IDLE_PRIO);
#endif
CRITICAL_ENTER;
if (_tasks[new_prio].state != STATE_NONE) {
CRITICAL_EXIT;
return EEXIST;
}
if (old_prio == SELF_PRIO) {
cprio = _current_prio;
old_prio = _tasks[cprio].prio.normal;
} else if (!__prio_if_normal(old_prio)) {
CRITICAL_EXIT;
return ENOTEXIST;
} else {
cprio = _tasks[old_prio].prio.current;
}
if (_tasks[cprio].lock > 0) {
CRITICAL_EXIT;
return ELOCK;
}
__nprio_lock(cprio);
_tasks[new_prio].state = STATE_ZOMBIE;
CRITICAL_EXIT;
__dummy();
CRITICAL_ENTER;
cprio = _tasks[old_prio].prio.current;
__nprio_unlock(cprio);
_tasks[cprio].prio.normal = new_prio;
__memcpy(&_tasks[new_prio], &_tasks[old_prio], sizeof(task_t));
__tcb_free(old_prio);
if (cprio == old_prio) {
#if CFG_IPC_EN > 0
if (_tasks[new_prio].pend_q != NULL) {
__queue_remove_f(_tasks[new_prio].pend_q, cprio);
__queue_add_f(_tasks[new_prio].pend_q, new_prio);
} else
#endif
{ __ready_que_move(cprio, new_prio); }
}
if (_current_prio == old_prio) {
_current_prio = new_prio;
}
CRITICAL_EXIT;
__schedule();
return EOK;
}
err_t task_change_cprio(u8 prio, u8 new_cprio)
{
register u8 old_cprio;
#if CFG_ARG_CHK > 1
if ((prio >= TASK_IDLE_PRIO && prio != SELF_PRIO) ||
new_cprio >= TASK_IDLE_PRIO) {
return EOUTRANGE;
}
#else
__ASSERT((prio < TASK_IDLE_PRIO || prio == SELF_PRIO) &&
new_cprio < TASK_IDLE_PRIO);
#endif
/*see if prio is available*/
CRITICAL_ENTER;
if (prio == SELF_PRIO) {
old_cprio = _current_prio;
prio = _tasks[old_cprio].prio.normal;
} else if (!__prio_if_normal(prio)) {
CRITICAL_EXIT;
return ENOTEXIST;
} else {
old_cprio = _tasks[prio].prio.current;
}
__nprio_lock(old_cprio);
CRITICAL_EXIT;
__dummy();
CRITICAL_ENTER;
if (_tasks[new_cprio].state == STATE_NONE ||
(_tasks[new_cprio].state == STATE_RESERVED &&
prio == new_cprio)) {
_tasks[new_cprio].state |= STATE_ZOMBIE;
} else {
old_cprio = _tasks[prio].prio.current;
__nprio_unlock(old_cprio);
CRITICAL_EXIT;
return EINVAL;
}
CRITICAL_EXIT;
__dummy();
CRITICAL_ENTER;
old_cprio = _tasks[prio].prio.current; /**/
if (!(_tasks[prio].state & STATE_ZOMBIE) ||
prio == new_cprio) {
__nprio_unlock(old_cprio);
__memcpy(&_tasks[new_cprio], &_tasks[old_cprio], sizeof(task_t));
/*free the old current tcb*/
__tcb_free(old_cprio);
if (prio != new_cprio) {
_tasks[prio].delay = 0;
_tasks[prio].state = STATE_RESERVED;
_tasks[prio].prio.current = new_cprio;
}
#if CFG_IPC_EN > 0
if (_tasks[new_cprio].pend_q != NULL) {
__queue_remove_f(_tasks[new_cprio].pend_q, old_cprio);
__queue_add_f(_tasks[new_cprio].pend_q, new_cprio);
} else
#endif
{ __ready_que_move(old_cprio, new_cprio); }
if (_current_prio == old_cprio) {
_current_prio = new_cprio;
}
CRITICAL_EXIT;
__schedule();
return EOK;
} else {
__nprio_unlock(old_cprio);
_tasks[new_cprio].state &= ~STATE_ZOMBIE;
CRITICAL_EXIT;
return ENAVAIL;
}
}
#endif
void task_sleep(tick_t ticks)
{
register u8 current;
if (ticks > 0) {
CRITICAL_ENTER;
current = _current_prio;
_tasks[current].delay = ticks;
__ready_que_remove(current);
CRITICAL_EXIT;
__schedule();
}
}
#if CFG_PRIO_MODE < 2
err_t task_wake(u8 prio)
{
#if CFG_ARG_CHK > 1
if (prio >= TASK_IDLE_PRIO) {
return EOUTRANGE;
}
#else
__ASSERT(prio < TASK_IDLE_PRIO);
#endif
CRITICAL_ENTER;
if (_tasks[prio].delay != 0 &&
!(_tasks[prio].state & STATE_SUSPEND)) {
_tasks[prio].delay = 0;
__ready_que_add(prio);
CRITICAL_EXIT;
__schedule();
return EOK;
} else {
CRITICAL_EXIT;
return EUNKNOW;
}
}
#else
err_t task_wake(u8 prio)
{
register u8 cprio;
#if CFG_ARG_CHK > 1
if (prio >= TASK_IDLE_PRIO) {
return EOUTRANGE;
}
#else
__ASSERT(prio < TASK_IDLE_PRIO);
#endif
CRITICAL_ENTER;
if (!__prio_if_normal(prio)) {
CRITICAL_EXIT;
return ENOTEXIST;
}
cprio = _tasks[prio].prio.current;
if (_tasks[cprio].delay != 0 &&
!(_tasks[cprio].state & STATE_SUSPEND)) {
_tasks[cprio].delay = 0;
__ready_que_add(cprio);
CRITICAL_EXIT;
__schedule();
return EOK;
} else {
CRITICAL_EXIT;
return EUNKNOW;
}
}
#endif
#if CFG_TASK_SUS_EN > 0 && CFG_PRIO_MODE < 2
err_t task_suspend(u8 prio)
{
#if CFG_ARG_CHK > 1
if (prio >= TASK_IDLE_PRIO && prio != SELF_PRIO) {
return EOUTRANGE;
}
#else
__ASSERT(prio < TASK_IDLE_PRIO || prio == SELF_PRIO);
#endif
CRITICAL_ENTER;
if (prio == SELF_PRIO) {
prio = _current_prio;
}
if (_tasks[prio].state & STATE_READY) {
_tasks[prio].state |= STATE_SUSPEND;
__ready_que_susremove(prio, _tasks[prio].state);
CRITICAL_EXIT;
__schedule();
return EOK;
} else {
CRITICAL_EXIT;
return ENOTEXIST;
}
}
err_t task_resume(u8 prio)
{
#if CFG_ARG_CHK > 1
if (prio >= TASK_IDLE_PRIO) {
return EOUTRANGE;
}
#else
__ASSERT(prio < TASK_IDLE_PRIO);
#endif
CRITICAL_ENTER;
if (!(_tasks[prio].state & STATE_READY)) {
CRITICAL_EXIT;
return ENOTEXIST;
}
_tasks[prio].state &= ~STATE_SUSPEND;
if ((_tasks[prio].state & STATE_PREREADY) ||
(!(_tasks[prio].state & STATE_BLOCKED) &&
_tasks[prio].delay == 0)) {
_tasks[prio].state &= ~STATE_PREREADY;
__ready_que_add(prio);
}
CRITICAL_EXIT;
__schedule();
return EOK;
}
#elif CFG_TASK_SUS_EN > 0
err_t task_suspend(u8 prio)
{
register u8 cprio;
#if CFG_ARG_CHK > 1
if (prio >= TASK_IDLE_PRIO && prio != SELF_PRIO) {
return EOUTRANGE;
}
#else
__ASSERT(prio < TASK_IDLE_PRIO || prio == SELF_PRIO);
#endif
CRITICAL_ENTER;
if (prio == SELF_PRIO) {
cprio = _current_prio;
prio = _tasks[cprio].prio.normal;
} else if (!__prio_if_normal(prio)) {
CRITICAL_EXIT;
return ENOTEXIST;
} else {
cprio = _tasks[prio].prio.current;
}
_tasks[cprio].state |= STATE_SUSPEND;
__ready_que_susremove(cprio, _tasks[cprio].state);
CRITICAL_EXIT;
__schedule();
return EOK;
}
err_t task_resume(u8 prio)
{
register u8 cprio;
#if CFG_ARG_CHK > 1
if (prio >= TASK_IDLE_PRIO) {
return EOUTRANGE;
}
#else
__ASSERT(prio < TASK_IDLE_PRIO);
#endif
CRITICAL_ENTER;
if (!__prio_if_normal(prio)) {
CRITICAL_EXIT;
return ENOTEXIST;
}
cprio = _tasks[prio].prio.current;
_tasks[cprio].state &= ~STATE_SUSPEND;
if ((_tasks[cprio].state & STATE_PREREADY) ||
(!(_tasks[cprio].state & STATE_BLOCKED) &&
_tasks[cprio].delay == 0)) {
_tasks[cprio].state &= ~STATE_PREREADY;
__ready_que_add(cprio);
}
CRITICAL_EXIT;
__schedule();
return EOK;
}
#endif
void __idle_task(arg_t arg)
{
arg = arg;
while (true) {
hook_idle_task();
#if CFG_TASK_INFO_EN>0
CRITICAL_ENTER;
_idle_counter++;
CRITICAL_EXIT;
#endif
}
}
#if CFG_TASK_INFO_EN > 0
u32 __get_max_idlecnt(void)
{
u32 idle_cnt_max;
task_sleep(2);
CRITICAL_ENTER;
_idle_counter = 0L;
CRITICAL_EXIT;
task_sleep(TICKS_PER_SEC);
CRITICAL_ENTER;
idle_cnt_max = _idle_counter;
CRITICAL_EXIT;
return idle_cnt_max;
}
void __usrtask_suspend(void)
{
u8 prio;
for (prio = 0; prio != TASK_INFO_PRIO; prio++) {
task_suspend(prio);
}
}
void __usrtask_resume(void)
{
u8 prio;
for (prio = 0; prio != TASK_INFO_PRIO; prio++) {
task_resume(prio);
}
}
void __info_task(arg_t arg)
{
u32 idle_cnt;
u32 idle_cnt_max;
s8 usage;
arg = arg;
idle_cnt_max = __get_max_idlecnt();
__usrtask_resume();
__ASSERT(idle_cnt_max != 0);
for (;;) {
hook_info_task();
task_lock();
idle_cnt = _idle_counter;
_idle_counter = 0L;
usage = (s8)(100L - 100L * idle_cnt / idle_cnt_max);
if (usage >= 0) {
_task_info.cpu_usage = usage;
} else {
_task_info.cpu_usage = 0;
}
task_unlock();
task_sleep(TICKS_PER_SEC);
}
}
err_t task_getinfo(info_t* info)
{
register u8 prio;
__ASSERT(info != NULL);
prio = info->prio;
#if TASK_IDLE_PRIO < 0xff && CFG_ARG_CHK > 1
if (prio > TASK_IDLE_PRIO) {
return EOUTRANGE;
}
#elif TASK_IDLE_PRIO < 0xff
__ASSERT(prio <= TASK_IDLE_PRIO);
#endif
task_lock();
info->cpu_usage = _task_info.cpu_usage;
info->state = _tasks[prio].state;
info->delay = _tasks[prio].delay;
info->stack = _tasks[prio].stack;
task_unlock();
return EOK;
}
#endif
void __task_init(void)
{
u8 prio;
prio = TASK_IDLE_PRIO + 1;
do {
__memclr(&_tasks[--prio], sizeof(task_t));
} while (prio != 0);
task_create(TASK_IDLE_PRIO,
__idle_task,
(arg_t)0,
"__idle",
(sp_t)IDLE_STK_TOP,
CFG_IDLE_STACKSZ,
0);
#if CFG_TASK_INFO_EN>0
task_create(TASK_INFO_PRIO,
__info_task,
(arg_t)0,
"__info",
(sp_t)STATUS_STK_TOP,
CFG_INFO_STACKSZ,
0);
#endif
}
/*===========================================================================*/