
/*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 lightweight semaphore component.
*
*
*END************************************************************************/

#include "mqx_inc.h"

/*!
 * \private
 *
 * \brief Creates the lightweight semaphore.
 *
 * \param[in] sem_ptr        Pointer to the lightweight semaphore to create.
 * \param[in] initial_number Inital number of semaphores available.
 * \param[in] hidden         TRUE if semaphore will ne hidden from kernel, FALSE if not.
 * \param[in] user           User mode functionality.
 *
 * \return MQX_OK
 * \return MQX_EINVAL (lwsem is already initialized.)
 * \return MQX_INVALID_LWSEM (In case of user mode, MQX tries to access a lwsem
 * with inappropriate access rights.)
 *
 * \see _lwsem_create
 * \see _lwsem_create_hidden
 * \see _usr_lwsem_create
 * \see LWSEM_STRUCT
 */
_mqx_uint _lwsem_create_internal
(
    LWSEM_STRUCT_PTR sem_ptr,
    _mqx_int         initial_number,
    bool          hidden,
    bool          user
)
{
    KERNEL_DATA_STRUCT_PTR kernel_data;
    LWSEM_STRUCT_PTR       sem_chk_ptr;

#if MQX_ENABLE_USER_MODE
    if (user && !_psp_mem_check_access_mask((uint32_t)sem_ptr, sizeof(LWSEM_STRUCT), MPU_UM_R, MPU_UM_RW))
    {
        return MQX_INVALID_LWSEM;
    }
#endif /* MQX_ENABLE_USER_MODE */

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_lwsem_create, initial_number);

    sem_ptr->VALUE = initial_number;
    _QUEUE_INIT(&sem_ptr->TD_QUEUE, 0);
    _int_disable();

    if (!hidden)
    {
#if MQX_CHECK_ERRORS
        /* Check if lwsem is already initialized */
#if MQX_ENABLE_USER_MODE
        if (user)
        {
            sem_chk_ptr = (LWSEM_STRUCT_PTR)((void *)kernel_data->USR_LWSEM.NEXT);
            while (sem_chk_ptr != (LWSEM_STRUCT_PTR)((void *)&kernel_data->USR_LWSEM))
            {
                if (sem_chk_ptr == sem_ptr)
                {
                    _int_enable();
                    _KLOGX2(KLOG_lwsem_create, MQX_EINVAL);
                    return(MQX_EINVAL);
                }

                sem_chk_ptr = (LWSEM_STRUCT_PTR)((void *)sem_chk_ptr->NEXT);
            }
        }
        else
#endif /* MQX_ENABLE_USER_MODE */
        {
            sem_chk_ptr = (LWSEM_STRUCT_PTR) ((void *) kernel_data->LWSEM.NEXT);
            while (sem_chk_ptr != (LWSEM_STRUCT_PTR) ((void *) &kernel_data->LWSEM))
            {
                if (sem_chk_ptr == sem_ptr)
                {
                    _int_enable();
                    _KLOGX2(KLOG_lwsem_create, MQX_EINVAL);
                    return (MQX_EINVAL);
                }

                sem_chk_ptr = (LWSEM_STRUCT_PTR) ((void *) sem_chk_ptr->NEXT);
            }
        }
#endif /* MQX_CHECK_ERRORS */

#if MQX_ENABLE_USER_MODE
        if (user)
        {
            _QUEUE_ENQUEUE(&kernel_data->USR_LWSEM, sem_ptr);
        }
        else
#endif /* MQX_ENABLE_USER_MODE */
        {
            _QUEUE_ENQUEUE(&kernel_data->LWSEM, sem_ptr);
        }
    }

    sem_ptr->VALID = LWSEM_VALID;
    _int_enable();

    _KLOGX2(KLOG_lwsem_create, MQX_OK);

    return (MQX_OK);
}

/*!
 * \brief Creates the lightweight semaphore.
 *
 * Because lightweight semaphores are a core component, an application need not to
 * create the component before it creates lightweight semaphores.
 *
 * \param[in] sem_ptr        Pointer to the lightweight semaphore to create.
 * \param[in] initial_number Inital number of semaphores available.
 *
 * \return MQX_OK
 * \return MQX_EINVAL (lwsem is already initialized.)
 * \return MQX_INVALID_LWSEM (In case of user mode, MQX tries to access a lwsem
 * with inappropriate access rights.)
 *
 * \see _lwsem_create_hidden
 * \see _lwsem_destroy
 * \see _lwsem_post
 * \see _lwsem_test
 * \see _lwsem_wait
 * \see _lwsem_wait_for
 * \see _lwsem_wait_ticks
 * \see _lwsem_wait_until
 * \see LWSEM_STRUCT
 */
_mqx_uint _lwsem_create
(
    LWSEM_STRUCT_PTR sem_ptr,
    _mqx_int         initial_number
)
{
#if MQX_ENABLE_USER_MODE && MQX_ENABLE_USER_STDAPI
    if (MQX_RUN_IN_USER_MODE)
    {
        return _usr_lwsem_create(sem_ptr, initial_number);
    }
#endif

    return _lwsem_create_internal(sem_ptr, initial_number, FALSE, FALSE);
}

/*!
 * \brief Creates the lightweight semaphore hidden from kernel.
 *
 * \param[in] sem_ptr        Pointer to the lightweight semaphore to create.
 * \param[in] initial_number Inital number of semaphores available.
 *
 * \return MQX_OK
 * \return MQX_EINVAL (lwsem is already initialized.)
 * \return MQX_INVALID_LWSEM (In case of user mode, MQX tries to access a lwsem
 * with inappropriate access rights.)
 *
 * \see _lwsem_create
 * \see _lwsem_destroy
 * \see _lwsem_post
 * \see _lwsem_test
 * \see _lwsem_wait
 * \see _lwsem_wait_for
 * \see _lwsem_wait_ticks
 * \see _lwsem_wait_until
 * \see LWSEM_STRUCT
 */
_mqx_uint _lwsem_create_hidden
(
    LWSEM_STRUCT_PTR sem_ptr,
    _mqx_int         initial_number
)
{
    return _lwsem_create_internal(sem_ptr, initial_number, TRUE, FALSE);
}

#if MQX_ENABLE_USER_MODE
/*!
 * \brief Creates the lightweight semaphore hidden form kernel.
 *
 * This function is an equivalent to the _lwsem_create() API call but it can be
 * executed from within the User task or other code running in the CPU User mode.
 * Parameters passed to this function by pointer are required to meet the memory
 * protection requirements as described in the parameter list below.
 *
 * \param[in] sem_ptr        Read only. Pointer to the lightweight semaphore to create.
 * \param[in] initial_number Inital number of semaphores available.
 *
 * \return MQX_OK
 * \return MQX_EINVAL (lwsem is already initialized.)
 * \return MQX_INVALID_LWSEM (In case of user mode, MQX tries to access a lwsem
 * with inappropriate access rights.)
 *
 * \see _lwsem_create
 * \see _usr_lwsem_destroy
 * \see _usr_lwsem_post
 * \see _usr_lwsem_wait
 * \see _usr_lwsem_wait_for
 * \see _usr_lwsem_wait_ticks
 * \see _usr_lwsem_wait_until
 * \see LWSEM_STRUCT
 */
_mqx_uint _usr_lwsem_create
(
    LWSEM_STRUCT_PTR sem_ptr,
    _mqx_int         initial_number
)
{
    MQX_API_CALL_PARAMS params =
    {   (uint32_t)sem_ptr, (uint32_t)initial_number, (uint32_t)FALSE, 0, 0};
    return _mqx_api_call(MQX_API_LWSEM_CREATE, &params);
}

#endif /* MQX_ENABLE_USER_MODE */

/*!
 * \private
 *
 * \brief Destroys the lightweight semaphore.
 *
 * \param[in] sem_ptr Pointer to the created lightweight semaphore.
 * \param[in] user    User mode functionality.
 *
 * \return MQX_OK
 * \return MQX_INVALID_LWSEM (sem_ptr does not point to a valid lightweight semaphore.)
 *
 * \see _lwsem_destroy
 * \see LWSEM_STRUCT
 */
_mqx_uint _lwsem_destroy_internal
(
    LWSEM_STRUCT_PTR sem_ptr,
    bool          user
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;
    TD_STRUCT_PTR          td_ptr;
    LWSEM_STRUCT_PTR       sem_chk_ptr;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_lwsem_destroy, sem_ptr);

    _int_disable();
#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != LWSEM_VALID)
    {
        _int_enable();
        _KLOGX2(KLOG_lwsem_destroy, MQX_INVALID_LWSEM);
        return (MQX_INVALID_LWSEM);
    } /* Endif */
#endif

    sem_ptr->VALID = 0; /* Invalidate the semaphore */
    while (_QUEUE_GET_SIZE(&sem_ptr->TD_QUEUE))
    {
        _QUEUE_DEQUEUE(&sem_ptr->TD_QUEUE, td_ptr);
        _BACKUP_POINTER(td_ptr, TD_STRUCT, AUX_QUEUE);
        _TIME_DEQUEUE(td_ptr, kernel_data);
        _TASK_READY(td_ptr, kernel_data);
    } /* Endwhile */

    /* Check if lwsem is in kernel's semaphore list */
#if MQX_ENABLE_USER_MODE
    if (user)
    {
        sem_chk_ptr = (LWSEM_STRUCT_PTR)((void *)kernel_data->USR_LWSEM.NEXT);
        while (sem_chk_ptr != (LWSEM_STRUCT_PTR)((void *)&kernel_data->USR_LWSEM))
        {
            if (sem_chk_ptr == sem_ptr)
            {
                /* remove semaphore from kernel LWSEM queue */
                _QUEUE_REMOVE(&kernel_data->USR_LWSEM, sem_ptr);
                break;
            }
            sem_chk_ptr = (LWSEM_STRUCT_PTR)((void *)sem_chk_ptr->NEXT);
        }
    }
    else
#endif /* MQX_ENABLE_USER_MODE */
    {
        sem_chk_ptr = (LWSEM_STRUCT_PTR) ((void *) kernel_data->LWSEM.NEXT);
        while (sem_chk_ptr != (LWSEM_STRUCT_PTR) ((void *) &kernel_data->LWSEM))
        {
            if (sem_chk_ptr == sem_ptr)
            {
                /* remove semaphore from kernel LWSEM queue */
                _QUEUE_REMOVE(&kernel_data->LWSEM, sem_ptr);
                break;
            } /* Endif */
            sem_chk_ptr = (LWSEM_STRUCT_PTR) ((void *) sem_chk_ptr->NEXT);
        } /* Endwhile */
    }

    _int_enable();

    _CHECK_RUN_SCHEDULER(); /* Allow higher priority tasks to run */


    _KLOGX2(KLOG_lwsem_destroy, MQX_OK);
    return (MQX_OK);

} /* Endbody */


/*!
 * \brief Destroys the lightweight semaphore.
 *
 * \param[in] sem_ptr Pointer to the created lightweight semaphore.
 *
 * \return MQX_OK
 * \return MQX_INVALID_LWSEM (sem_ptr does not point to a valid lightweight semaphore.)
 *
 * \warning Puts all waiting tasks in their ready queues.
 * \warning Cannot be called from an ISR.
 *
 * \see _lwsem_create
 * \see _lwsem_create_hidden
 * \see LWSEM_STRUCT
 */
_mqx_uint _lwsem_destroy
(
    LWSEM_STRUCT_PTR sem_ptr
)
{
#if MQX_ENABLE_USER_MODE && MQX_ENABLE_USER_STDAPI
    if (MQX_RUN_IN_USER_MODE)
    {
        return _usr_lwsem_destroy(sem_ptr);
    }
#endif

    return _lwsem_destroy_internal(sem_ptr, FALSE);
}

#if MQX_ENABLE_USER_MODE
/*!
 * \brief Destroys the lightweight semaphore.
 *
 * This function is an equivalent to the _lwsem_destroy() API call but it can be
 * executed from within the User task or other code running in the CPU User mode.
 * Parameters passed to this function by pointer are required to meet the memory
 * protection requirements as described in the parameter list below.
 *
 * \param[in] sem_ptr Read only. Pointer to the created lightweight semaphore.
 *
 * \return MQX_OK
 * \return MQX_INVALID_LWSEM (sem_ptr does not point to a valid lightweight semaphore.)
 *
 * \warning Puts all waiting tasks in their ready queues.
 * \warning Cannot be called from an ISR.
 *
 * \see _lwsem_destroy
 * \see _usr_lwsem_create
 * \see LWSEM_STRUCT
 */
_mqx_uint _usr_lwsem_destroy
(
    LWSEM_STRUCT_PTR sem_ptr
)
{
    MQX_API_CALL_PARAMS params = {(uint32_t)sem_ptr, 0, 0, 0, 0};
    return _mqx_api_call(MQX_API_LWSEM_DESTROY, &params);
}

#endif /* MQX_ENABLE_USER_MODE */

/*
 * \brief Check validity of semaphore.
 *
 * This function can be used to determine if semaphore is initialized or not.
 *
 * \param[in] sem_ptr Pointer to semaphore to be checked.
 *
 * \return TRUE (Semaphore is valid/initialized)
 * \return FALSE (Semaphore is invalid/not initialized)
 *
 * \see _lwsem_create
 * \see _lwsem_destroy
 * \see LWSEM_STRUCT
 */
bool _lwsem_is_valid
(
    LWSEM_STRUCT_PTR sem_ptr
)
{
    if (sem_ptr == NULL)
    {
        return(FALSE);
    }
    /* Searching for lwsem in kernel data is meaningless because it can be created as hidden. */
    return (sem_ptr->VALID == LWSEM_VALID) ? TRUE : FALSE;
}
/*!
 * \brief Poll for the lightweight semaphore.
 *
 * This function is the nonblocking alternative to the _lwsem_wait family of functions.
 *
 * \param[in] sem_ptr Pointer to the created lightweight semaphore.
 *
 * \return TRUE (Task got the lightweight semaphore.)
 * \return FALSE (Lightweight semaphore was not available.)
 *
 * \see _lwsem_create
 * \see _lwsem_create_hidden
 * \see _lwsem_wait
 * \see _lwsem_wait_for
 * \see _lwsem_wait_ticks
 * \see _lwsem_wait_until
 * \see LWSEM_STRUCT
 */
bool _lwsem_poll
(
    LWSEM_STRUCT_PTR sem_ptr
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    bool                result;

#if MQX_ENABLE_USER_MODE && MQX_ENABLE_USER_STDAPI
    if (MQX_RUN_IN_USER_MODE)
    {
        return _usr_lwsem_poll(sem_ptr);
    }
#endif

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE2(KLOG_lwsem_poll, sem_ptr);

#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != LWSEM_VALID)
    {
        _KLOGX2(KLOG_lwsem_poll, FALSE);
        return (FALSE);
    } /* Endif */
#endif /* MQX_CHECK_VALIDITY */

    _INT_DISABLE();
    if (sem_ptr->VALUE <= 0)
    {
        result = FALSE;
    }
    else
    {
        --sem_ptr->VALUE;
        result = TRUE;
    } /* Endif */
    _INT_ENABLE();

    _KLOGX2(KLOG_lwsem_poll, result);

    return (result);

}

#if MQX_ENABLE_USER_MODE
/*!
 * \brief Poll for the lightweight semaphore.
 *
 * This function is an equivalent to the _lwsem_poll() API call but it can be
 * executed from within the User task or other code running in the CPU User mode.
 * Parameters passed to this function by pointer are required to meet the memory
 * protection requirements as described in the parameter list below.
 *
 * \param[in] sem_ptr Read only. Pointer to the created lightweight semaphore.
 *
 * \return TRUE (Task got the lightweight semaphore.)
 * \return FALSE (Lightweight semaphore was not available.)
 *
 * \see _lwsem_poll
 * \see _usr_lwsem_create
 * \see _usr_lwsem_wait
 * \see _usr_lwsem_wait_for
 * \see _usr_lwsem_wait_ticks
 * \see _usr_lwsem_wait_until
 * \see LWSEM_STRUCT
 */
bool _usr_lwsem_poll
(
    LWSEM_STRUCT_PTR sem_ptr
)
{
    MQX_API_CALL_PARAMS params =
    {   (uint32_t)sem_ptr, 0, 0, 0, 0};

    return (bool)_mqx_api_call(MQX_API_LWSEM_POLL, &params);
}
#endif /* MQX_ENABLE_USER_MODE */

/*!
 * \brief Posts the lightweight semaphore.
 *
 * If tasks are waiting for the lightweight semaphore, MQX removes the first one
 * from the queue and puts it in the task's ready queue.
 *
 * \param[in] sem_ptr Pointer to the created lightweight semaphore.
 *
 * \return MQX_OK
 * \return MQX_INVALID_LWSEM (sem_ptr does not point to a valid lightweight semaphore)
 *
 * \warning Might put a waiting task in the task's ready queue.
 *
 * \see _lwsem_create
 * \see _lwsem_wait
 * \see _lwsem_wait_for
 * \see _lwsem_wait_ticks
 * \see _lwsem_wait_until
 * \see LWSEM_STRUCT
 */
_mqx_uint _lwsem_post
(
    LWSEM_STRUCT_PTR sem_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;
    TD_STRUCT_PTR          td_ptr;

#if MQX_ENABLE_USER_MODE && MQX_ENABLE_USER_STDAPI
    if (MQX_RUN_IN_USER_MODE)
    {
        return _usr_lwsem_post(sem_ptr);
    }
#endif

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_lwsem_post, sem_ptr);

#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != LWSEM_VALID)
    {
        _KLOGX2(KLOG_lwsem_post, MQX_INVALID_LWSEM);
        return (MQX_INVALID_LWSEM);
    } /* Endif */
#endif /* MQX_CHECK_VALIDITY */

    _INT_DISABLE();
    if ((sem_ptr->VALUE >= 0) && (_QUEUE_GET_SIZE(&sem_ptr->TD_QUEUE)))
    {
        _QUEUE_DEQUEUE(&sem_ptr->TD_QUEUE, td_ptr);
        _BACKUP_POINTER(td_ptr, TD_STRUCT, AUX_QUEUE);
        _TIME_DEQUEUE(td_ptr, kernel_data);
        td_ptr->INFO = 0; /* Signal that post is activating the task */
        _TASK_READY(td_ptr, kernel_data);
        _CHECK_RUN_SCHEDULER(); /* Let higher priority task run */
    }
    else
    {
        ++sem_ptr->VALUE;
    } /* Endif */
    _INT_ENABLE();

    _KLOGX2(KLOG_lwsem_post, MQX_OK);

    return (MQX_OK);

}

#if MQX_ENABLE_USER_MODE
/*!
 * \brief Posts the lightweight semaphore.
 *
 * This function is an equivalent to the _lwsem_post() API call but it can be
 * executed from within the User task or other code running in the CPU User mode.
 * Parameters passed to this function by pointer are required to meet the memory
 * protection requirements as described in the parameter list below.
 *
 * \param[in] sem_ptr Read only. Pointer to the created lightweight semaphore.
 *
 * \return MQX_OK
 * \return MQX_INVALID_LWSEM (sem_ptr does not point to a valid lightweight semaphore)
 *
 * \warning Might put a waiting task in the task's ready queue.
 *
 * \see _lwsem_post
 * \see _usr_lwsem_create
 * \see _usr_lwsem_wait
 * \see _usr_lwsem_wait_for
 * \see _usr_lwsem_wait_ticks
 * \see _usr_lwsem_wait_until
 * \see LWSEM_STRUCT
 */
_mqx_uint _usr_lwsem_post
(
    LWSEM_STRUCT_PTR sem_ptr
)
{
    MQX_API_CALL_PARAMS params =
    {   (uint32_t)sem_ptr, 0, 0, 0, 0};
    return _mqx_api_call(MQX_API_LWSEM_POST, &params);
}
#endif /* MQX_ENABLE_USER_MODE */

/*!
 * \brief Tests the data structures (including queues) of the lightweight semaphores
 * component for consistency and validity.
 *
 * \param[out] lwsem_error_ptr Pointer to the lightweight semaphore in error (NULL
 * if no error is found)
 * \param[out] td_error_ptr    Pointer to the task descriptor of waiting task that
 * has an error (NULL if no error is found).
 *
 * \return MQX_OK
 * \return MQX_INVALID_LWSEM (Results of _queue_test().)
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 *
 * \warning Cannot be called from an ISR.
 * Disables and enables interrupts.
 *
 * \see _lwsem_create
 * \see _lwsem_destroy
 * \see _queue_test
 */
_mqx_uint _lwsem_test
(
    void    **lwsem_error_ptr,
    void    **td_error_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;
    LWSEM_STRUCT_PTR       sem_ptr;
    _mqx_uint              queue_size;
    _mqx_uint              result;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_lwsem_test, lwsem_error_ptr, td_error_ptr);

    *td_error_ptr = NULL;
    *lwsem_error_ptr = NULL;

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_lwsem_test, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    }/* Endif */
#endif

    _int_disable();

    result = _queue_test((QUEUE_STRUCT_PTR) &kernel_data->LWSEM, lwsem_error_ptr);
    if (result != MQX_OK)
    {
        _KLOGX3(KLOG_lwsem_test, result, *lwsem_error_ptr);
        return (result);
    } /* Endif */

    sem_ptr = (LWSEM_STRUCT_PTR) ((void *) kernel_data->LWSEM.NEXT);
    queue_size = _QUEUE_GET_SIZE(&kernel_data->LWSEM);
    while (queue_size--)
    {
        if (sem_ptr->VALID != LWSEM_VALID)
        {
            result = MQX_INVALID_LWSEM;
            break;
        } /* Endif */

        result = _queue_test(&sem_ptr->TD_QUEUE, td_error_ptr);
        if (result != MQX_OK)
        {
            break;
        } /* Endif */

        sem_ptr = sem_ptr->NEXT;
    } /* Endwhile */

    _int_enable();

    if (result != MQX_OK)
    {
        *lwsem_error_ptr = (void *) sem_ptr;
    } /* Endif */
    _KLOGX4(KLOG_lwsem_test, result, *lwsem_error_ptr, *td_error_ptr);

    return (result);

}

#if MQX_ENABLE_USER_MODE
/*!
 * \brief Checks whether the specified pointer corresponds with a valid lightweight
 * semaphore.
 *
 * \param[in] tst_sem_ptr Pointer to the lightweight semaphore.
 *
 * \return MQX_OK (Valid lightweight semaphore.)
 * \return MQX_INVALID_LWSEM (Specified lightweight semaphore is not valid.)
 *
 * \see LWSEM_STRUCT
 */
_mqx_uint _lwsem_usr_check
(
    LWSEM_STRUCT_PTR tst_sem_ptr
)
{
    KERNEL_DATA_STRUCT_PTR kernel_data;
    LWSEM_STRUCT_PTR       sem_ptr;
    _mqx_uint              result = MQX_INVALID_LWSEM;
    _mqx_uint              queue_size;

    _GET_KERNEL_DATA(kernel_data);

    sem_ptr = (LWSEM_STRUCT_PTR)((void *)kernel_data->USR_LWSEM.NEXT);
    queue_size = _QUEUE_GET_SIZE(&kernel_data->USR_LWSEM);

    while (queue_size--)
    {
        if (sem_ptr->VALID != LWSEM_VALID)
        {
            break;
        }

        if (tst_sem_ptr == sem_ptr)
        {
            result = MQX_OK;
            break;
        }

        sem_ptr = (LWSEM_STRUCT_PTR)(void *)sem_ptr->NEXT;
    }

    return result;
}

#endif /* MQX_ENABLE_USER_MODE */

/*!
 * \brief Waits (in FIFO order) for the lightweight semaphore until it is available.
 *
 * \note Because priority inversion might occur if tasks with different priorities
 * access the same lightweight semaphore, we recommend under these circumstances
 * that you use the semaphore component.
 *
 * \param[in] sem_ptr Pointer to the lightweight semaphore.
 *
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_LWSEM (Sem_ptr is for a lightweight semaphore that is not
 * longer valid.)
 *
 * \warning Might block the calling task.
 * Cannot be called from an ISR.
 *
 * \see _lwsem_create
 * \see _lwsem_post
 * \see LWSEM_STRUCT
 */
_mqx_uint _lwsem_wait
(
    LWSEM_STRUCT_PTR sem_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;
    TD_STRUCT_PTR td_ptr;

#if MQX_ENABLE_USER_MODE && MQX_ENABLE_USER_STDAPI
    if (MQX_RUN_IN_USER_MODE)
    {
        return _usr_lwsem_wait(sem_ptr);
    }
#endif

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_lwsem_wait, sem_ptr);

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_lwsem_wait, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    }
#endif

#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != LWSEM_VALID)
    {
        _KLOGX2(KLOG_lwsem_wait, MQX_INVALID_LWSEM);
        return (MQX_INVALID_LWSEM);
    }
#endif

    _INT_DISABLE();
    if (sem_ptr->VALUE <= 0)
    {
        td_ptr = kernel_data->ACTIVE_PTR;
        td_ptr->STATE = LWSEM_BLOCKED;
        td_ptr->INFO = (_mqx_uint) &sem_ptr->TD_QUEUE;
        _QUEUE_UNLINK(td_ptr);
        _QUEUE_ENQUEUE(&sem_ptr->TD_QUEUE, &td_ptr->AUX_QUEUE);
        _sched_execute_scheduler_internal(); /* Let the other tasks run */
        /* Another task has posted a semaphore, and it has been tranfered to this
         ** task.
         */
    }
    else
    {
        --sem_ptr->VALUE;
    }

    /* We must check for component destruction */
    if (sem_ptr->VALID != LWSEM_VALID)
    {
        _int_enable();
        /* The semaphore has been deleted */
        _KLOGX2(KLOG_lwsem_wait, MQX_INVALID_LWSEM);
        return (MQX_INVALID_LWSEM);
    } /* Endif */

    _INT_ENABLE();

    _KLOGX2(KLOG_lwsem_wait, MQX_OK);

    return (MQX_OK);
}

#if MQX_ENABLE_USER_MODE
/*!
 * \brief Waits (in FIFO order) for the lightweight semaphore until it is available.
 *
 * This function is an equivalent to the _lwsem_wait() API call but it can be
 * executed from within the User task or other code running in the CPU User mode.
 * Parameters passed to this function by pointer are required to meet the memory
 * protection requirements as described in the parameter list below.
 *
 * \param[in] sem_ptr Read only. Pointer to the lightweight semaphore.
 *
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_LWSEM (Sem_ptr is for a lightweight semaphore that is not
 * longer valid.)
 *
 * \warning Might block the calling task.
 * Cannot be called from an ISR.
 *
 * \see _lwsem_wait
 * \see _usr_lwsem_create
 * \see _usr_lwsem_post
 * \see LWSEM_STRUCT
 */
_mqx_uint _usr_lwsem_wait
(
    LWSEM_STRUCT_PTR sem_ptr
)
{
    MQX_API_CALL_PARAMS params =
    {   (uint32_t)sem_ptr, 0, 0, 0, 0};
    return _mqx_api_call(MQX_API_LWSEM_WAIT, &params);
}

#endif /* MQX_ENABLE_USER_MODE */

/*!
 * \private
 *
 * \brief This function is an internal funciton, it waits for a light weight
 * semaphore with a pre-calcualted timeout.
 *
 * \param[in] sem_ptr Pointer to the lightweight semaphore.
 * \param[in] td_ptr  Pointer to the task descriptor waiting.
 *
 * \return MQX_OK
 * \return MQX_LWSEM_WAIT_TIMEOUT (Timeout expired before the task could get the
 * lightweight semaphore.)
 *
 * \see _lwsem_wait
 * \see _lwsem_wait_for
 * \see _lwsem_wait_ticks
 * \see _lwsem_wait_until
 * \see _usr_lwsem_wait
 * \see _usr_lwsem_wait_for
 * \see _usr_lwsem_wait_ticks
 * \see _usr_lwsem_wait_until
 * \see LWSEM_STRUCT
 * \see TD_STRUCT
 */
_mqx_uint _lwsem_wait_timed_internal
(
    LWSEM_STRUCT_PTR sem_ptr,
    TD_STRUCT_PTR    td_ptr
)
{ /* Body */

    td_ptr->STATE = LWSEM_BLOCKED;
    td_ptr->INFO  = (_mqx_uint) &sem_ptr->TD_QUEUE;
    _QUEUE_UNLINK(td_ptr);
    _QUEUE_ENQUEUE(&sem_ptr->TD_QUEUE, &td_ptr->AUX_QUEUE);
    _time_delay_internal(td_ptr);
    if (td_ptr->INFO != 0)
    {
        /*_QUEUE_REMOVE(&sem_ptr->TD_QUEUE, &td_ptr->AUX_QUEUE);*/
        return (MQX_LWSEM_WAIT_TIMEOUT);
    } /* Endif */

    return (MQX_OK);

} /* Endbody */

#if MQX_HAS_TICK

/*!
 * \brief Waits (in FIFO order) for the lightweight semaphore for the number of
 * ticks (in tick time).
 *
 * \note Because priority inversion might occur if tasks with different priorities access
 * the same lightweight semaphore, we recommend under these circumstances that you
 * use the semaphore component.
 *
 * \param[in] sem_ptr Pointer to the lightweight semaphore.
 * \param[in] ticks   Pointer to the maximum number of ticks to wait or NULL
 * (unlimited wait).
 *
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_LWSEM (Sem_ptr is for a lightweight semaphore that is not
 * longer valid.)
 * \return MQX_LWSEM_WAIT_TIMEOUT (Timeout expired before the task could get the
 * lightweight semaphore.)
 *
 * \warning Might block the calling task.
 * Cannot be called from an ISR.
 *
 * \see _lwsem_create
 * \see _lwsem_post
 * \see LWSEM_STRUCT
 * \see MQX_TICK_STRUCT
 */
_mqx_uint _lwsem_wait_for
(
    LWSEM_STRUCT_PTR    sem_ptr,
    MQX_TICK_STRUCT_PTR ticks
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;
    TD_STRUCT_PTR          td_ptr;
    _mqx_uint              result;

#if MQX_ENABLE_USER_MODE && MQX_ENABLE_USER_STDAPI
    if (MQX_RUN_IN_USER_MODE)
    {
        return _usr_lwsem_wait_for(sem_ptr, ticks);
    }
#endif

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_lwsem_wait_for, sem_ptr, ticks);

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_lwsem_wait_for, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != LWSEM_VALID)
    {
        _KLOGX2(KLOG_lwsem_wait_for, MQX_INVALID_LWSEM);
        return (MQX_INVALID_LWSEM);
    } /* Endif */
#endif

    _INT_DISABLE();
    if (sem_ptr->VALUE <= 0)
    {
        td_ptr = kernel_data->ACTIVE_PTR;
        /* Calculate time to wake up the task */
        PSP_ADD_TICKS(ticks, &kernel_data->TIME, &td_ptr->TIMEOUT);
        result = _lwsem_wait_timed_internal(sem_ptr, td_ptr);
    }
    else
    {
        --sem_ptr->VALUE;
        result = MQX_OK;
    } /* Endif */

    /* We must check for component destruction */
    if (sem_ptr->VALID != LWSEM_VALID)
    {
        _int_enable();
        /* The semaphore has been deleted */
        _KLOGX2(KLOG_lwsem_wait_for, MQX_INVALID_LWSEM);
        return (MQX_INVALID_LWSEM);
    } /* Endif */

    _INT_ENABLE();

    _KLOGX2(KLOG_lwsem_wait_for, result);

    return (result);

}

#if MQX_ENABLE_USER_MODE
/*!
 * \brief Waits (in FIFO order) for the lightweight semaphore for the number of
 * ticks (in tick time).
 *
 * This function is an equivalent to the _lwsem_wait_for() API call but it can be
 * executed from within the User task or other code running in the CPU User mode.
 * Parameters passed to this function by pointer are required to meet the memory
 * protection requirements as described in the parameter list below.
 *
 * \param[in] sem_ptr Read only. Pointer to the lightweight semaphore.
 * \param[in] ticks   Read/write. Pointer to the maximum number of ticks to wait
 * or NULL (unlimited wait).
 *
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_LWSEM (Sem_ptr is for a lightweight semaphore that is not
 * longer valid.)
 * \return MQX_LWSEM_WAIT_TIMEOUT (Timeout expired before the task could get the
 * lightweight semaphore.)
 *
 * \warning Might block the calling task.
 * Cannot be called from an ISR.
 *
 * \see _lwsem_wait_for
 * \see _usr_lwsem_create
 * \see _usr_lwsem_post
 * \see LWSEM_STRUCT
 * \see MQX_TICK_STRUCT
 */
_mqx_uint _usr_lwsem_wait_for
(
    LWSEM_STRUCT_PTR    sem_ptr,
    MQX_TICK_STRUCT_PTR ticks
)
{
    MQX_API_CALL_PARAMS params =
    {   (uint32_t)sem_ptr, (uint32_t)ticks, 0, 0, 0};
    return _mqx_api_call(MQX_API_LWSEM_WAIT_FOR, &params);
}

#endif /* MQX_ENABLE_USER_MODE */

/*!
 * \brief Waits (in FIFO order) for the lightweight semaphore for the number of ticks.
 *
 * \note Because priority inversion might occur if tasks with different priorities
 * access the same lightweight semaphore, we recommend under these circumstances
 * that you use the semaphore component.
 *
 * \param[in] sem_ptr       Pointer to the lightweight semaphore.
 * \param[in] time_in_ticks Maximum number of ticks to wait or 0 (unlimited wait).
 *
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_LWSEM (Sem_ptr is for a lightweight semaphore that is not
 * longer valid.)
 * \return MQX_LWSEM_WAIT_TIMEOUT (Timeout expired before the task could get the
 * lightweight semaphore.)
 *
 * \warning Might block the calling task.
 * Cannot be called from an ISR.
 *
 * \see _lwsem_create
 * \see _lwsem_post
 * \see LWSEM_STRUCT
 */
_mqx_uint _lwsem_wait_ticks
(
    LWSEM_STRUCT_PTR sem_ptr,
    _mqx_uint        time_in_ticks
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;
    TD_STRUCT_PTR          td_ptr;
    _mqx_uint              result;

#if MQX_ENABLE_USER_MODE && MQX_ENABLE_USER_STDAPI
    if (MQX_RUN_IN_USER_MODE)
    {
        return _usr_lwsem_wait_ticks(sem_ptr, time_in_ticks);
    }
#endif

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_lwsem_wait_ticks, sem_ptr, time_in_ticks);

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_lwsem_wait_ticks, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != LWSEM_VALID)
    {
        _KLOGX2(KLOG_lwsem_wait_ticks, MQX_INVALID_LWSEM);
        return (MQX_INVALID_LWSEM);
    } /* Endif */
#endif

    _INT_DISABLE();
    if (sem_ptr->VALUE <= 0)
    {
        td_ptr = kernel_data->ACTIVE_PTR;
        if (time_in_ticks == 0)
        {
            td_ptr->STATE = LWSEM_BLOCKED;
            td_ptr->INFO = (_mqx_uint) &sem_ptr->TD_QUEUE;
            _QUEUE_UNLINK(td_ptr);
            _QUEUE_ENQUEUE(&sem_ptr->TD_QUEUE, &td_ptr->AUX_QUEUE);
            _sched_execute_scheduler_internal(); /* Let the other tasks run */
            /* Another task has posted a semaphore, and it has been tranfered to this
             ** task.
             */
            result = MQX_OK;
        }
        else
        {
            PSP_ADD_TICKS_TO_TICK_STRUCT(&kernel_data->TIME, time_in_ticks,
                            &td_ptr->TIMEOUT);
            result = _lwsem_wait_timed_internal(sem_ptr, td_ptr);
        } /* Endif */
    }
    else
    {
        --sem_ptr->VALUE;
        result = MQX_OK;
    } /* Endif */

    /* We must check for component destruction */
    if (sem_ptr->VALID != LWSEM_VALID)
    {
        _int_enable();
        /* The semaphore has been deleted */
        _KLOGX2(KLOG_lwsem_wait_ticks, MQX_INVALID_LWSEM);
        return (MQX_INVALID_LWSEM);
    } /* Endif */

    _INT_ENABLE();

    _KLOGX2(KLOG_lwsem_wait_ticks, result);

    return (result);

}

#if MQX_ENABLE_USER_MODE
/*!
 * \brief Waits (in FIFO order) for the lightweight semaphore for the number of ticks.
 *
 * This function is an equivalent to the _lwsem_wait_ticks() API call but it can
 * be executed from within the User task or other code running in the CPU User
 * mode. Parameters passed to this function by pointer are required to meet the
 * memory protection requirements as described in the parameter list below.
 *
 * \param[in] sem_ptr       Rread only. Pointer to the lightweight semaphore.
 * \param[in] time_in_ticks Maximum number of ticks to wait or 0 (unlimited wait).
 *
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_LWSEM (Sem_ptr is for a lightweight semaphore that is not
 * longer valid.)
 * \return MQX_LWSEM_WAIT_TIMEOUT (Timeout expired before the task could get the
 * lightweight semaphore.)
 *
 * \warning Might block the calling task.
 * Cannot be called from an ISR.
 *
 * \see _lwsem_wait_ticks
 * \see _usr_lwsem_create
 * \see _usr_lwsem_post
 * \see LWSEM_STRUCT
 */
_mqx_uint _usr_lwsem_wait_ticks
(
    LWSEM_STRUCT_PTR sem_ptr,
    _mqx_uint        time_in_ticks
)
{
    MQX_API_CALL_PARAMS params =
    {   (uint32_t)sem_ptr, (uint32_t)time_in_ticks, 0, 0, 0};
    return _mqx_api_call(MQX_API_LWSEM_WAIT_TICKS, &params);
}

#endif /* MQX_ENABLE_USER_MODE */

/*!
 * \brief Waits (in FIFO order) for the lightweight semaphore until the specified
 * time (in tick time).
 *
 * \note Because priority inversion might occur if tasks with different priorities
 * access the same lightweight semaphore, we recommend under these circumstances
 * that you use the semaphore component.
 *
 * \param[in] sem_ptr Pointer to the lightweight semaphore.
 * \param[in] ticks   Pointer to the time (in tick time) until which to wait or
 * NULL (unlimited wait).
 *
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_LWSEM (Sem_ptr is for a lightweight semaphore that is not
 * longer valid.)
 * \return MQX_LWSEM_WAIT_TIMEOUT (Timeout expired before the task could get the
 * lightweight semaphore.)
 *
 * \warning Might block the calling task.
 * Cannot be called from an ISR.
 *
 * \see _lwsem_create
 * \see _lwsem_post
 * \see LWSEM_STRUCT
 * \see MQX_TICK_STRUCT
 */
_mqx_uint _lwsem_wait_until
(
    LWSEM_STRUCT_PTR    sem_ptr,
    MQX_TICK_STRUCT_PTR ticks
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR kernel_data;
    TD_STRUCT_PTR          td_ptr;
    _mqx_uint              result;

#if MQX_ENABLE_USER_MODE && MQX_ENABLE_USER_STDAPI
    if (MQX_RUN_IN_USER_MODE)
    {
        return _usr_lwsem_wait_until(sem_ptr, ticks);
    }
#endif

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_lwsem_wait_until, sem_ptr, ticks);

#if MQX_CHECK_ERRORS
    if (kernel_data->IN_ISR)
    {
        _KLOGX2(KLOG_lwsem_wait_until, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        return (MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != LWSEM_VALID)
    {
        _KLOGX2(KLOG_lwsem_wait_until, MQX_INVALID_LWSEM);
        return (MQX_INVALID_LWSEM);
    } /* Endif */
#endif

    _INT_DISABLE();
    if (sem_ptr->VALUE <= 0)
    {
        td_ptr = kernel_data->ACTIVE_PTR;
        td_ptr->TIMEOUT = *ticks;
        result = _lwsem_wait_timed_internal(sem_ptr, td_ptr);
    }
    else
    {
        --sem_ptr->VALUE;
        result = MQX_OK;
    } /* Endif */

    /* We must check for component destruction */
    if (sem_ptr->VALID != LWSEM_VALID)
    {
        _int_enable();
        /* The semaphore has been deleted */
        _KLOGX2(KLOG_lwsem_wait_until, MQX_INVALID_LWSEM);
        return (MQX_INVALID_LWSEM);
    } /* Endif */

    _INT_ENABLE();

    _KLOGX2(KLOG_lwsem_wait_until, result);

    return (result);

}

#if MQX_ENABLE_USER_MODE
/*!
 * \brief Waits (in FIFO order) for the lightweight semaphore until the specified
 * time (in tick time).
 *
 * This function is an equivalent to the _lwsem_wait_until() API call but it can
 * be executed from within the User task or other code running in the CPU User
 * mode. Parameters passed to this function by pointer are required to meet the
 * memory protection requirements as described in the parameter list below.
 *
 * \param[in] sem_ptr Read only. Pointer to the lightweight semaphore.
 * \param[in] ticks   Read/write. Pointer to the time (in tick time) until which
 * to wait or NULL (unlimited wait).
 *
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_LWSEM (Sem_ptr is for a lightweight semaphore that is not
 * longer valid.)
 * \return MQX_LWSEM_WAIT_TIMEOUT (Timeout expired before the task could get the
 * lightweight semaphore.)
 *
 * \warning Might block the calling task.
 * Cannot be called from an ISR.
 *
 * \see _lwsem_wait_until
 * \see _usr_lwsem_create
 * \see _usr_lwsem_post
 * \see LWSEM_STRUCT
 * \see MQX_TICK_STRUCT
 */
_mqx_uint _usr_lwsem_wait_until
(
    LWSEM_STRUCT_PTR    sem_ptr,
    MQX_TICK_STRUCT_PTR ticks
)
{
    MQX_API_CALL_PARAMS params =
    {   (uint32_t)sem_ptr, (uint32_t)ticks, 0, 0, 0};
    return _mqx_api_call(MQX_API_LWSEM_WAIT_UNTIL, &params);
}

#endif /* MQX_ENABLE_USER_MODE */

#endif /* MQX_HAS_TICK */
