www.pudn.com > r&s1.10°æ±¾£«Îĵµ.rar > mutex.c
/*
===============================================================================
| Copyright (C) 2004 RuanHaiShen, All rights reserved.
| SUMMARY:
| Mutex 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"
#if CFG_MUTEX_EN > 0
err_t mutex_init(mutex_t* mut, u8 prio)
{
__ASSERT(mut != NULL);
#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_NONE) {
CRITICAL_EXIT;
return EEXIST;
}
_tasks[prio].state = STATE_ZOMBIE;
CRITICAL_EXIT;
mut->ceiling = prio;
mut->hand_prio = NULL_PRIO;
__queue_init(mut->tasks);
return EOK;
}
#if CFG_MUTEX_EN == 1
err_t mutex_wait(mutex_t* mut)
{
register u8 current;
register u8 ceiling;
register u8 hand;
__ASSERT(mut != NULL);
#if CFG_ARG_CHK > 0
if (_sched_lock > 0) {
return ELOCK;
}
#else
__ASSERT(_sched_lock == 0);
#endif
while (true) {
CRITICAL_ENTER;
current = _current_prio;
ceiling = mut->ceiling;
hand = mut->hand_prio;
if (hand == NULL_PRIO) {
mut->hand_prio = _tasks[current].prio.normal;
__nprio_lock(current);
CRITICAL_EXIT;
return EOK;
}
if (current < hand &&
!(_tasks[hand].state | STATE_RESERVED)) {
/*change hand-priority to ceiling-priority*/
__memcpy(&_tasks[ceiling], &_tasks[hand], sizeof(task_t));
_tasks[hand].delay = 0;
_tasks[hand].state = (STATE_ZOMBIE|STATE_RESERVED);
_tasks[hand].prio.current = ceiling;
if (_tasks[ceiling].pend_q == NULL) {
__ready_que_move(hand, ceiling);
} else {
__queue_remove_f(_tasks[ceiling].pend_q, hand);
__queue_add_f(_tasks[ceiling].pend_q, ceiling);
}
#if CFG_ARG_CHK > 0
/*prevent a task waiting the same mutex again.*/
} else if (hand == _tasks[current].prio.normal) {
CRITICAL_EXIT;
return EAGAIN;
#endif
}
__ipc_block(&mut->tasks, 0);
CRITICAL_EXIT;
__schedule();
}
}
#if CFG_IPC_TIMEOUT_EN > 0
err_t mutex_timewait(mutex_t* mut, tick_t ticks)
{
register u8 current;
register u8 ceiling;
register u8 hand;
__ASSERT(mut != NULL);
#if CFG_ARG_CHK > 0
if (_sched_lock > 0) {
return ELOCK;
}
#else
__ASSERT(_sched_lock == 0);
#endif
while (true) {
CRITICAL_ENTER;
current = _current_prio;
ceiling = mut->ceiling;
hand = mut->hand_prio;
if (hand == NULL_PRIO) {
mut->hand_prio = _tasks[current].prio.normal;
__nprio_lock(current);
CRITICAL_EXIT;
return EOK;
}
if (current < hand &&
!(_tasks[hand].state | STATE_RESERVED)) {
/*change hand-priority to ceiling-priority*/
__memcpy(&_tasks[ceiling], &_tasks[hand], sizeof(task_t));
_tasks[hand].delay = 0;
_tasks[hand].state = (STATE_ZOMBIE|STATE_RESERVED);
_tasks[hand].prio.current = ceiling;
if (_tasks[ceiling].pend_q == NULL) {
__ready_que_move(hand, ceiling);
} else {
__queue_remove_f(_tasks[ceiling].pend_q, hand);
__queue_add_f(_tasks[ceiling].pend_q, ceiling);
}
#if CFG_ARG_CHK > 0
/*prevent a task waiting the same mutex again.*/
} else if (hand == _tasks[current].prio.normal) {
CRITICAL_EXIT;
return EAGAIN;
#endif
}
__ipc_block(&mut->tasks, ticks);
CRITICAL_EXIT;
__schedule();
CRITICAL_ENTER;
current = _current_prio;
if (_tasks[current].state & STATE_BLOCKED) {
__ipc_timeout(&mut->tasks);
CRITICAL_EXIT;
return ETIMEOUT;
}
__adjust_delay(current, ticks);
CRITICAL_EXIT;
}
}
#endif
err_t mutex_trywait(mutex_t* mut)
{
register u8 current;
__ASSERT(mut != NULL);
#if CFG_ARG_CHK > 0
if (_sched_lock > 0) {
return ELOCK;
}
#else
__ASSERT(_sched_lock == 0);
#endif
CRITICAL_ENTER;
current = _current_prio;
if (mut->hand_prio == NULL_PRIO) {
mut->hand_prio = _tasks[current].prio.normal;
__nprio_lock(current);
CRITICAL_EXIT;
return EOK;
}
CRITICAL_EXIT;
return ENAVAIL;
}
#else
err_t mutex_wait(mutex_t* mut)
{
register u8 current;
register u8 ceiling;
__ASSERT(mut != NULL);
#if CFG_ARG_CHK > 0
if (_sched_lock > 0) {
return ELOCK;
}
#else
__ASSERT(_sched_lock == 0);
#endif
while (true) {
CRITICAL_ENTER;
current = _current_prio;
ceiling = mut->ceiling;
if (mut->hand_prio == NULL_PRIO) {
mut->hand_prio = _tasks[current].prio.normal;
__nprio_lock(current);
if (current == mut->hand_prio) {
/*change hand-priority to ceiling-priority*/
__memcpy(&_tasks[ceiling], &_tasks[current], sizeof(task_t));
_tasks[current].state = (STATE_ZOMBIE|STATE_RESERVED);
_tasks[current].prio.current = ceiling;
__ready_que_remove(current);
__ready_que_add(ceiling);
_current_prio = ceiling;
}
CRITICAL_EXIT;
return EOK;
#if CFG_ARG_CHK > 0
/*prevent a task waiting the same mutex again.*/
} else if (mut->hand_prio == _tasks[current].prio.normal) {
CRITICAL_EXIT;
return EAGAIN;
#endif
}
__ipc_block(&mut->tasks, 0);
CRITICAL_EXIT;
__schedule();
}
}
#if CFG_IPC_TIMEOUT_EN > 0
err_t mutex_timewait(mutex_t* mut, tick_t ticks)
{
register u8 current;
register u8 ceiling;
__ASSERT(mut != NULL);
#if CFG_ARG_CHK > 0
if (_sched_lock > 0) {
return ELOCK;
}
#else
__ASSERT(_sched_lock == 0);
#endif
while (true) {
CRITICAL_ENTER;
current = _current_prio;
ceiling = mut->ceiling;
if (mut->hand_prio == NULL_PRIO) {
mut->hand_prio = _tasks[current].prio.normal;
__nprio_lock(current);
if (current == mut->hand_prio) {
/*change hand-priority to ceiling-priority*/
__memcpy(&_tasks[ceiling], &_tasks[current], sizeof(task_t));
_tasks[current].state = (STATE_ZOMBIE|STATE_RESERVED);
_tasks[current].prio.current = ceiling;
__ready_que_remove(current);
__ready_que_add(ceiling);
_current_prio = ceiling;
}
CRITICAL_EXIT;
return EOK;
#if CFG_ARG_CHK > 0
/*prevent a task waiting the same mutex again.*/
} else if (mut->hand_prio == _tasks[current].prio.normal) {
CRITICAL_EXIT;
return EAGAIN;
#endif
}
__ipc_block(&mut->tasks, ticks);
CRITICAL_EXIT;
__schedule();
CRITICAL_ENTER;
current = _current_prio;
if (_tasks[current].state & STATE_BLOCKED) {
__ipc_timeout(&mut->tasks);
CRITICAL_EXIT;
return ETIMEOUT;
}
__adjust_delay(current, ticks);
CRITICAL_EXIT;
}
}
#endif
err_t mutex_trywait(mutex_t* mut)
{
register u8 current;
register u8 ceiling;
__ASSERT(mut != NULL);
#if CFG_ARG_CHK > 0
if (_sched_lock > 0) {
return ELOCK;
}
#else
__ASSERT(_sched_lock == 0);
#endif
CRITICAL_ENTER;
current = _current_prio;
ceiling = mut->ceiling;
if (mut->hand_prio == NULL_PRIO) {
mut->hand_prio = _tasks[current].prio.normal;
__nprio_lock(current);
if (current == mut->hand_prio) {
/*change hand-priority to ceiling-priority*/
__memcpy(&_tasks[ceiling], &_tasks[current], sizeof(task_t));
_tasks[current].state = (STATE_ZOMBIE|STATE_RESERVED);
_tasks[current].prio.current = ceiling;
__ready_que_remove(current);
__ready_que_add(ceiling);
_current_prio = ceiling;
}
CRITICAL_EXIT;
return EOK;
}
CRITICAL_EXIT;
return ENAVAIL;
}
#endif
err_t mutex_release(mutex_t* mut)
{
register u8 current;
register u8 hand;
__ASSERT(mut != NULL);
#if CFG_ARG_CHK > 0
if (_sched_lock > 0) {
return ELOCK;
}
#else
__ASSERT(_sched_lock == 0);
#endif
CRITICAL_ENTER;
current = _current_prio;
hand = mut->hand_prio;
__nprio_unlock(current);
if (current == mut->ceiling) {
/*change current-priority to hand-priority*/
__memcpy(&_tasks[hand], &_tasks[current], sizeof(task_t));
_tasks[current].state = STATE_ZOMBIE;
__ready_que_remove(current);
__ready_que_add(hand);
/*!!! the current priority has been changed already:)*/
_current_prio = hand;
#if CFG_ARG_CHK > 0
} else if (hand != _tasks[current].prio.normal) {
__nprio_lock(current); /*!!!we have been unlock it above*/
CRITICAL_EXIT;
return EINVAL;
#endif
}
mut->hand_prio = NULL_PRIO;
__ipc_resume(&mut->tasks);
CRITICAL_EXIT;
__schedule();
return EOK;
}
u8 mutex_gethand(mutex_t* mut)
{
register u8 val;
__ASSERT(mut != NULL);
CRITICAL_ENTER;
val = mut->hand_prio;
CRITICAL_EXIT;
return val;
}
u8 mutex_getprio(mutex_t* mut)
{
register u8 val;
__ASSERT(mut != NULL);
CRITICAL_ENTER;
val = mut->ceiling;
CRITICAL_EXIT;
return val;
}
err_t mutex_destroy(mutex_t* mut)
{
__ASSERT(mut != NULL);
if (mut->hand_prio != NULL_PRIO) {
return EEXIST;
}
_tasks[mut->ceiling].state = STATE_NONE;
return EOK;
}
#endif
/*===========================================================================*/