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 
 
/*===========================================================================*/