
/*HEADER**********************************************************************
*
* Copyright 2008 Freescale Semiconductor, Inc.
* Copyright 2004-2008 Embedded Access Inc.
* Copyright 1989-2008 ARC International
*
* This software is owned or controlled by Freescale Semiconductor.
* Use of this software is governed by the Freescale MQX RTOS License
* distributed with this Material.
* See the MQX_RTOS_LICENSE file distributed for more details.
*
* Brief License Summary:
* This software is provided in source form for you to use free of charge,
* but it is not open source software. You are allowed to use this software
* but you cannot redistribute it or derivative works of it in source form.
* The software may be used only in connection with a product containing
* a Freescale microprocessor, microcontroller, or digital signal processor.
* See license agreement file for full license terms including other restrictions.
*****************************************************************************
*
* Comments:
*
*   This file contains functions of the Mutex component.
*
*
*END************************************************************************/

#include "mqx_inc.h"

#if MQX_USE_MUTEXES
#include "mutex.h"
#include "mutex_prv.h"

#if MQX_LITE_VERSION_NUMBER
MUTEX_COMPONENT_STRUCT mutex_struct;
#endif /* MQX_LITE_VERSION_NUMBER */

/*!
 * \brief Initializes the mutex attributes structure to default values.
 *
 * This function initializes the mutex attributes structure to default values and
 * validates the structure. It must be called before a task can modify the values
 * of the mutex attributes structure. This function does not affect any mutexes
 * already initialized with this structure.
 *
 * <table>
 *  <tr>
 *     <td><b> Mutex attribute </b></td>
 *     <td><b> Field in MUTEX_ATTR_STRUCT </b></td>
 *     <td><b> Default value </b></td>
 *  </tr>
 *  <tr>
 *     <td> Scheduling protocol </td>
 *     <td> POLICY </td>
 *     <td> MUTEX_NO_PRIO_INHERIT </td>
 *  </tr>
 *  <tr>
 *     <td> Valid </td>
 *     <td> VALID </td>
 *     <td> TRUE </td>
 *  </tr>
 *  <tr>
 *     <td> Priority </td>
 *     <td> PRIORITY </td>
 *     <td> 0 </td>
 *  </tr>
 *  <tr>
 *     <td> Spin limit </td>
 *     <td> COUNT </td>
 *     <td> 0 </td>
 *  </tr>
 *  <tr>
 *     <td> Waiting protocol </td>
 *     <td> WAITING POLICY </td>
 *     <td> MUTEX_QUEUEING </td>
 *  </tr>
 * </table>
 *
 * \param[in] attr_ptr Pointer to the mutex attributes structure to initialize.
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (attr_ptr is NULL.)
 *
 * \see _mutex_init
 * \see _mutatr_destroy
 * \see MUTEX_ATTR_STRUCT
 */
_mqx_uint _mutatr_init
(
    register MUTEX_ATTR_STRUCT_PTR attr_ptr
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE2(KLOG_mutatr_init, attr_ptr);

#if MQX_CHECK_ERRORS
    if (attr_ptr == NULL)
    {
        _KLOGX2(KLOG_mutatr_init, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

    attr_ptr->SCHED_PROTOCOL   = MUTEX_NO_PRIO_INHERIT;
    attr_ptr->PRIORITY_CEILING = 0;
    attr_ptr->VALID            = MUTEX_VALID;
    attr_ptr->COUNT            = 0;
    attr_ptr->WAIT_PROTOCOL    = MUTEX_QUEUEING;

    _KLOGX2(KLOG_mutatr_init, MQX_EOK);
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Installs the mutex component into the kernel.
 *
 * MQX calls this function if the mutex component is not created when a task calls
 * _mutex_init().
 *
 * \return MQX_OK
 * \return MQX_OUT_OF_MEMORY
 *
 * \see _mutex_init
 * \see _mutatr_init
 */
_mqx_uint _mutex_create_component(void)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;
    register MUTEX_COMPONENT_STRUCT_PTR mutex_component_ptr;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE1(KLOG_mutex_create_component);

    if (kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES] != NULL)
    {
        _KLOGX2(KLOG_mutex_create_component, MQX_OK);
        return (MQX_OK);
    } /* Endif */

#if MQX_LITE_VERSION_NUMBER
    mutex_component_ptr = &mutex_struct;
#else
    mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) _mem_alloc_system_zero(
                    (_mem_size) sizeof(MUTEX_COMPONENT_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (mutex_component_ptr == NULL)
    {
        _KLOGX2(KLOG_mutex_create_component, MQX_OUT_OF_MEMORY);
        return (MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(mutex_component_ptr, MEM_TYPE_MUTEX_COMPONENT);
#endif /* MQX_LITE_VERSION_NUMBER */

    _QUEUE_INIT(&mutex_component_ptr->MUTEXES, 0);
    mutex_component_ptr->VALID = MUTEX_VALID;

    _int_disable();

#if MQX_CHECK_ERRORS
    if (kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES] != NULL)
    {
        _int_enable();
#if !MQX_LITE_VERSION_NUMBER
        _mem_free(mutex_component_ptr);
#endif /* MQX_LITE_VERSION_NUMBER */
        _KLOGX2(KLOG_mutex_create_component, MQX_OK);
        return (MQX_OK);
    } /* Endif */
#endif

    kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES] = mutex_component_ptr;

#if MQX_COMPONENT_DESTRUCTION
    kernel_data->COMPONENT_CLEANUP[KERNEL_MUTEXES] = _mutex_cleanup;
#endif

    _int_enable();

    _KLOGX2(KLOG_mutex_create_component, MQX_OK);
    return (MQX_OK);

} /* Endbody */

/*!
 * \brief Deinitializes the mutex attributes structure.
 *
 * To reuse the mutex attributes structure, a task must reinitialize the structure.
 *
 * \param[in] attr_ptr Pointer to the mutex attributes structure; initialized
 * with _mutatr_init().
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
 *
 * \see _mutatr_init
 * \see MUTEX_ATTR_STRUCT
 */
_mqx_uint _mutatr_destroy
(
    MUTEX_ATTR_STRUCT_PTR attr_ptr
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE2(KLOG_mutatr_destroy, attr_ptr);

#if MQX_CHECK_ERRORS
    if (attr_ptr == NULL)
    {
        _KLOGX2(KLOG_mutatr_destroy, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (attr_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutatr_destroy, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

    attr_ptr->VALID = 0;

    _KLOGX2(KLOG_mutatr_destroy, MQX_EOK);
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Deinitializes the mutex.
 *
 * To reuse the mutex after it is destroyed, a task must reinitialize it with _mutex_create().
 *
 * \param[in] mutex_ptr Pointer to the mutex to be deinitialized.
 *
 * \return MQX_EOK
 * \return MQX_COMPONENT_DOES_NOT_EXIST
 * \return MQX_INVALID_COMPONENT_BASE (Mutex component data is not valid.)
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (From _mutex_lock: function cannot
 * be called from an ISR.)
 * \return MQX_EINVAL (From _mutex_lock: mutex_ptr was destroyed or is NULL.)
 * \return MQX_EDEADLK (From _mutex_lock: task already has the mutex locked.)
 * \return MQX_EBUSY (From _mutex_lock: mutex is already locked.)
 *
 * \warning Puts in their ready queues all tasks that are waiting for the mutex;
 * their call to _mutex_lock() returns MQX_EINVAL.
 *
 * \see _mutex_init
 * \see MUTEX_STRUCT
 */
_mqx_uint _mutex_destroy
(
    register MUTEX_STRUCT_PTR mutex_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR     kernel_data;
    MUTEX_COMPONENT_STRUCT_PTR mutex_component_ptr;
    TD_STRUCT_PTR              td_ptr;
    _mqx_uint                  result;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_mutex_destroy, mutex_ptr);

#if MQX_CHECK_ERRORS
    if (kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES] == NULL)
    {
        _KLOGX2(KLOG_mutex_destroy, MQX_COMPONENT_DOES_NOT_EXIST);
        return (MQX_COMPONENT_DOES_NOT_EXIST);
    } /* Endif */
#endif

    mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES];

#if MQX_CHECK_VALIDITY
    if (mutex_component_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutex_destroy, MQX_INVALID_COMPONENT_BASE);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    td_ptr = kernel_data->ACTIVE_PTR;

    if (mutex_ptr->OWNER_TD != td_ptr)
    {
        result = _mutex_lock(mutex_ptr); /* Get the mutex */
        if (result != MQX_EOK)
        {
            _KLOGX2(KLOG_mutex_destroy, result);
            return (result);
        } /* Endif */
    } /* Endif */

    mutex_ptr->VALID = 0;

    if (mutex_ptr->LINK.NEXT != NULL)
    {
        /* Remove mutex from the queue of mutexes in the kernel */
        _int_disable();
        _QUEUE_REMOVE(&mutex_component_ptr->MUTEXES, mutex_ptr);
        _int_enable();
    } /* Endif */

    /* Get rid of all waiting tasks */
    while (_QUEUE_GET_SIZE(&mutex_ptr->WAITING_TASKS))
    {
        _QUEUE_DEQUEUE(&mutex_ptr->WAITING_TASKS, td_ptr);
        _task_set_error_td_internal(td_ptr, MQX_EINVAL);
        _int_disable();
        _TASK_READY(td_ptr,kernel_data);
        _int_enable();
    } /* Endwhile */

    td_ptr = kernel_data->ACTIVE_PTR;

    _int_disable();
    if (mutex_ptr->BOOSTED)
    {
        _sched_unboost_priority_internal(td_ptr, mutex_ptr->BOOSTED);
    } /* Endif */

    _int_enable();

    _CHECK_RUN_SCHEDULER(); /* Let higher priority task run */

    _KLOGX2(KLOG_mutex_destroy, MQX_EOK);
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Gets the waiting policy of the mutex attributes structure.
 *
 * \param[in]  attr_ptr             Pointer to an initialized mutex attributes
 * structure.
 * \param[out] waiting_protocol_ptr Pointer to the current waiting protocol.
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attribute structure.)
 *
 * \see _mutatr_set_wait_protocol
 * \see _mutatr_init
 * \see _mutatr_get_spin_limit
 * \see _mutatr_set_spin_limit
 * \see MUTEX_ATTR_STRUCT
 */
_mqx_uint _mutatr_get_wait_protocol
(
    MUTEX_ATTR_STRUCT_PTR attr_ptr,
    _mqx_uint_ptr         waiting_protocol_ptr
)
{ /* Body */

#if MQX_CHECK_ERRORS
    if ((attr_ptr == NULL) || (waiting_protocol_ptr == NULL))
    {
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (attr_ptr->VALID != MUTEX_VALID)
    {
        return (MQX_EINVAL);
    } /* Endif */
#endif

    *waiting_protocol_ptr = attr_ptr->WAIT_PROTOCOL;
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Gets the priority ceiling from a mutex attributes structure.
 *
 * Priority applies only to mutexes whose scheduling protocol is priority protect.
 *
 * \param[in]  attr_ptr    Pointer to an initialized mutex attributes structure.
 * \param[out] ceiling_ptr Pointer to the current priority.
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
 *
 * \see _mutatr_set_priority_ceiling
 * \see _mutatr_init
 * \see MUTEX_ATTR_STRUCT
 */
_mqx_uint _mutatr_get_priority_ceiling
(
    MUTEX_ATTR_STRUCT_PTR attr_ptr,
    _mqx_uint_ptr         ceiling_ptr
)
{ /* Body */

#if MQX_CHECK_ERRORS
    if ((attr_ptr == NULL) || (ceiling_ptr == NULL))
    {
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (attr_ptr->VALID != MUTEX_VALID)
    {
        return (MQX_EINVAL);
    } /* Endif */
#endif

    *ceiling_ptr = attr_ptr->PRIORITY_CEILING;
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Gets the scheduling protocol of the mutex attributes structure.
 *
 * \param[in]  attr_ptr     Pointer to an initialized mutex attributes structure.
 * \param[out] protocol_ptr Pointer to the current scheduling protocol.
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
 *
 * \see _mutatr_set_sched_protocol
 * \see _mutatr_init
 * \see _mutatr_get_priority_ceiling
 * \see _mutatr_set_priority_ceiling
 * \see MUTEX_ATTR_STRUCT
 */
_mqx_uint _mutatr_get_sched_protocol
(
    MUTEX_ATTR_STRUCT_PTR attr_ptr,
    _mqx_uint_ptr         protocol_ptr
)
{ /* Body */

#if MQX_CHECK_ERRORS
    if ((attr_ptr == NULL) || (protocol_ptr == NULL))
    {
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (attr_ptr->VALID != MUTEX_VALID)
    {
        return (MQX_EINVAL);
    } /* Endif */
#endif

    *protocol_ptr = attr_ptr->SCHED_PROTOCOL;
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Gets the spin limit of the mutex attributes structure.
 *
 * Spin limit applies only to mutexes whose waiting policy is limited spin. Spin
 * limit is the number of times that a task spins (is rescheduled) while it waits
 * for the mutex.
 *
 * \param[in]  attr_ptr       Pointer to an initialized mutex attributes structure.
 * \param[out] spin_count_ptr Pointer to the current spin limit.
 *
 * \return MQX_OK
 * \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
 *
 * \see _mutatr_set_spin_limit
 * \see _mutatr_init
 * \see _mutatr_get_wait_protocol
 * \see _mutatr_set_wait_protocol
 * \see MUTEX_ATTR_STRUCT
 */
_mqx_uint _mutatr_get_spin_limit
(
    MUTEX_ATTR_STRUCT_PTR attr_ptr,
    _mqx_uint_ptr         spin_count_ptr
)
{ /* Body */

#if MQX_CHECK_ERRORS
    if ((attr_ptr == NULL) || (spin_count_ptr == NULL))
    {
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (attr_ptr->VALID != MUTEX_VALID)
    {
        return (MQX_EINVAL);
    } /* Endif */
#endif

    *spin_count_ptr = attr_ptr->COUNT;
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Initializes the mutex.
 *
 * \param[in] mutex_ptr Pointer to where the mutex is to be initialized.
 * \param[in] attr_ptr  Pointer to an initialized mutex attributes structure or
 * NULL (use default attributes as defined for _mutatr_init()).
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (Mutex_ptr is NULL, attr_ptr is not initialized or a value
 * in attr_ptr is not correct.)
 * \return MQX_INVALID_COMPONENT_BASE (Mutex component data is not valid.)
 * \return MQX_OUT_OF_MEMORY
 *
 * \warning Creates the mutex component if it was not previously created.
 *
 * \see _mutex_destroy
 * \see _mutatr_init
 * \see MUTEX_STRUCT
 * \see MUTEX_ATTR_STRUCT
 */
_mqx_uint _mutex_init
(
    register MUTEX_STRUCT_PTR      mutex_ptr,
    register MUTEX_ATTR_STRUCT_PTR attr_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR     kernel_data;
    MUTEX_COMPONENT_STRUCT_PTR mutex_component_ptr;
    MUTEX_ATTR_STRUCT          default_attr;
#if MQX_CHECK_ERRORS
    MUTEX_STRUCT_PTR           mutex_chk_ptr;
#endif
    _mqx_uint                  result;

    _GET_KERNEL_DATA(kernel_data);
    if (attr_ptr == NULL)
    {
        attr_ptr = &default_attr;
        _mutatr_init(attr_ptr);
        _KLOGE3(KLOG_mutex_init, mutex_ptr, NULL);
    }
    else
    {
        _KLOGE3(KLOG_mutex_init, mutex_ptr, attr_ptr);
    } /* Endif */

#if MQX_CHECK_ERRORS
    if (mutex_ptr == NULL)
    {
        _KLOGX2(KLOG_mutex_init, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (attr_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutex_init, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

    mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES];
    if (mutex_component_ptr == NULL)
    {
        result = _mutex_create_component();
        mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES];
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
        if (mutex_component_ptr == NULL)
        {
            _KLOGX2(KLOG_mutex_init, result);
            return (result);
        } /* Endif */
#endif
    } /* Endif */

#if MQX_CHECK_VALIDITY
    if (mutex_component_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutex_init, MQX_INVALID_COMPONENT_BASE);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    _int_disable();
#if MQX_CHECK_ERRORS
    /* Check if mutex is already initialized */
    mutex_chk_ptr = (MUTEX_STRUCT_PTR) ((void *) mutex_component_ptr->MUTEXES.NEXT);
    while (mutex_chk_ptr != (MUTEX_STRUCT_PTR) ((void *) &mutex_component_ptr->MUTEXES))
    {
        if (mutex_chk_ptr == mutex_ptr)
        {
            _int_enable();
            _KLOGX2(KLOG_mutex_init, MQX_EINVAL);
            return (MQX_EINVAL);
        } /* Endif */
        mutex_chk_ptr = (MUTEX_STRUCT_PTR) ((void *) mutex_chk_ptr->LINK.NEXT);
    } /* Endif */
#endif

    mutex_ptr->PROTOCOLS = attr_ptr->SCHED_PROTOCOL | attr_ptr->WAIT_PROTOCOL;
    mutex_ptr->VALID            = MUTEX_VALID;
    mutex_ptr->COUNT            = attr_ptr->COUNT;
    mutex_ptr->PRIORITY_CEILING = attr_ptr->PRIORITY_CEILING;
    mutex_ptr->LOCK             = 0;
    mutex_ptr->BOOSTED          = 0;
    mutex_ptr->OWNER_TD         = NULL;
    _QUEUE_INIT(&mutex_ptr->WAITING_TASKS, 0);

    _QUEUE_ENQUEUE(&mutex_component_ptr->MUTEXES, mutex_ptr);
    _int_enable();

    _KLOGX2(KLOG_mutex_init, MQX_EOK);
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Locks the mutex.
 *
 * If the mutex is already locked, the task waits according to the waiting protocol
 * of the mutex.
 *
 * \param[in] mutex_ptr Pointer to the mutex to be locked.
 *
 * \return MQX_EOK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_EINVAL (Mutex_ptr is NULL or mutex was destroyed.)
 * \return MQX_EDEADLK (Task already has the mutex locked.)
 * \return MQX_EBUSY (Mutex is already locked.)
 *
 * \warning Might block the calling task.
 * \warning Cannot be called from an ISR.
 *
 * \see _mutex_init
 * \see _mutex_try_lock
 * \see _mutex_unlock
 * \see _mutatr_init
 * \see _mutatr_get_wait_protocol
 * \see _mutatr_set_wait_protocol
 * \see _mutex_destroy
 * \see MUTEX_STRUCT
 */
_mqx_uint _mutex_lock
(
    register MUTEX_STRUCT_PTR mutex_ptr
)
{ /* Body */
    register KERNEL_DATA_STRUCT_PTR kernel_data;
    register TD_STRUCT_PTR          td_ptr;
    volatile unsigned char                 *lock_ptr;
    _mqx_uint                       priority;
    _mqx_uint                       count;
#if MQX_MUTEX_HAS_POLLING
    _mqx_uint                       limited;
#endif

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_mutex_lock, mutex_ptr);

    td_ptr = kernel_data->ACTIVE_PTR;

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_mutex_lock, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    } /* Endif */
    if (mutex_ptr == NULL)
    {
        _KLOGX2(KLOG_mutex_lock, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (mutex_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutex_lock, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

    if (mutex_ptr->OWNER_TD == (void *) td_ptr)
    {
        _KLOGX2(KLOG_mutex_lock, MQX_EDEADLK);
        return (MQX_EDEADLK);
    } /* Endif */

    priority = td_ptr->MY_QUEUE->PRIORITY;
    lock_ptr = &mutex_ptr->LOCK;

#if MQX_MUTEX_HAS_POLLING
    if ((mutex_ptr->PROTOCOLS & MUTEX_SPIN_ONLY) ||
        (mutex_ptr->PROTOCOLS & MUTEX_LIMITED_SPIN))
    {

        if (mutex_ptr->PROTOCOLS & MUTEX_SPIN_ONLY)
        {
            count = 1;
            limited = 0;
        }
        else
        {
            count = mutex_ptr->COUNT;
            limited = 1;
        } /* Endif */
        if (mutex_ptr->PROTOCOLS & MUTEX_PRIO_INHERIT)
        {

            _INT_DISABLE();
            while (count && *lock_ptr)
            {
                count -= limited;
                if (((TD_STRUCT_PTR)(mutex_ptr->OWNER_TD))->HOME_QUEUE->PRIORITY >
                    priority)
                {
                    if (((TD_STRUCT_PTR)(mutex_ptr->OWNER_TD))->MY_QUEUE->PRIORITY >
                        priority)
                    {
                        _sched_boost_priority_internal(
                                        (TD_STRUCT_PTR)mutex_ptr->OWNER_TD, priority);
                    } /* Endif */
                    mutex_ptr->BOOSTED++;
                } /* Endif */
                _INT_ENABLE(); /* Allow interruption and tasks of same prio a kick*/
                _sched_yield();
                _INT_DISABLE();
#if MQX_COMPONENT_DESTRUCTION
                if (mutex_ptr->VALID != MUTEX_VALID)
                {
                    _int_enable();
                    _KLOGX2(KLOG_mutex_lock, MQX_EINVAL);
                    return(MQX_EINVAL);
                } /* Endif */
#endif
            } /* Endwhile */
            if (count)
            {
                /* Test and set sets the high bit. */
                mutex_ptr->LOCK = MQX_TEST_AND_SET_VALUE;
            } /* Endif */
            _INT_ENABLE();

        }
        else
        {

            while (count && _mem_test_and_set((unsigned char *)lock_ptr))
            {
                count -= limited;
                _sched_yield();
#if MQX_COMPONENT_DESTRUCTION
                if (mutex_ptr->VALID != MUTEX_VALID)
                {
                    _KLOGX2(KLOG_mutex_lock, MQX_EINVAL);
                    return(MQX_EINVAL);
                } /* Endif */
#endif
            } /* Endwhile */

        } /* Endif */

        if (count == 0)
        {
            _KLOGX2(KLOG_mutex_lock, MQX_EBUSY);
            return(MQX_EBUSY);
        } /* Endif */
        mutex_ptr->OWNER_TD = td_ptr;

    }
    else
    {

#endif

    _INT_DISABLE();
    if (*lock_ptr)
    {
        /* Must wait for a mutex to become available */

        /* Boost the priority of the owner task if necessary */
        if (mutex_ptr->PROTOCOLS & MUTEX_PRIO_INHERIT) {
            if (((TD_STRUCT_PTR) (mutex_ptr->OWNER_TD))->HOME_QUEUE->PRIORITY > priority)
            {
                if (((TD_STRUCT_PTR) (mutex_ptr->OWNER_TD))->MY_QUEUE->PRIORITY > priority)
                {
                    _sched_boost_priority_internal((TD_STRUCT_PTR) mutex_ptr->OWNER_TD, priority);
                } /* Endif */
                mutex_ptr->BOOSTED++;
            } /* Endif */
        } /* Endif */

        _QUEUE_UNLINK(td_ptr); /* Remove from ready to run queue */
        td_ptr->INFO = (_mqx_uint) &mutex_ptr->WAITING_TASKS;
        if (mutex_ptr->PROTOCOLS & MUTEX_PRIORITY_QUEUEING)
        {
            /*
             ** The waiting task must be inserted into the waiting list in order
             ** of the priority of the waiting task.
             */
            _sched_insert_priorityq_internal(&mutex_ptr->WAITING_TASKS, td_ptr);
        }
        else
        {
            /* Enqueue at end */
            _QUEUE_ENQUEUE(&mutex_ptr->WAITING_TASKS, td_ptr);
        } /* Endif */

        /* Now put the task to sleep */
        td_ptr->STATE = MUTEX_BLOCKED;
        _sched_execute_scheduler_internal();

        /* If mutex alive, then active task owns it now, (done by unlock) */
#if MQX_COMPONENT_DESTRUCTION
        if (mutex_ptr->VALID != MUTEX_VALID)
        {
            _int_enable();
            _KLOGX2(KLOG_mutex_lock, MQX_EINVAL);
            return (MQX_EINVAL);
        } /* Endif */
#endif

    }
    else
    {
        /* Test and set sets the high bit. */
        mutex_ptr->LOCK = MQX_TEST_AND_SET_VALUE;
        mutex_ptr->OWNER_TD = td_ptr;
    } /* Endif */

    /*
     * This task now owns the mutex, if priority inheritance is in effect
     * the queue of waiting tasks must be checked for any task which may
     * have a higher priority than mine ONLY if priority queueing is NOT
     * in effect
     */
    if ((mutex_ptr->PROTOCOLS & MUTEX_PRIO_INHERIT) && !(mutex_ptr->PROTOCOLS & MUTEX_PRIORITY_QUEUEING))
    {
        count = _sched_get_max_priority_on_q_internal(&mutex_ptr->WAITING_TASKS);
        if (count < td_ptr->HOME_QUEUE->PRIORITY)
        {
            if (count < td_ptr->MY_QUEUE->PRIORITY)
            {
                _sched_boost_priority_internal(td_ptr, count);
            } /* Endif */
            mutex_ptr->BOOSTED++;
        } /* Endif */
    } /* Endif */
    _INT_ENABLE();

#if MQX_MUTEX_HAS_POLLING
} /* Endif */
#endif

    if (mutex_ptr->PROTOCOLS & MUTEX_PRIO_PROTECT)
    {
        /* Switch my priority to the higher one if necessary */
        _INT_DISABLE();
        if (mutex_ptr->PRIORITY_CEILING < td_ptr->HOME_QUEUE->PRIORITY)
        {
            if (mutex_ptr->PRIORITY_CEILING < td_ptr->MY_QUEUE->PRIORITY)
            {
                _sched_boost_priority_internal(td_ptr, mutex_ptr->PRIORITY_CEILING);
            } /* Endif */
            mutex_ptr->BOOSTED++;
        } /* Endif */
        _INT_ENABLE();
    } /* Endif */

    _KLOGX2(KLOG_mutex_lock, MQX_EOK);
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Sets the waiting policy of the mutex attributes structure.
 *
 * \param[in] attr_ptr         Pointer to an initialized mutex attributes structure.
 * \param[in] waiting_protocol New waiting protocol (see waiting protocols).
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attribute structure.)
 *
 * \see _mutatr_get_wait_protocol
 * \see _mutatr_init
 * \see _mutatr_get_spin_limit
 * \see _mutatr_set_spin_limit
 * \see MUTEX_ATTR_STRUCT
 */
_mqx_uint _mutatr_set_wait_protocol
(
    MUTEX_ATTR_STRUCT_PTR attr_ptr,
    _mqx_uint             waiting_protocol
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE3(KLOG_mutatr_set_wait_protocol, attr_ptr, waiting_protocol);

#if MQX_CHECK_ERRORS
    if (attr_ptr == NULL)
    {
        _KLOGX2(KLOG_mutatr_set_wait_protocol, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (attr_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutatr_set_wait_protocol, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_ERRORS
    /* Validate input value */
    if (!(
#if MQX_MUTEX_HAS_POLLING
    (waiting_protocol == MUTEX_SPIN_ONLY) ||
    (waiting_protocol == MUTEX_LIMITED_SPIN) ||
#endif
    (waiting_protocol == MUTEX_QUEUEING) || (waiting_protocol == MUTEX_PRIORITY_QUEUEING)))
    {
        _KLOGX2(KLOG_mutatr_set_wait_protocol, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

    attr_ptr->WAIT_PROTOCOL = waiting_protocol;

    _KLOGX2(KLOG_mutatr_set_wait_protocol, MQX_EOK);
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Sets the priority ceiling of a mutex attributes structure.
 *
 * Priority applies only to mutexes whose scheduling protocol is priority protect.
 *
 * \param[in] attr_ptr Pointer to an initialized mutex attributes structure.
 * \param[in] ceiling New priority ceiling to use.
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attribute structure.)
 *
 * \see _mutatr_get_priority_ceiling
 * \see _mutatr_init
 * \see MUTEX_ATTR_STRUCT
 */
_mqx_uint _mutatr_set_priority_ceiling
(
    MUTEX_ATTR_STRUCT_PTR attr_ptr,
    _mqx_uint             ceiling
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_mutatr_set_priority_ceiling, attr_ptr, ceiling);

#if MQX_CHECK_ERRORS
    if (attr_ptr == NULL)
    {
        _KLOGX2(KLOG_mutatr_set_priority_ceiling, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (attr_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutatr_set_priority_ceiling, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_ERRORS
    if (ceiling > kernel_data->LOWEST_TASK_PRIORITY)
    {
        _KLOGX2(KLOG_mutatr_set_priority_ceiling, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

    attr_ptr->PRIORITY_CEILING = ceiling;

    _KLOGX2(KLOG_mutatr_set_priority_ceiling, MQX_EOK);
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Sets the scheduling protocol of the mutex attributes structure.
 *
 * \param[in] attr_ptr Pointer to an initialized mutex attributes structure.
 * \param[in] protocol New scheduling protocol (see scheduling protocols).
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
 *
 * \see _mutatr_get_sched_protocol
 * \see _mutatr_init
 * \see _mutatr_get_priority_ceiling
 * \see _mutatr_set_priority_ceiling
 * \see MUTEX_ATTR_STRUCT
 */
_mqx_uint _mutatr_set_sched_protocol
(
    MUTEX_ATTR_STRUCT_PTR attr_ptr,
    _mqx_uint             protocol
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE3(KLOG_mutatr_set_sched_protocol, attr_ptr, protocol);

#if MQX_CHECK_ERRORS
    if (attr_ptr == NULL)
    {
        _KLOGX2(KLOG_mutatr_set_sched_protocol, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (attr_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutatr_set_sched_protocol, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_ERRORS
    /* Validate protocol value */
    if (!((protocol == MUTEX_PRIO_INHERIT) || (protocol == MUTEX_PRIO_PROTECT) || (protocol == MUTEX_NO_PRIO_INHERIT)))
    {
        _KLOGX2(KLOG_mutatr_set_sched_protocol, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

    attr_ptr->SCHED_PROTOCOL = protocol;

    _KLOGX2(KLOG_mutatr_set_sched_protocol, MQX_EOK);
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Sets the spin limit of the mutex attributes structure.
 *
 * Spin limit applies only to mutexes whose waiting policy is limited spin. Spin
 * limit is the number of times that a task spins (is rescheduled) while it waits
 * for the mutex.
 *
 * \param[in] attr_ptr Pointer to an initialized mutex attributes structure.
 * \param[in] spin_count New spin limit.
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (attr_ptr is NULL or points to an invalid attributes structure.)
 *
 * \see _mutatr_get_spin_limit
 * \see _mutatr_init
 * \see _mutatr_get_wait_protocol
 * \see _mutatr_set_wait_protocol
 * \see MUTEX_ATTR_STRUCT
 */
_mqx_uint _mutatr_set_spin_limit
(
    MUTEX_ATTR_STRUCT_PTR attr_ptr,
    _mqx_uint             spin_count
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE3(KLOG_mutatr_set_spin_limit, attr_ptr, spin_count);

#if MQX_MUTEX_HAS_POLLING
#if MQX_CHECK_ERRORS
    if (attr_ptr == NULL)
    {
        _KLOGX2(KLOG_mutatr_set_spin_limit, MQX_EINVAL);
        return(MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (attr_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutatr_set_spin_limit, MQX_EINVAL);
        return(MQX_EINVAL);
    } /* Endif */
#endif

    attr_ptr->COUNT = spin_count;

    _KLOGX2(KLOG_mutatr_set_spin_limit, MQX_EOK);
    return(MQX_EOK);
#else
    _KLOGX2(KLOG_mutatr_set_spin_limit, MQX_EINVAL);
    return (MQX_EINVAL);
#endif

} /* Endbody */

/*!
 * \brief Used during task destruction to free up any mutex owned by this task.
 *
 * \param[in] td_ptr Pointer to the task descriptor of the task to be destroyed.
 *
 * \see mutex_destroy
 */
void _mutex_cleanup
(
    TD_STRUCT_PTR td_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR     kernel_data;
    MUTEX_COMPONENT_STRUCT_PTR mutex_component_ptr;
    MUTEX_STRUCT_PTR           mutex_ptr;

    _GET_KERNEL_DATA(kernel_data);

    mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES];
    if (mutex_component_ptr == NULL)
    {
        return; /* No work to do! */
    } /* Endif */

#if MQX_CHECK_VALIDITY
    if (mutex_component_ptr->VALID != MUTEX_VALID)
    {
        return;
    } /* Endif */
#endif

    _int_disable();
    mutex_ptr = (MUTEX_STRUCT_PTR) ((void *) mutex_component_ptr->MUTEXES.NEXT);
    while (mutex_ptr != (MUTEX_STRUCT_PTR) ((void *) &mutex_component_ptr->MUTEXES))
    {
        if ((mutex_ptr->LOCK) && (mutex_ptr->OWNER_TD == td_ptr))
        {
            mutex_ptr->OWNER_TD = kernel_data->ACTIVE_PTR;
            _mutex_unlock(mutex_ptr);
            mutex_ptr = (MUTEX_STRUCT_PTR) ((void *) mutex_component_ptr->MUTEXES.NEXT);
        }
        else
        {
            mutex_ptr = (MUTEX_STRUCT_PTR) ((void *) mutex_ptr->LINK.NEXT);
        } /* Endif */
    } /* Endwhile */
    _int_enable();

} /* Endbody */

/*!
 * \brief Tests the mutex component.
 *
 * This function tests:
 * \n - mutex component data
 * \n - MQX queue of mutexes
 * \n - each mutex
 * \n - waiting queue of each mutex
 *
 * \param[out] mutex_error_ptr Pointer to the invalid queue or to the mutex with the
 * error (see return).
 *
 * \return MQX_OK No errors were found (mutex_error_ptr = NULL).
 * \return MQX_INVALID_COMPONENT_BASE Mutex component data is not valid (mutex_error_ptr
 * = NULL).
 * \return MQX_EINVAL A mutex is not valid or a mutex queue is not valid (mutex_error_ptr
 * = pointer to the mutex with the error).
 * \return MQX_CORRUPT_QUEUE Queue of mutexes is not valid (mutex_error_ptr = pointer
 * to the invalid queue).
 *
 * \see _mutex_create_component
 * \see _mutex_init
 */
_mqx_uint _mutex_test
(
    void    **mutex_error_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR     kernel_data;
    MUTEX_COMPONENT_STRUCT_PTR mutex_component_ptr;
    MUTEX_STRUCT_PTR           mutex_ptr;
    _mqx_uint                  result;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_mutex_test, mutex_error_ptr);

    *mutex_error_ptr = NULL;

    mutex_component_ptr = (MUTEX_COMPONENT_STRUCT_PTR) kernel_data->KERNEL_COMPONENTS[KERNEL_MUTEXES];
    if (mutex_component_ptr == NULL)
    {
        _KLOGX2(KLOG_mutex_test, MQX_OK);
        return (MQX_OK);
    } /* Endif */

    if (mutex_component_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutex_test, MQX_INVALID_COMPONENT_BASE);
        return (MQX_INVALID_COMPONENT_BASE);
    } /* Endif */

    _int_disable();

    /* Make sure that the queue of mutexes is ok */
    result = _queue_test(&mutex_component_ptr->MUTEXES, mutex_error_ptr);
    if (result != MQX_OK)
    {
        _int_enable();
        _KLOGX3(KLOG_mutex_test, result, *mutex_error_ptr);
        return (result);
    } /* Endif */

    mutex_ptr = (MUTEX_STRUCT_PTR) ((void *) mutex_component_ptr->MUTEXES.NEXT);
    while (mutex_ptr != (MUTEX_STRUCT_PTR) ((void *) &mutex_component_ptr->MUTEXES))
    {
        if (mutex_ptr->VALID != MUTEX_VALID)
        {
            _int_enable();
            *mutex_error_ptr = mutex_ptr;
            _KLOGX3(KLOG_mutex_test, MQX_EINVAL, mutex_ptr);
            return (MQX_EINVAL);
        } /* Endif */
        result = _queue_test(&mutex_ptr->WAITING_TASKS, mutex_error_ptr);
        if (result != MQX_OK)
        {
            _int_enable();
            *mutex_error_ptr = mutex_ptr;
            _KLOGX3(KLOG_mutex_test, result, mutex_ptr);
            return (result);
        } /* Endif */
        mutex_ptr = (MUTEX_STRUCT_PTR) ((void *) mutex_ptr->LINK.NEXT);
    } /* Endif */

    _int_enable();

    _KLOGX2(KLOG_mutex_test, MQX_OK);
    return (MQX_OK);

} /* Endbody */

/*!
 * \brief Tries to lock the mutex.
 *
 * If the mutex is not currently locked, the task locks it. If the mutex is currently
 * locked, the task continues to run; it does not block.
 *
 * \param[in] mutex_ptr Pointer to the mutex.
 *
 * \return MQX_EOK
 * \return MQX_EBUSY (Mutex is currently locked.)
 * \return MQX_EDEADLK (Task already has the mutex locked.)
 * \return MQX_EINVAL (Mutex_ptr is NULL or mutex has been destroyed.)
 *
 * \see _mutex_create_component
 * \see _mutex_init
 * \see _mutex_lock
 * \see _mutex_unlock
 * \see _mutatr_init
 * \see MUTEX_STRUCT
 */
_mqx_uint _mutex_try_lock
(
    register MUTEX_STRUCT_PTR mutex_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;
    TD_STRUCT_PTR          td_ptr;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_mutex_try_lock, mutex_ptr);

#if MQX_CHECK_ERRORS
    if (mutex_ptr == NULL)
    {
        _KLOGX2(KLOG_mutex_try_lock, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (mutex_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutex_try_lock, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

    _INT_DISABLE();
    if (_mem_test_and_set(&mutex_ptr->LOCK))
    {
        _INT_ENABLE();
        /* Lock value was set, can't have it */
        if (mutex_ptr->OWNER_TD == (void *) kernel_data->ACTIVE_PTR)
        {
            _KLOGX2(KLOG_mutex_try_lock, MQX_EDEADLK);
            return (MQX_EDEADLK);
        }
        else
        {
            _KLOGX2(KLOG_mutex_try_lock, MQX_EBUSY);
            return (MQX_EBUSY);
        } /* Endif */
    }
    else
    {
        /* Lock value was not set, now it is, I own it */
        mutex_ptr->OWNER_TD = kernel_data->ACTIVE_PTR;
        _INT_ENABLE();

        if (mutex_ptr->PROTOCOLS & MUTEX_PRIO_PROTECT)
        {
            /* Switch my priority to the higher one if necessary */
            td_ptr = kernel_data->ACTIVE_PTR;
            _INT_DISABLE();
            if (mutex_ptr->PRIORITY_CEILING < td_ptr->HOME_QUEUE->PRIORITY)
            {
                if (mutex_ptr->PRIORITY_CEILING < td_ptr->MY_QUEUE->PRIORITY)
                {
                    _sched_boost_priority_internal(td_ptr, mutex_ptr->PRIORITY_CEILING);
                } /* Endif */
                mutex_ptr->BOOSTED++;
            } /* Endif */
            _INT_ENABLE();
        } /* Endif */

        _KLOGX2(KLOG_mutex_try_lock, MQX_EOK);
        return (MQX_EOK);
    } /* Endif */

} /* Endbody */

/*!
 * \brief Unlocks the mutex.
 *
 * If tasks are waiting for the mutex, MQX removes the first one from the mutex
 * queue and puts the task in the task's ready queue.
 *
 * \param[in] mutex_ptr Pointer to the mutex.
 *
 * \return MQX_EOK
 * \return MQX_EINVAL
 *
 * \warning Might put a task in the task's ready queue.
 *
 * \see _mutex_create_component
 * \see _mutex_init
 * \see _mutex_lock
 * \see _mutex_try_lock
 * \see _mutatr_init
 * \see MUTEX_STRUCT
 */
_mqx_uint _mutex_unlock
(
    register MUTEX_STRUCT_PTR mutex_ptr
)
{ /* Body */
    register KERNEL_DATA_STRUCT_PTR kernel_data;
    register TD_STRUCT_PTR          td_ptr;
    _mqx_uint                       boosted;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_mutex_unlock, mutex_ptr);

    td_ptr = kernel_data->ACTIVE_PTR;

#if MQX_CHECK_ERRORS
    if (mutex_ptr == NULL)
    {
        _KLOGX2(KLOG_mutex_unlock, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (mutex_ptr->VALID != MUTEX_VALID)
    {
        _KLOGX2(KLOG_mutex_unlock, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

#if MQX_CHECK_ERRORS
    if (mutex_ptr->LOCK != MQX_TEST_AND_SET_VALUE)
    {
        _KLOGX2(KLOG_mutex_unlock, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
    if (mutex_ptr->OWNER_TD != (void *) td_ptr)
    {
        _KLOGX2(KLOG_mutex_unlock, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

    _INT_DISABLE();
    boosted = mutex_ptr->BOOSTED;
    mutex_ptr->BOOSTED = 0;

    if (mutex_ptr->PROTOCOLS & (MUTEX_SPIN_ONLY | MUTEX_LIMITED_SPIN))
    {
        mutex_ptr->OWNER_TD = NULL;
        mutex_ptr->LOCK = 0;
    }
    else
    {

        if (_QUEUE_GET_SIZE(&mutex_ptr->WAITING_TASKS))
        {

            /* Schedule a waiting task to run */
            _QUEUE_DEQUEUE(&mutex_ptr->WAITING_TASKS, td_ptr);
            mutex_ptr->OWNER_TD = td_ptr;
            _TASK_READY(td_ptr, kernel_data);
            if (mutex_ptr->PROTOCOLS & MUTEX_PRIO_PROTECT)
            {
                /* Switch priority to the higher one if necessary */
                if (mutex_ptr->PRIORITY_CEILING < td_ptr->HOME_QUEUE->PRIORITY)
                {
                    if (mutex_ptr->PRIORITY_CEILING < td_ptr->MY_QUEUE->PRIORITY)
                    {
                        _sched_boost_priority_internal(td_ptr, mutex_ptr->PRIORITY_CEILING);
                    } /* Endif */
                    mutex_ptr->BOOSTED++;
                } /* Endif */
            } /* Endif */

            _CHECK_RUN_SCHEDULER();/* Let higher priority task run */

        }
        else
        {
            mutex_ptr->LOCK = 0;
            mutex_ptr->OWNER_TD = NULL;
        } /* Endif */

    } /* Endif */

    if (boosted)
    {
        _sched_unboost_priority_internal(kernel_data->ACTIVE_PTR, boosted);
    } /* Endif */
    _INT_ENABLE();

    _KLOGX2(KLOG_mutex_unlock, MQX_EOK);
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Sets the priority of the mutex.
 *
 * This function operate on an initialized mutex; whereas, _mutatr_get_priority_ceiling()
 * and _mutatr_set_priority_ceiling() operate on an initialized mutex attributes
 * structure.
 *
 * \param[in]  mutex_ptr       Pointer to the mutex.
 * \param[in]  ceiling         New priority ceiling.
 * \param[out] old_ceiling_ptr Pointer to the previous priority ceiling.
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (Mutex_ptr does not point to a valid mutex structure or
 * priority_ptr is NULL)
 *
 * \see _mutex_get_priority_ceiling
 * \see _mutex_init
 * \see MUTEX_STRUCT
 */
_mqx_uint _mutex_set_priority_ceiling
(
    MUTEX_STRUCT_PTR mutex_ptr,
    _mqx_uint        ceiling,
    _mqx_uint_ptr    old_ceiling_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;

    _GET_KERNEL_DATA(kernel_data);
    _KLOGE4(KLOG_mutex_set_priority_ceiling, mutex_ptr, ceiling, old_ceiling_ptr);

#if MQX_CHECK_ERRORS
    if (ceiling > kernel_data->LOWEST_TASK_PRIORITY)
    {
        _KLOGX2(KLOG_mutex_set_priority_ceiling, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

    _int_disable();

#if MQX_CHECK_ERRORS
    if ((mutex_ptr == NULL) || (old_ceiling_ptr == NULL))
    {
        _int_enable();
        _KLOGX2(KLOG_mutex_set_priority_ceiling, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (mutex_ptr->VALID != MUTEX_VALID)
    {
        _int_enable();
        _KLOGX2(KLOG_mutex_set_priority_ceiling, MQX_EINVAL);
        return (MQX_EINVAL);
    } /* Endif */
#endif

    *old_ceiling_ptr = mutex_ptr->PRIORITY_CEILING;
    mutex_ptr->PRIORITY_CEILING = ceiling;
    _int_enable();

    _KLOGX2(KLOG_mutex_set_priority_ceiling, MQX_EOK);
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Gets the priority of the mutex.
 *
 * This function operate on an initialized mutex; whereas, _mutatr_get_priority_ceiling()
 * and _mutatr_set_priority_ceiling() operate on an initialized mutex attributes
 * structure.
 *
 * \param[in]  mutex_ptr   Pointer to the mutex.
 * \param[out] ceiling_ptr Pointer to the previous priority ceiling.
 *
 * \return MQX_EOK
 * \return MQX_EINVAL (Mutex_ptr does not point to a valid mutex structure or
 * priority_ptr is NULL)
 *
 * \see _mutex_set_priority_ceiling
 * \see _mutex_init
 * \see MUTEX_STRUCT
 */
_mqx_uint _mutex_get_priority_ceiling
(
    MUTEX_STRUCT_PTR mutex_ptr,
    _mqx_uint_ptr    ceiling_ptr
)
{ /* Body */

#if MQX_CHECK_ERRORS
    if ((mutex_ptr == NULL) || (ceiling_ptr == NULL))
    {
        return (MQX_EINVAL);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (mutex_ptr->VALID != MUTEX_VALID)
    {
        return (MQX_EINVAL);
    } /* Endif */
#endif

    *ceiling_ptr = mutex_ptr->PRIORITY_CEILING;
    return (MQX_EOK);

} /* Endbody */

/*!
 * \brief Gets the number of tasks waiting for the specified mutex.
 *
 * \param[in] mutex_ptr Pointer to the mutex.
 *
 * \return Number of tasks that are waiting for the mutex.
 * \return MAX_MQX_UINT (Failure.)
 *
 * \warning On failure, calls _task_set_error() to set the task error code to
 * MQX_EINVAL.
 *
 * \see _mutex_lock
 * \see _task_set_error
 * \see MUTEX_STRUCT
 */
_mqx_uint _mutex_get_wait_count
(
    register MUTEX_STRUCT_PTR mutex_ptr
)
{ /* Body */

#if MQX_CHECK_ERRORS
    if (mutex_ptr == NULL)
    {
        _task_set_error(MQX_EINVAL);
        return (MAX_MQX_UINT);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (mutex_ptr->VALID != MUTEX_VALID)
    {
        _task_set_error(MQX_EINVAL);
        return (MAX_MQX_UINT);
    } /* Endif */
#endif

    return (_QUEUE_GET_SIZE(&mutex_ptr->WAITING_TASKS));

} /* Endbody */

#endif /* MQX_USE_MUTEXES */

/* EOF */
