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

#include <string.h>
#include "mqx_inc.h"
#if MQX_USE_SEMAPHORES
#include "name.h"
#include "name_prv.h"
#include "sem.h"
#include "sem_prv.h"
#include "mqx_str.h"

/*!
 * \brief Closes the connection to the semaphore.
 * 
 * \param[in] users_sem_ptr Semaphore handle from _sem_open() or _sem_open_fast().
 * 
 * \return MQX_OK 
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return SEM_INVALID_SEMAPHORE_HANDLE (Semaphore is no longer valid or sem_handle 
 * is not a valid semaphore connection)
 * \return Error from _mem_free() (Task is not the one that opened the connection.)
 * 
 * \warning If the semaphore is strict, posts the appropriate number of times to 
 * the semaphore for this connection.
 * \warning Might dispatch tasks that are waiting for the semaphore.
 * \warning Cannot be called from an ISR.
 * 
 * \see _sem_destroy
 * \see _sem_destroy_fast
 * \see _sem_open
 * \see _sem_open_fast 
 */ 
_mqx_uint _sem_close
(
    void   *users_sem_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR    kernel_data;
    SEM_CONNECTION_STRUCT_PTR sem_connection_ptr;

    _GET_KERNEL_DATA(kernel_data);
    _KLOGE2(KLOG_sem_close, users_sem_ptr);

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

    sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)users_sem_ptr;
#if MQX_CHECK_ERRORS
    if (sem_connection_ptr->TD_PTR != kernel_data->ACTIVE_PTR)
    {
        _KLOGX2(KLOG_sem_close, SEM_INVALID_SEMAPHORE_HANDLE);
        return(SEM_INVALID_SEMAPHORE_HANDLE);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (sem_connection_ptr->VALID != SEM_VALID)
    {
        _KLOGX2(KLOG_sem_close, SEM_INVALID_SEMAPHORE_HANDLE);
        return(SEM_INVALID_SEMAPHORE_HANDLE);
    } /* Endif */
#endif

    if (sem_connection_ptr->SEM_PTR->VALID)
    {
        /* Release all held semaphores */
        while (sem_connection_ptr->POST_STATE > 0)
        {
            _sem_post(sem_connection_ptr);
        } /* Endwhile */
    } /* Endif */

    sem_connection_ptr->VALID = 0;

    if (_mem_free(sem_connection_ptr) != MQX_OK)
    {
        _KLOGX2(KLOG_sem_close, kernel_data->ACTIVE_PTR->TASK_ERROR_CODE);
        return(kernel_data->ACTIVE_PTR->TASK_ERROR_CODE);
    }
    else
    {
        _KLOGX2(KLOG_sem_close, MQX_OK);
        return(MQX_OK);
    } /* Endif */

} /* Endbody */

/*!
 * \brief Creates the semaphore component.
 * 
 * If an application previously called the function and maximum_number is greater 
 * that what was specified, MQX changes the maximum number of semaphores to 
 * maximum_number.
 * \n If an application does not explicitly create the semaphore component, MQX 
 * does so with the following default values the first time that a task calls 
 * _sem_create() or _sem_create_fast().
 * \n Parameter default values:
 * \li Initial_number = 8(default)
 * \li Grow_number = 8(default)
 * \li Maximum_number = 0(unlimited)  
 * 
 * \param[in] initial_number Initial number of semaphores that can be created.
 * \param[in] grow_number    Number of semaphores to be added when the initial 
 * number have been created.
 * \param[in] maximum_number If grow_number is not 0, one of:
 * \li Maximum number of semaphores that can be created.
 * \li 0 (Unlimited number.)
 * 
 * \return MQX_OK (success)
 * \return MQX_OUT_OF_MEMORY (Failure: MQX cannot allocate memory for semaphore 
 * component data.) 
 * 
 * \warning On failure, the task error code might be set.
 * 
 * \see _sem_create
 * \see _sem_create_fast
 * \see _sem_open
 * \see _sem_open_fast
 * \see _task_set_error
 */ 
_mqx_uint _sem_create_component
(
    _mqx_uint initial_number,
    _mqx_uint grow_number,
    _mqx_uint maximum_number
)
{ /* Body */
    SEM_COMPONENT_STRUCT_PTR sem_component_ptr;
    KERNEL_DATA_STRUCT_PTR   kernel_data;
    _mqx_uint                result;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE4(KLOG_sem_create_component, initial_number, grow_number, maximum_number);

    sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
    kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
    if (sem_component_ptr != NULL)
    {
        if (maximum_number > sem_component_ptr->MAXIMUM_NUMBER)
        {
            sem_component_ptr->MAXIMUM_NUMBER = maximum_number;
        } /* Endif */
        _KLOGX2(KLOG_sem_create_component, MQX_OK);
        return(MQX_OK);
    } /* Endif */

    sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
    _mem_alloc_system_zero((_mem_size)sizeof(SEM_COMPONENT_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (sem_component_ptr == NULL)
    {
        _KLOGX2(KLOG_sem_create_component, MQX_OUT_OF_MEMORY);
        return(MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(sem_component_ptr, MEM_TYPE_SEMAPHORE_COMPONENT);

    result = _name_create_handle_internal(&sem_component_ptr->NAME_TABLE_HANDLE,
                    initial_number, grow_number, maximum_number, initial_number);
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (result != MQX_OK)
    {
        _mem_free(sem_component_ptr);
        _KLOGX2(KLOG_sem_create_component, result);
        return(result);
    } /* Endif */
#endif

    sem_component_ptr->GROW_NUMBER = grow_number;
    if (maximum_number == 0)
    {
        sem_component_ptr->MAXIMUM_NUMBER = MAX_MQX_UINT;
    }
    else if (maximum_number < initial_number)
    {
        sem_component_ptr->MAXIMUM_NUMBER = initial_number;
    }
    else
    {
        sem_component_ptr->MAXIMUM_NUMBER = maximum_number;
    } /* Endif */
    sem_component_ptr->VALID = SEM_VALID;

    _int_disable();
#if MQX_CHECK_ERRORS
    if (kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES] != NULL)
    {
        SEM_COMPONENT_STRUCT_PTR new_sem_component_ptr;

        new_sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
        kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
        if (maximum_number > new_sem_component_ptr->MAXIMUM_NUMBER)
        {
            new_sem_component_ptr->MAXIMUM_NUMBER = maximum_number;
        } /* Endif */
        _int_enable();
        _name_destroy_handle_internal(sem_component_ptr->NAME_TABLE_HANDLE);
        _mem_free(sem_component_ptr);
        _KLOGX2(KLOG_sem_create_component, MQX_OK);
        return(MQX_OK);
    } /* Endif */
#endif
    kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES] = sem_component_ptr;

#if MQX_COMPONENT_DESTRUCTION
    kernel_data->COMPONENT_CLEANUP[KERNEL_SEMAPHORES] = _sem_cleanup;
#endif

    _int_enable();

    _KLOGX2(KLOG_sem_create_component, MQX_OK);
    return(MQX_OK);

} /* Endbody */

/*!
 * \brief Creates a named semaphore.
 * 
 * After the semaphore is created, tasks open a connection to it with _sem_open() 
 * and close the connection with _sem_close(). A named semaphore is destroyed 
 * with _sem_destroy().
 * <table>
 *   <tr>
 *     <td><b>Bit flag</b></td>
 *     <td><b>Set</b></td>
 *     <td><b>Not set</b></td>  
 *   </tr>
 *   <tr>
 *     <td><b>SEM_PRIORITY_INHERITANCE</b>(<b>SEM_STRICT</b> must also be set)</td>
 *     <td>If a task that waits for the semaphore has a higher priority than a 
 *     task that owns the semaphore, MQX boosts the priority of one of the owning 
 *     tasks to the priority of the waiting task. When the boosted task posts its 
 *     semaphore, MQX returns its priorities to its original values.</td>
 *     <td>MQX does not boost priorities</td>  
 *   </tr>
 *   <tr>
 *     <td><b>SEM_PRIORITY_QUEUEING</b></td>
 *     <td>Task that waits for the semaphore is queued according to the task's 
 *     priority. Within a priority, tasks are in FIFO order.</td>
 *     <td>Task that waits for the semaphore is queued in FIFO order.</td>  
 *   </tr>
 *   <tr>
 *     <td><b>SEM_STRICT</b></td>
 *     <td>Task must wait for the semaphore before it can post the semaphore.</td>
 *     <td>Task need not wait before posting.</td>  
 *   </tr>
 *   <tr>
 *     <td><b>SEM_STRICT</b></td>
 *     <td>Sem_count must be greater than or equal to 1.</td>
 *     <td>Sem_count must be greater than or equal to 0.</td>  
 *   </tr>     
 * </table> 
 * 
 * \param[in] name_ptr      Name by which to identify the semaphore.
 * \param[in] initial_count Number of requests that can concurrently have the 
 * semaphore.
 * \param[in] flags         Bit flags: 0 or as in Description.
 * 
 * \return MQX_OK (success)
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_COMPONENT_BASE (Semaphore component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX cannot allocate memory for the semaphore.)  
 * \return SEM_INCORRECT_INITIAL_COUNT (sem_count cannot be 0 if SEM_STRICT is set.)
 * \return SEM_INVALID_POLICY (SEM_STRICT must be set if SEM_PRIORITY_INHERITANCE 
 * is set.)
 * \return SEM_SEMAPHORE_EXISTS (Semaphore with the name exists.)
 * \return SEM_SEMAPHORE_TABLE_FULL (Semaphore names database is full and cannot 
 * be expanded.)
 * 
 * \warning Creates the semaphore component with default values if it was not 
 * previously created.
 * \warning Cannot be called from an ISR.
 * \warning On failure, the task error code might be set.
 * 
 * \see _sem_create_component
 * \see _sem_destroy
 * \see _sem_destroy_fast
 * \see _sem_open
 * \see _sem_open_fast
 * \see _sem_close
 * \see _task_set_error          
 */ 
_mqx_uint _sem_create
(
    char  *name_ptr,
    _mqx_uint initial_count,
    _mqx_uint flags
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR            kernel_data;
    register SEM_COMPONENT_STRUCT_PTR sem_component_ptr;
    register SEM_STRUCT_PTR           sem_ptr;
    _mqx_uint                         result;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE4(KLOG_sem_create, name_ptr, initial_count, flags);

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

#if MQX_CHECK_ERRORS
    if (flags & SEM_STRICT)
    {
        if (initial_count == 0)
        {
            _KLOGX2(KLOG_sem_create, SEM_INCORRECT_INITIAL_COUNT);
            return(SEM_INCORRECT_INITIAL_COUNT);
        }/* Endif */
    }
    else
    {
        if (flags & SEM_PRIORITY_INHERITANCE)
        {
            _KLOGX2(KLOG_sem_create, SEM_INVALID_POLICY);
            return(SEM_INVALID_POLICY);
        } /* Endif */
    }/* Endif */
#endif

    sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
    kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
    if (sem_component_ptr == NULL)
    {
        result = _sem_create_component(SEM_DEFAULT_INITIAL_NUMBER,
                        SEM_DEFAULT_GROW_NUMBER, SEM_DEFAULT_MAXIMUM_NUMBER);
        sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
        kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
        if (sem_component_ptr == NULL)
        {
            _KLOGX2(KLOG_sem_create, result);
            return(result);
        } /* Endif */
#endif
    } /* Endif */

#if MQX_CHECK_VALIDITY
    if (sem_component_ptr->VALID != SEM_VALID)
    {
        _KLOGX2(KLOG_sem_create, MQX_INVALID_COMPONENT_BASE);
        return(MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    sem_ptr = (SEM_STRUCT_PTR)_mem_alloc_system_zero((_mem_size)sizeof(SEM_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (sem_ptr == NULL)
    {
        _KLOGX2(KLOG_sem_create, MQX_OUT_OF_MEMORY);
        return(MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(sem_ptr, MEM_TYPE_SEMAPHORE);

    sem_ptr->POLICY = flags;
    sem_ptr->COUNT = initial_count;
    if (flags & SEM_STRICT)
    {
        sem_ptr->MAX_COUNT = initial_count;
    }
    else
    {
        sem_ptr->MAX_COUNT = MAX_MQX_UINT;
    }/* Endif */
    _QUEUE_INIT(&sem_ptr->WAITING_TASKS, SEM_MAX_WAITING_TASKS);
    _QUEUE_INIT(&sem_ptr->OWNING_TASKS, SEM_MAX_WAITING_TASKS);

    result = _name_add_internal(sem_component_ptr->NAME_TABLE_HANDLE, name_ptr,
                    (_mqx_uint)sem_ptr);
#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        _mem_free(sem_ptr);
        if (result == NAME_EXISTS)
        {
            _KLOGX2(KLOG_sem_create, SEM_SEMAPHORE_EXISTS);
            return(SEM_SEMAPHORE_EXISTS);
        }
        else if (result == NAME_TABLE_FULL)
        {
            _KLOGX2(KLOG_sem_create, SEM_SEMAPHORE_TABLE_FULL);
            return(SEM_SEMAPHORE_TABLE_FULL);
        } /* Endif */
        _KLOGX2(KLOG_sem_create, result);
        return(result);
    } /* Endif */
#endif

    strncpy(sem_ptr->NAME, name_ptr, (_mqx_uint)NAME_MAX_NAME_SIZE-1);
    sem_ptr->NAME[NAME_MAX_NAME_SIZE-1] = '\0';

    sem_ptr->VALID = SEM_VALID;

    _KLOGX2(KLOG_sem_create, result);
    return(result);

} /* Endbody */

/*!
 * \brief Destroys the named semaphore.
 * 
 * <table>
 *   <tr>
 *     <td><b>force_destroy is TRUE</b></td>
 *     <td><b>force_destroy is FALSE</b></td> 
 *   </tr>
 *   <tr>
 *     <td> \li Tasks that are waiting for the semaphore are made ready.
 *     \li Semaphore is destroyed after all the owners post the semaphore.</td>
 *     <td> \li Semaphore is destroyed after the last waiting task gets and posts 
 *     the semaphore.
 *     \li This is the action if the semaphore is strict.</td> 
 *   </tr>  
 * </table>  
 * 
 * \param[in] name_ptr      Name of the semaphore to destroy, created using 
 * _sem_create().
 * \param[in] force_destroy A bool flag, see Description.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Semaphore component is not created.)
 * \return MQX_INVALID_COMPONENT_BASE (Semaphore component data is not valid.)
 * \return SEM_SEMAPHORE_NOT_FOUND (Name_ptr is not in the semaphore names database.)
 * \return SEM_INVALID_SEMAPHORE (Semaphore data that is associated with name or index is not valid.)
 * _name_find_internal
 * \return NAME_TOO_SHORT (Name is 0 lenght string.)
 * \return NAME_TOO_LONG (Name is longer than NAME_MAX_NAME_SIZE.) 
 * 
 * \warning Cannot be called from an ISR.
 *    
 * \see _sem_destroy_fast
 * \see _sem_close
 * \see _sem_create
 * \see _sem_create_fast 
 */ 
_mqx_uint _sem_destroy
(
    char *name_ptr,
    bool  force_destroy
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR            kernel_data;
    register SEM_COMPONENT_STRUCT_PTR sem_component_ptr;
    SEM_STRUCT_PTR                    sem_ptr;
    SEM_CONNECTION_STRUCT_PTR         sem_connection_ptr;
    QUEUE_STRUCT_PTR                  queue_ptr;
    TD_STRUCT_PTR                     td_ptr;
    _mqx_max_type                     tmp;
    _mqx_uint                         result;
    _mqx_uint                         i;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_sem_destroy, name_ptr, force_destroy);

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

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

    sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
    kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
#if MQX_CHECK_VALIDITY
    if (sem_component_ptr->VALID != SEM_VALID)
    {
        _KLOGX2(KLOG_sem_destroy, MQX_INVALID_COMPONENT_BASE);
        return(MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    result = _name_find_internal(sem_component_ptr->NAME_TABLE_HANDLE,
                    name_ptr, &tmp);
#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        if (result == NAME_NOT_FOUND)
        {
            _KLOGX2(KLOG_sem_destroy, SEM_SEMAPHORE_NOT_FOUND);
            return(SEM_SEMAPHORE_NOT_FOUND);
        } /* Endif */
        _KLOGX2(KLOG_sem_destroy, result);
        return(result);
    } /* Endif */
#endif

    sem_ptr = (SEM_STRUCT_PTR)tmp;

    _int_disable();

#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != SEM_VALID)
    {
        _int_enable();
        _KLOGX2(KLOG_sem_destroy, SEM_INVALID_SEMAPHORE);
        return(SEM_INVALID_SEMAPHORE);
    } /* Endif */
#endif

    queue_ptr = &sem_ptr->WAITING_TASKS;
    if (force_destroy)
    {
        /* Get rid of all waiting tasks */
        i = _QUEUE_GET_SIZE(queue_ptr) + 1;
        while (--i)
        {
            sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)
            ((void *)queue_ptr->NEXT);
            td_ptr = sem_connection_ptr->TD_PTR;
            if ((td_ptr->STATE & STATE_MASK)== SEM_BLOCKED)
            {
                _TIME_DEQUEUE(td_ptr,kernel_data);
                _task_set_error_td_internal(td_ptr,SEM_SEMAPHORE_DELETED);
                _TASK_READY(td_ptr,kernel_data);
            } /* Endif */
        } /* Endwhile */
    } /* Endif */

    if (
        ( (sem_ptr->POLICY & SEM_STRICT) &&
          (sem_ptr->COUNT == sem_ptr->MAX_COUNT) &&
          (_QUEUE_GET_SIZE(queue_ptr) == 0))
        ||
        ( (!(sem_ptr->POLICY & SEM_STRICT)) &&
          (_QUEUE_GET_SIZE(queue_ptr) == 0)))
    {
        /* Destroy the semaphore */
        sem_ptr->VALID = 0;

        _int_enable();

        /* May need to let higher priority task run */
        _CHECK_RUN_SCHEDULER();

        result = _name_delete_internal(sem_component_ptr->NAME_TABLE_HANDLE,
                        name_ptr);
        if (result == NAME_NOT_FOUND)
        {
            result = SEM_SEMAPHORE_NOT_FOUND;
        } /* Endif */
        _mem_free(sem_ptr);
    }
    else
    {
        sem_ptr->DELAYED_DESTROY = TRUE;

        _int_enable();

        /* May need to let higher priority task run */
        _CHECK_RUN_SCHEDULER();
    } /* Endif */

    _KLOGX2(KLOG_sem_destroy, result);
    return(result);

} /* Endbody */

/*!
 * \brief Creates the fast semaphore.
 * 
 * After the semaphore is created, tasks open a connection to it with 
 * _sem_open_fast() and close the connection with _sem_close(). A fast semaphore 
 * is destroyed with _sem_destroy_fast().
 * \n _sem_create_fast() access the semaphore via an index number rather than a 
 * name.
 * 
 * \param[in] sem_index     Number by which to identify the semaphore.
 * \param[in] initial_count Number of tasks that can concurrently have the semaphore.
 * \param[in] flags         Bit flags, as described for _sem_create().
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_INVALID_COMPONENT_BASE (Semaphore component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX cannot allocate memory for the semaphore.)
 * \return SEM_SEMAPHORE_TABLE_FULL (Semaphore names database is full and cannot 
 * be expanded.)
 * \return SEM_SEMAPHORE_EXISTS (Semaphore with the name exists.)
 * \return SEM_INCORRECT_INITIAL_COUNT (Sem_count cannot be 0 if SEM_STRICT is set.)
 * \return SEM_INVALID_POLICY (SEM_STRICT must be set if SEM_PRIORITY_INHERITANCE 
 * is set.)  
 * 
 * \warning Creates the semaphore component with default values if it was not 
 * previously created.
 * \warning Cannot be called from an ISR.
 * \warning On failure, the task error code might be set.
 * 
 * \see _sem_create_component
 * \see _sem_destroy
 * \see _sem_destroy_fast
 * \see _sem_open
 * \see _sem_open_fast
 * \see _sem_close
 * \see _sem_create 
 *         
 */ 
_mqx_uint _sem_create_fast
(
    _mqx_uint sem_index,
    _mqx_uint initial_count,
    _mqx_uint flags
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR            kernel_data;
    register SEM_COMPONENT_STRUCT_PTR sem_component_ptr;
    register SEM_STRUCT_PTR           sem_ptr;
    _mqx_uint                         result;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE4(KLOG_sem_create_fast, sem_index, initial_count, flags);

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

#if MQX_CHECK_ERRORS
    if (flags & SEM_STRICT)
    {
        if (initial_count == 0)
        {
            _KLOGX2(KLOG_sem_create_fast, SEM_INCORRECT_INITIAL_COUNT);
            return(SEM_INCORRECT_INITIAL_COUNT);
        }/* Endif */
    }
    else
    {
        if (flags & SEM_PRIORITY_INHERITANCE)
        {
            _KLOGX2(KLOG_sem_create_fast, SEM_INVALID_POLICY);
            return(SEM_INVALID_POLICY);
        } /* Endif */
    }/* Endif */
#endif

    sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
    kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
    if (sem_component_ptr == NULL)
    {
        result = _sem_create_component(SEM_DEFAULT_INITIAL_NUMBER,
                        SEM_DEFAULT_GROW_NUMBER, SEM_DEFAULT_MAXIMUM_NUMBER);
        sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
        kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
        if (sem_component_ptr == NULL)
        {
            _KLOGX2(KLOG_sem_create_fast, result);
            return(result);
        } /* Endif */
#endif
    } /* Endif */

#if MQX_CHECK_VALIDITY
    if (sem_component_ptr->VALID != SEM_VALID)
    {
        _KLOGX2(KLOG_sem_create_fast, MQX_INVALID_COMPONENT_BASE);
        return(MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    sem_ptr = (SEM_STRUCT_PTR)_mem_alloc_system_zero((_mem_size)sizeof(SEM_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (sem_ptr == NULL)
    {
        _KLOGX2(KLOG_sem_create_fast, MQX_OUT_OF_MEMORY);
        return(MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(sem_ptr, MEM_TYPE_SEMAPHORE);

    sem_ptr->POLICY = flags;
    sem_ptr->COUNT = initial_count;
    if (flags & SEM_STRICT)
    {
        sem_ptr->MAX_COUNT = initial_count;
    }
    else
    {
        sem_ptr->MAX_COUNT = MAX_MQX_UINT;
    }/* Endif */
    _QUEUE_INIT(&sem_ptr->WAITING_TASKS, SEM_MAX_WAITING_TASKS);
    _QUEUE_INIT(&sem_ptr->OWNING_TASKS, SEM_MAX_WAITING_TASKS);

    _str_mqx_uint_to_hex_string(sem_index, sem_ptr->NAME);

    result = _name_add_internal_by_index(sem_component_ptr->NAME_TABLE_HANDLE,
                    sem_ptr->NAME, (_mqx_uint)sem_ptr, sem_index);
#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        _mem_free(sem_ptr);
        if (result == NAME_EXISTS)
        {
            _KLOGX2(KLOG_sem_create_fast, SEM_SEMAPHORE_EXISTS);
            return(SEM_SEMAPHORE_EXISTS);
        }
        else if (result == NAME_TABLE_FULL)
        {
            _KLOGX2(KLOG_sem_create_fast, SEM_SEMAPHORE_TABLE_FULL);
            return(SEM_SEMAPHORE_TABLE_FULL);
        } /* Endif */
        _KLOGX2(KLOG_sem_create_fast, result);
        return(result);
    } /* Endif */
#endif

    sem_ptr->VALID = SEM_VALID;

    _KLOGX2(KLOG_sem_create_fast, result);
    return(result);

} /* Endbody */

/*!
 * \brief Destroys the fast semaphore.
 * 
 * <table>
 *   <tr>
 *     <td><b>force_destroy is TRUE</b></td>
 *     <td><b>force_destroy is FALSE</b></td> 
 *   </tr>
 *   <tr>
 *     <td> \li Tasks that are waiting for the semaphore are made ready.
 *     \li Semaphore is destroyed after all the owners post the semaphore.</td>
 *     <td> \li Semaphore is destroyed after the last waiting task gets and posts 
 *     the semaphore.
 *     \li This is the action if the semaphore is strict.</td> 
 *   </tr>  
 * </table>  
 * 
 * \param[in] sem_index     Number that identifies the semaphore to destroy, 
 * created using _sem_create_fast().
 * \param[in] force_destroy A bool flag, see Description.
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Semaphore component is not created.)
 * \return MQX_INVALID_COMPONENT_BASE (Semaphore component data is not valid.)
 * \return SEM_SEMAPHORE_NOT_FOUND (Name_ptr is not in the semaphore names database.)
 * \return SEM_INVALID_SEMAPHORE (Semaphore data that is associated with name or index is not valid.)
 * _name_find_internal_by_index
 * \return NAME_TOO_SHORT (Name is 0 lenght string.)
 * \return NAME_TOO_LONG (Name is longer than NAME_MAX_NAME_SIZE.) 
 * 
 * \warning Cannot be called from an ISR. 
 * 
 * \see _sem_destroy
 * \see _sem_close
 * \see _sem_create
 * \see _sem_create_fast
 */ 
_mqx_uint _sem_destroy_fast
(
    _mqx_uint sem_index,
    bool   force_destroy
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR            kernel_data;
    register SEM_COMPONENT_STRUCT_PTR sem_component_ptr;
    SEM_STRUCT_PTR                    sem_ptr;
    SEM_CONNECTION_STRUCT_PTR         sem_connection_ptr;
    QUEUE_STRUCT_PTR                  queue_ptr;
    TD_STRUCT_PTR                     td_ptr;
    _mqx_max_type                     tmp;
    _mqx_uint                         result;
    _mqx_uint                         i;
#if MQX_CHECK_ERRORS
    char                              name[9];
#endif

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_sem_destroy_fast, sem_index, force_destroy);

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

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

    sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
    kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
#if MQX_CHECK_VALIDITY
    if (sem_component_ptr->VALID != SEM_VALID)
    {
        _KLOGX2(KLOG_sem_destroy_fast, MQX_INVALID_COMPONENT_BASE);
        return(MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    result = _name_find_internal_by_index(sem_component_ptr->NAME_TABLE_HANDLE,
                    sem_index, &tmp);
    sem_ptr = (SEM_STRUCT_PTR)tmp;

#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        if (result == NAME_NOT_FOUND)
        {
            _KLOGX2(KLOG_sem_destroy_fast, SEM_SEMAPHORE_NOT_FOUND);
            return(SEM_SEMAPHORE_NOT_FOUND);
        } /* Endif */
        _KLOGX2(KLOG_sem_destroy_fast, result);
        return(result);
    } /* Endif */

    _str_mqx_uint_to_hex_string(sem_index, name);
    if (strncmp(name, sem_ptr->NAME, 8))
    {
        /* Name does not match */
        _KLOGX2(KLOG_sem_destroy_fast, SEM_SEMAPHORE_NOT_FOUND);
        return(SEM_SEMAPHORE_NOT_FOUND);
    } /* Endif */
#endif

    _int_disable();

#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != SEM_VALID)
    {
        _int_enable();
        _KLOGX2(KLOG_sem_destroy_fast, SEM_INVALID_SEMAPHORE);
        return(SEM_INVALID_SEMAPHORE);
    } /* Endif */
#endif

    queue_ptr = &sem_ptr->WAITING_TASKS;

    if (force_destroy)
    {
        /* Get rid of all waiting tasks */
        i = _QUEUE_GET_SIZE(queue_ptr) + 1;
        while (--i)
        {
            sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)
            ((void *)queue_ptr->NEXT);
            td_ptr = sem_connection_ptr->TD_PTR;
            if ((td_ptr->STATE & STATE_MASK)== SEM_BLOCKED)
            {
                _TIME_DEQUEUE(td_ptr,kernel_data);
                _task_set_error_td_internal(td_ptr,SEM_SEMAPHORE_DELETED);
                _TASK_READY(td_ptr,kernel_data);
            } /* Endif */
        } /* Endwhile */
    } /* Endif */

    if (
        ( (sem_ptr->POLICY & SEM_STRICT) &&
          (sem_ptr->COUNT == sem_ptr->MAX_COUNT) &&
          (_QUEUE_GET_SIZE(queue_ptr) == 0))
        ||
        ( (!(sem_ptr->POLICY & SEM_STRICT)) &&
          (_QUEUE_GET_SIZE(queue_ptr) == 0)))
    {
        /* Destroy the semaphore */
        sem_ptr->VALID = 0;

        _int_enable();

        /* May need to let higher priority task run */
        _CHECK_RUN_SCHEDULER();

        result = _name_delete_internal_by_index(sem_component_ptr->NAME_TABLE_HANDLE,
                        sem_index);
        if (result == NAME_NOT_FOUND)
        {
            result = SEM_SEMAPHORE_NOT_FOUND;
        } /* Endif */
        _mem_free(sem_ptr);
    }
    else
    {
        sem_ptr->DELAYED_DESTROY = TRUE;

        _int_enable();

        /* May need to let higher priority task run */
        _CHECK_RUN_SCHEDULER();

    } /* Endif */

    _KLOGX2(KLOG_sem_destroy_fast, result);
    return(result);

} /* Endbody */

/*!
 * \brief Opens a connection to the fast semaphore.
 * 
 * \param[in]  sem_index        Number that identifies the semaphore that was 
 * created using _sem_create_fast().
 * \param[out] returned_sem_ptr Pointer to the semaphore handle, which is a 
 * connection to the semaphore.
 * 
 * \return MQX_OK
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Semaphore component is not created.)
 * \return MQX_INVALID_COMPONENT_BASE (Semaphore component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX cannot allocate memory for the connection.)
 * \return SEM_SEMAPHORE_NOT_FOUND (Name is not in the semaphore names database.)
 * \return SEM_INVALID_SEMAPHORE (Data that is associated with the semaphore is 
 * not valid.)
 * \return SEM_SEMAPHORE_DELETED (Semaphore is in the process of being destroyed.)
 *   
 * \see _sem_open
 * \see _sem_close
 * \see _sem_create
 * \see _sem_post
 * \see _sem_wait
 * \see _sem_wait_for
 * \see _sem_wait_ticks
 * \see _sem_wait_until
 */ 
_mqx_uint _sem_open_fast
(
    _mqx_uint     sem_index,
    void    **returned_sem_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR             kernel_data;
    register SEM_COMPONENT_STRUCT_PTR  sem_component_ptr;
    SEM_STRUCT_PTR                     sem_ptr;
    register SEM_CONNECTION_STRUCT_PTR sem_connection_ptr;
    _mqx_uint                          result;
    _mqx_max_type                      tmp;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_sem_open_fast, sem_index, returned_sem_ptr);

    *returned_sem_ptr = NULL;

    sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
    kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
#if MQX_CHECK_ERRORS
    if (sem_component_ptr == NULL)
    {
        _KLOGX3(KLOG_sem_open_fast, MQX_COMPONENT_DOES_NOT_EXIST, 0);
        return(MQX_COMPONENT_DOES_NOT_EXIST);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (sem_component_ptr->VALID != SEM_VALID)
    {
        _KLOGX3(KLOG_sem_open_fast, MQX_INVALID_COMPONENT_BASE, 0);
        return(MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    result = _name_find_internal_by_index(sem_component_ptr->NAME_TABLE_HANDLE,
                    sem_index, &tmp);
#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        if (result == NAME_NOT_FOUND)
        {
            _KLOGX3(KLOG_sem_open_fast, SEM_SEMAPHORE_NOT_FOUND, 0);
            return(SEM_SEMAPHORE_NOT_FOUND);
        } /* Endif */
        _KLOGX3(KLOG_sem_open_fast, result, 0);
        return(result);
    } /* Endif */
#endif

    sem_ptr = (SEM_STRUCT_PTR)tmp;

#if MQX_CHECK_ERRORS
    if (sem_ptr->VALID != SEM_VALID)
    {
        /* Semaphore not valid */
        _KLOGX3(KLOG_sem_open_fast, SEM_INVALID_SEMAPHORE, 0);
        return(SEM_INVALID_SEMAPHORE);
    } /* Endif */
#endif

#if MQX_COMPONENT_DESTRUCTION
    if (sem_ptr->DELAYED_DESTROY)
    {
        /* Semaphore in delayed destroy state */
        _KLOGX3(KLOG_sem_open_fast, SEM_SEMAPHORE_DELETED, 0);
        return(SEM_SEMAPHORE_DELETED);
    } /* Endif */
#endif

    sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)_mem_alloc_zero(
                    (_mem_size)sizeof(SEM_CONNECTION_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (sem_connection_ptr == NULL)
    {
        _KLOGX3(KLOG_sem_open_fast, MQX_OUT_OF_MEMORY, 0);
        return(MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(sem_connection_ptr, MEM_TYPE_SEMAPHORE_CONNECTION);

    sem_connection_ptr->SEM_PTR = sem_ptr;
    sem_connection_ptr->VALID = SEM_VALID;
    sem_connection_ptr->TD_PTR = kernel_data->ACTIVE_PTR;

    *returned_sem_ptr = (void *)sem_connection_ptr;

    _KLOGX3(KLOG_sem_open_fast, MQX_OK, sem_connection_ptr);
    return(MQX_OK);

} /* Endbody */

/*!
 * \private
 * 
 * \brief This function inserts a connection pointer by priority onto a queue.
 * 
 * \param[in] queue_ptr          The queue to insert the member into.
 * \param[in] sem_connection_ptr The connection pointer to insert into the queue. 
 */ 
void _sem_insert_priority_internal
(
    QUEUE_STRUCT_PTR          queue_ptr,
    SEM_CONNECTION_STRUCT_PTR sem_connection_ptr
)
{ /* Body */
    SEM_CONNECTION_STRUCT_PTR conn2_ptr;
    SEM_CONNECTION_STRUCT_PTR conn_prev_ptr;
    _mqx_uint                 count;
    _mqx_uint                 priority;

    conn_prev_ptr = (SEM_CONNECTION_STRUCT_PTR)((void *)queue_ptr);
    conn2_ptr = (SEM_CONNECTION_STRUCT_PTR)((void *)queue_ptr->NEXT);
    count = _QUEUE_GET_SIZE(queue_ptr) + 1;
    priority = sem_connection_ptr->TD_PTR->MY_QUEUE->PRIORITY;
    while (--count)
    {
        if (conn2_ptr->TD_PTR->MY_QUEUE->PRIORITY > priority)
        {
            break;
        } /* Endif */
        conn_prev_ptr = conn2_ptr;
        conn2_ptr = (SEM_CONNECTION_STRUCT_PTR)conn2_ptr->NEXT;
    } /* Endwhile */
    _QUEUE_INSERT(queue_ptr, conn_prev_ptr, sem_connection_ptr);

} /* Endbody */

/*!
 * \brief Opens a connection to the named semaphore.
 * 
 * \param[in]  name_ptr         Name that identifies the semaphore that was created 
 * using _sem_create().
 * \param[out] returned_sem_ptr Pointer to the semaphore handle, which is a 
 * connection to the semaphore.
 * 
 * \return MQX_OK
 * \return MQX_COMPONENT_DOES_NOT_EXIST (Semaphore component is not created.)
 * \return MQX_INVALID_COMPONENT_BASE (Semaphore component data is not valid.)
 * \return MQX_OUT_OF_MEMORY (MQX cannot allocate memory for the connection.)
 * \return SEM_SEMAPHORE_NOT_FOUND (Name is not in the semaphore names database.)
 * \return SEM_INVALID_SEMAPHORE (Data that is associated with the semaphore is 
 * not valid.)
 * \return SEM_SEMAPHORE_DELETED (Semaphore is in the process of being destroyed.)
 *   
 * \see _sem_open_fast
 * \see _sem_close
 * \see _sem_create
 * \see _sem_post
 * \see _sem_wait
 * \see _sem_wait_for
 * \see _sem_wait_ticks
 * \see _sem_wait_until
 */
_mqx_uint _sem_open
(
    char      *name_ptr,
    void    **returned_sem_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR             kernel_data;
    register SEM_COMPONENT_STRUCT_PTR  sem_component_ptr;
    SEM_STRUCT_PTR                     sem_ptr;
    register SEM_CONNECTION_STRUCT_PTR sem_connection_ptr;
    _mqx_max_type                      tmp;
    _mqx_uint                          result;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE3(KLOG_sem_open, name_ptr, returned_sem_ptr);

    *returned_sem_ptr = NULL;

    sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
    kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
#if MQX_CHECK_ERRORS
    if (sem_component_ptr == NULL)
    {
        _KLOGX3(KLOG_sem_open, MQX_COMPONENT_DOES_NOT_EXIST, 0);
        return(MQX_COMPONENT_DOES_NOT_EXIST);
    } /* Endif */
#endif
#if MQX_CHECK_VALIDITY
    if (sem_component_ptr->VALID != SEM_VALID)
    {
        _KLOGX3(KLOG_sem_open, MQX_INVALID_COMPONENT_BASE, 0);
        return(MQX_INVALID_COMPONENT_BASE);
    } /* Endif */
#endif

    result = _name_find_internal(sem_component_ptr->NAME_TABLE_HANDLE,
                    name_ptr, &tmp);
#if MQX_CHECK_ERRORS
    if (result != MQX_OK)
    {
        if (result == NAME_NOT_FOUND)
        {
            _KLOGX3(KLOG_sem_open, SEM_SEMAPHORE_NOT_FOUND, NULL);
            return(SEM_SEMAPHORE_NOT_FOUND);
        } /* Endif */
        _KLOGX3(KLOG_sem_open, result, 0);
        return(result);
    } /* Endif */
#endif

    sem_ptr = (SEM_STRUCT_PTR)tmp;

#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != SEM_VALID)
    {
        /* Semaphore not valid */
        _KLOGX2(KLOG_sem_open, SEM_INVALID_SEMAPHORE);
        return(SEM_INVALID_SEMAPHORE);
    } /* Endif */
#endif

#if MQX_COMPONENT_DESTRUCTION
    if (sem_ptr->DELAYED_DESTROY)
    {
        /* Semaphore in delayed destroy state */
        _KLOGX3(KLOG_sem_open, SEM_SEMAPHORE_DELETED, 0);
        return(SEM_SEMAPHORE_DELETED);
    } /* Endif */
#endif

    sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)
    _mem_alloc_zero((_mem_size)sizeof(SEM_CONNECTION_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (sem_connection_ptr == NULL)
    {
        _KLOGX3(KLOG_sem_open, MQX_OUT_OF_MEMORY, 0);
        return(MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(sem_connection_ptr, MEM_TYPE_SEMAPHORE_CONNECTION);

    sem_connection_ptr->SEM_PTR = sem_ptr;
    sem_connection_ptr->VALID = SEM_VALID;
    sem_connection_ptr->TD_PTR = kernel_data->ACTIVE_PTR;

    *returned_sem_ptr = (void *)sem_connection_ptr;

    _KLOGX3(KLOG_sem_open, MQX_OK, sem_connection_ptr);
    return(MQX_OK);

} /* Endbody */

/*!
 * \brief Returns a semaphore to the semaphore, so another task may use it.
 * 
 * MQX gives the semaphore to the first waiting task and puts the task in the 
 * task's ready queue.
 * 
 * \param[in] users_sem_ptr Semaphore handle from _sem_open() or _sem_open_fast().
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return SEM_INVALID_SEMAPHORE_HANDLE (One of the following:
 * \li Sem_handle is not a valid semaphore handle.
 * \li Semaphore is strict and sem_handle was obtained byanother task.)
 * \return SEM_CANNOT_POST (Semaphore is strict and the task has not first waited 
 * for the semaphore.)
 * \return SEM_INVALID_SEMAPHORE (Sem_handle represents a semaphore that is no 
 * longer valid.)
 * \return SEM_INVALID_SEMAPHORE_COUNT (Semaphore data are corrupted.)
 * 
 * \warning Might put a task in its ready queue.
 * \warning For a strict semaphore, cannot be called from an ISR (ISR can call 
 * the function for a non-strict semaphore).
 * 
 * \see _sem_open
 * \see _sem_open_fast
 * \see _sem_get_wait_count
 * \see _sem_get_value
 * \see _sem_wait
 * \see _sem_wait_for
 * \see _sem_wait_ticks
 * \see _sem_wait_until      
 */ 
_mqx_uint _sem_post
(
    void   *users_sem_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR    kernel_data;
    SEM_STRUCT_PTR            sem_ptr;
#if MQX_COMPONENT_DESTRUCTION
    SEM_COMPONENT_STRUCT_PTR  sem_component_ptr;
#endif
    SEM_CONNECTION_STRUCT_PTR new_sem_connection_ptr;
    SEM_CONNECTION_STRUCT_PTR sem_connection_ptr;
    TD_STRUCT_PTR             new_td_ptr;
    bool                   task_added = FALSE;
    bool                   destroying_semaphore = FALSE;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_sem_post, users_sem_ptr);

    sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)users_sem_ptr;

#if MQX_CHECK_VALIDITY
    if (sem_connection_ptr->VALID != SEM_VALID)
    {
        _KLOGX2(KLOG_sem_post, SEM_INVALID_SEMAPHORE_HANDLE);
        return(SEM_INVALID_SEMAPHORE_HANDLE);
    } /* Endif */
#endif

    sem_ptr = sem_connection_ptr->SEM_PTR;

#if MQX_CHECK_ERRORS
    if (sem_ptr->POLICY & SEM_STRICT)
    {
        if (kernel_data->IN_ISR)
        {
            _KLOGX2(KLOG_sem_post, MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
            return(MQX_CANNOT_CALL_FUNCTION_FROM_ISR);
        } /* Endif */

        if (sem_connection_ptr->TD_PTR != kernel_data->ACTIVE_PTR)
        {
            /* ONLY OPENING task can use the semaphore */
            _KLOGX2(KLOG_sem_post, SEM_INVALID_SEMAPHORE_HANDLE);
            return(SEM_INVALID_SEMAPHORE_HANDLE);
        } /* Endif */

        if (sem_connection_ptr->POST_STATE == 0)
        {
            _KLOGX2(KLOG_sem_post, SEM_CANNOT_POST);
            return(SEM_CANNOT_POST);
        } /* Endif */
    } /* Endif */
#endif

    _INT_DISABLE();

#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != SEM_VALID)
    {
        _int_enable();
        _KLOGX2(KLOG_sem_post, SEM_INVALID_SEMAPHORE);
        return(SEM_INVALID_SEMAPHORE);
    } /* Endif */
#endif

    if (sem_ptr->POLICY & SEM_STRICT)
    {
#if MQX_CHECK_ERRORS
        if (sem_ptr->COUNT > sem_ptr->MAX_COUNT)
        {
            /* Corruption somewhere */
            _int_enable();
            _KLOGX2(KLOG_sem_post, SEM_INVALID_SEMAPHORE_COUNT);
            return(SEM_INVALID_SEMAPHORE_COUNT);
        } /* Endif */
#endif

        --sem_connection_ptr->POST_STATE;
        if (sem_connection_ptr->POST_STATE == 0)
        {
            _QUEUE_REMOVE(&sem_ptr->OWNING_TASKS, sem_connection_ptr);
        } /* Endif */
    } /* Endif */

    if (_QUEUE_GET_SIZE(&sem_ptr->WAITING_TASKS))
    {
        /* Schedule a waiting task to run */

        new_sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)
        ((void *)sem_ptr->WAITING_TASKS.NEXT);
        while (new_sem_connection_ptr != (void *)&sem_ptr->WAITING_TASKS)
        {
            new_td_ptr = new_sem_connection_ptr->TD_PTR;
            if ((new_td_ptr->STATE & STATE_MASK) == SEM_BLOCKED)
            {
                _TIME_DEQUEUE(new_td_ptr, kernel_data);
                _TASK_READY(new_td_ptr, kernel_data);
                new_td_ptr->INFO = SEM_AVAILABLE;
                task_added = TRUE;
                break;
            } /* Endif */
            new_sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)
            new_sem_connection_ptr->NEXT;
        } /* Endwhile */

    } /* Endif */

    if (!task_added)
    {

        ++sem_ptr->COUNT;

#if MQX_COMPONENT_DESTRUCTION
        if ( sem_ptr->DELAYED_DESTROY )
        {
            if ( ( (sem_ptr->POLICY & SEM_STRICT) &&
                   (sem_ptr->COUNT == sem_ptr->MAX_COUNT) ) ||
                 ( !(sem_ptr->POLICY & SEM_STRICT) ) )
            {
                /* Destroy the semaphore name */
                sem_ptr->VALID = 0;
                destroying_semaphore = TRUE;
            } /* Endif */
        } /* Endif */
#endif
    } /* Endif */

    if (sem_connection_ptr->BOOSTED && (sem_connection_ptr->POST_STATE == 0))
    {
        /* This task was boosted by a waiting task */
        _sched_unboost_priority_internal(kernel_data->ACTIVE_PTR,
                        sem_connection_ptr->BOOSTED);
        sem_connection_ptr->BOOSTED = 0;
    } /* Endif */

    _INT_ENABLE();

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

#if MQX_COMPONENT_DESTRUCTION
    if (destroying_semaphore)
    {
        sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
        kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
        if (sem_component_ptr != NULL)
        {
            _name_delete_internal(sem_component_ptr->NAME_TABLE_HANDLE,
                                  sem_ptr->NAME);
        } /* Endif */
        _mem_free(sem_ptr);
    } /* Endif */
#endif

    _KLOGX2(KLOG_sem_post, MQX_OK);
    return(MQX_OK);

} /* Endbody */

/*!
 * \brief Used during task destruction to free up any semaphore resources owned 
 * by this task.
 * 
 * \param[in] td_ptr The task being destroyed. 
 */ 
void _sem_cleanup
(
    TD_STRUCT_PTR td_ptr
)
{ /* Body */
    SEM_CONNECTION_STRUCT_PTR sem_connection_ptr;
    SEM_CONNECTION_STRUCT_PTR connection_ptr;
    SEM_STRUCT_PTR            sem_ptr;

    connection_ptr = _mem_get_next_block_internal(td_ptr, NULL);
    while (connection_ptr)
    {
        if ((connection_ptr->VALID == SEM_VALID) &&
                        (connection_ptr->TD_PTR == td_ptr) )
        {
            sem_ptr = connection_ptr->SEM_PTR;
            if (sem_ptr->VALID == SEM_VALID)
            {
                /* Check if the connection is on the queue */
                _int_disable();
                sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)
                ((void *)sem_ptr->WAITING_TASKS.NEXT);
                while (sem_connection_ptr != (void *)&sem_ptr->WAITING_TASKS.NEXT)
                {
                    if (sem_connection_ptr == connection_ptr)
                    {
                        /* Connection is queued, so dequeue it */
                        _QUEUE_REMOVE(&sem_ptr->WAITING_TASKS, connection_ptr);
                        break;
                    }/* Endif */
                    sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)
                    sem_connection_ptr->NEXT;
                } /* Endwhile */
                if (sem_ptr->POLICY & SEM_STRICT)
                {
                    while (connection_ptr->POST_STATE)
                    {
                        _sem_post(connection_ptr);
                    } /* Endwhile */
                }/* Endif */
                _int_enable();
            }/* Endif */
        } /* Endif */
        connection_ptr = (SEM_CONNECTION_STRUCT_PTR)
        _mem_get_next_block_internal(td_ptr, connection_ptr);
    } /* Endwhile */

} /* Endbody */

/*!
 * \brief Tests the semaphore component for validity and consistency.
 * 
 * The function does the following:
 * \li Verifies semaphore component data.
 * \li Verifies the integrity of the entries in the semaphore names database.
 * \li For each semaphore, checks: validity of data (VALID field), integrity of 
 * the queue of waiting tasks and integrity of the queue of tasks that have the 
 * semaphore.
 * 
 * \param[out] sem_error_ptr Pointer to the semaphore that has an error (NULL if 
 * no errors are found).
 * 
 * \return MQX_OK (No errors were found.)
 * \return MQX_CORRUPT_QUEUE (Error was found in a semaphore queue.) 
 * \return MQX_INVALID_COMPONENT_BASE (Error was found in semaphore component data.)
 * \return SEM_INVALID_SEMAPHORE (Error was found in semaphore data.)
 * 
 * \warning Disables and enables interrupts.
 * 
 * \see _sem_close
 * \see _sem_create
 * \see _sem_create_fast
 * \see _sem_open
 * \see _sem_open_fast
 * \see _sem_post
 * \see _sem_wait
 * \see _sem_wait_for
 * \see _sem_wait_ticks
 * \see _sem_wait_until 
 */ 
_mqx_uint _sem_test
(
    void    **sem_error_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR   kernel_data;
    SEM_COMPONENT_STRUCT_PTR sem_component_ptr;
    SEM_STRUCT_PTR           sem_ptr;
    void                    *table_ptr;
    _mqx_max_type            data;
    _mqx_uint                result;
    _mqx_uint                i;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_sem_test, sem_error_ptr);

    *sem_error_ptr = NULL;

    sem_component_ptr = (SEM_COMPONENT_STRUCT_PTR)
    kernel_data->KERNEL_COMPONENTS[KERNEL_SEMAPHORES];
    if (sem_component_ptr == NULL)
    {
        _KLOGX3(KLOG_sem_test, MQX_OK, 0);
        return(MQX_OK);
    } /* Endif */

    if (sem_component_ptr->VALID != SEM_VALID)
    {
        _KLOGX3(KLOG_sem_test, MQX_INVALID_COMPONENT_BASE, 0);
        return(MQX_INVALID_COMPONENT_BASE);
    } /* Endif */

    _int_disable();
    /* Test the semaphore name table */
    result = _name_test_internal((NAME_COMPONENT_STRUCT_PTR)
                    sem_component_ptr->NAME_TABLE_HANDLE, &table_ptr, sem_error_ptr);
    _int_enable();
    if (result != MQX_OK)
    {
        _KLOGX3(KLOG_sem_test, MQX_INVALID_COMPONENT_BASE, *sem_error_ptr);
        return(MQX_INVALID_COMPONENT_BASE);
    } /* Endif */

    i = 0;
    while (TRUE)
    {
        _int_disable();
        result = _name_find_internal_by_index(
                        sem_component_ptr->NAME_TABLE_HANDLE, i++, &data);
        if (result != MQX_OK)
        {
            result = MQX_OK;
            break;
        } /* Endif */

        sem_ptr = (SEM_STRUCT_PTR)data;
        if (sem_ptr->VALID != SEM_VALID)
        {
            result = SEM_INVALID_SEMAPHORE;
            break;
        } /* Endif */
        result = _queue_test(&sem_ptr->WAITING_TASKS, sem_error_ptr);
        if (result != MQX_OK)
        {
            break;
        } /* Endif */
        result = _queue_test(&sem_ptr->OWNING_TASKS, sem_error_ptr);
        if (result != MQX_OK)
        {
            break;
        } /* Endif */
        _int_enable();

    } /* Endwhile */

    _int_enable();

    _KLOGX3(KLOG_sem_test, result, *sem_error_ptr);
    return(result);

} /* Endbody */

/*!
 * \brief Gets the value of the semaphore counter; that is, the number of 
 * subsequent requests that can get the semaphore without waiting.
 * 
 * \param[in] users_sem_ptr Semaphore handle from _sem_open() or _sem_open_fast().
 * 
 * \return Current value of the semaphore counter (success).
 * \return MAX_MQX_UINT (failure)
 * 
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li SEM_INVALID_SEMAPHORE_HANDLE (Sem_ptr is not a valid semaphore handle.)
 * \li SEM_INVALID_SEMAPHORE (Sem_ptr does not point to a valid semaphore.)
 * 
 * \see _sem_open
 * \see _sem_open_fast
 * \see _sem_post
 * \see _sem_get_wait_count
 * \see _sem_wait
 * \see _sem_wait_for
 * \see _sem_wait_ticks
 * \see _sem_wait_until 
 * \see _task_set_error
 */ 
_mqx_uint _sem_get_value
(
    void   *users_sem_ptr
)
{ /* Body */
    register SEM_CONNECTION_STRUCT_PTR sem_connection_ptr;
    register SEM_STRUCT_PTR            sem_ptr;

    sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)users_sem_ptr;
#if MQX_CHECK_VALIDITY
    if (sem_connection_ptr->VALID != SEM_VALID)
    {
        _task_set_error(SEM_INVALID_SEMAPHORE_HANDLE);
        return(MAX_MQX_UINT);
    } /* Endif */
#endif

    sem_ptr = sem_connection_ptr->SEM_PTR;
#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != SEM_VALID)
    {
        _task_set_error(SEM_INVALID_SEMAPHORE);
        return(MAX_MQX_UINT);
    } /* Endif */
#endif

    return(sem_ptr->COUNT);

} /* Endbody */

/*!
 * \brief Gets the number of tasks that are waiting for the semaphore.
 * 
 * \param[in] users_sem_ptr Semaphore handle from _sem_open() or _sem_open_fast().
 * 
 * \return Number of tasks waiting for the semaphore (success).
 * \return MAX_MQX_UINT (failure)
 * 
 * \warning On failure, calls _task_set_error() to set one of the task error codes 
 * described for _sem_get_value().
 *               
 * \see _sem_get_value 
 * \see _sem_open
 * \see _sem_open_fast
 * \see _sem_post
 * \see _sem_wait
 * \see _sem_wait_for
 * \see _sem_wait_ticks
 * \see _sem_wait_until 
 * \see _task_set_error  
 */ 
_mqx_uint _sem_get_wait_count
(
    void   *users_sem_ptr
)
{ /* Body */
    register SEM_CONNECTION_STRUCT_PTR sem_connection_ptr;
    register SEM_STRUCT_PTR            sem_ptr;

    sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)users_sem_ptr;
#if MQX_CHECK_VALIDITY
    if (sem_connection_ptr->VALID != SEM_VALID)
    {
        _task_set_error(SEM_INVALID_SEMAPHORE_HANDLE);
        return(MAX_MQX_UINT);
    } /* Endif */
#endif

    sem_ptr = sem_connection_ptr->SEM_PTR;
#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != SEM_VALID)
    {
        _task_set_error(SEM_INVALID_SEMAPHORE);
        return(MAX_MQX_UINT);
    } /* Endif */
#endif

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

} /* Endbody */

/*!
 * \private
 * 
 * \brief This function waits for a semaphore to become available. If one is not
 * the task is queued according to the queueing policy for this semaphore.
 *   
 * \param[in] users_sem_ptr      Semaphore handle from _sem_open() or 
 * _sem_open_fast().
 * \param[in] tick_ptr           One of the following:
 * \li Pointer to the maximum number of ticks to wait.
 * \li NULL (Unlimited wait.)
 * \param[in] ticks_are_absolute Specifies whether the wait time specified in 
 * ticks represents absolute or relative time.
 *  
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_EDEADLK (Function was aborted to prevent deadlock: the task has 
 * all the semaphore locks and, since the semaphore is strict, the task cannot 
 * post to "wake" itself.)
 * \return SEM_INVALID_SEMAPHORE_HANDLE (One of the following:
 * \li Sem_handle is not a valid semaphore handle.
 * \li Sem_handle was obtained by another task.)
 * \return SEM_INVALID_SEMAPHORE (Sem_handle is for a semaphore that is no longer 
 * valid.)
 * \return SEM_SEMAPHORE_DELETED (MQX is in the process of destroying the semaphore.)
 * \return SEM_WAIT_TIMEOUT (Timeout expired before the task can get the semaphore.)
 */ 
_mqx_uint _sem_wait_internal
(
    void               *users_sem_ptr,
    MQX_TICK_STRUCT_PTR tick_ptr,
    bool             ticks_are_absolute

)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR             kernel_data;
    TD_STRUCT_PTR                      td_ptr;
    SEM_STRUCT_PTR                     sem_ptr;
    register SEM_CONNECTION_STRUCT_PTR sem_connection_ptr;
    register SEM_CONNECTION_STRUCT_PTR list_connection_ptr;
    SEM_CONNECTION_STRUCT_PTR          saved_connection_ptr;
    _mqx_uint                          priority;

    _GET_KERNEL_DATA(kernel_data);

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

    sem_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)users_sem_ptr;

#if MQX_CHECK_VALIDITY
    if (sem_connection_ptr->VALID != SEM_VALID)
    {
        return(SEM_INVALID_SEMAPHORE_HANDLE);
    } /* Endif */
#endif

    sem_ptr = sem_connection_ptr->SEM_PTR;
    td_ptr = kernel_data->ACTIVE_PTR;

#if MQX_CHECK_ERRORS
    if (sem_connection_ptr->TD_PTR != td_ptr)
    {
        /* Only OPENING task can wait on the semaphore */
        return(SEM_INVALID_SEMAPHORE_HANDLE);
    } /* Endif */
#endif

    _INT_DISABLE();

#if MQX_CHECK_VALIDITY
    if (sem_ptr->VALID != SEM_VALID)
    {
        _int_enable();
        return(SEM_INVALID_SEMAPHORE);
    } /* Endif */
#endif

    if (sem_ptr->COUNT == 0)
    {

        /* Must wait for a semaphore to become available */
        if (sem_ptr->POLICY & SEM_STRICT)
        {

            /* 
             * First check for deadlock... See if this task already
             * owns all the semaphores, thus cannot post to wake itself up
             */
            if (sem_connection_ptr->POST_STATE == sem_ptr->MAX_COUNT)
            {
                _int_enable();
                return(MQX_EDEADLK);
            } /* Endif */

            /* 
             * May need to raise priorities of one task with semaphore,
             * If the current task has a higher priority.
             */
            if ((sem_ptr->POLICY & SEM_PRIORITY_INHERITANCE) &&
                            (_QUEUE_GET_SIZE(&sem_ptr->OWNING_TASKS) > 0))
            {

                /* Find owning task with highest priority */
                list_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)
                ((void *)sem_ptr->OWNING_TASKS.NEXT);
                saved_connection_ptr = list_connection_ptr;
                priority = kernel_data->LOWEST_TASK_PRIORITY;
                while ((void *)list_connection_ptr !=
                                (void *)&sem_ptr->OWNING_TASKS)
                {
                    if (list_connection_ptr->TD_PTR->MY_QUEUE->PRIORITY < priority)
                    {
                        priority = list_connection_ptr->TD_PTR->MY_QUEUE->PRIORITY;
                        saved_connection_ptr = list_connection_ptr;
                    } /* Endif */
                    list_connection_ptr = (SEM_CONNECTION_STRUCT_PTR)
                    list_connection_ptr->NEXT;
                } /* Endwhile */

                if (priority > td_ptr->HOME_QUEUE->PRIORITY)
                {
                    if (priority > td_ptr->MY_QUEUE->PRIORITY)
                    {
                        /* Not high enough, boost the tasks priority */
                        _sched_boost_priority_internal(saved_connection_ptr->TD_PTR,
                                        (_mqx_uint)td_ptr->MY_QUEUE->PRIORITY);
                    } /* Endif */
                    saved_connection_ptr->BOOSTED++;
                } /* Endif */
            } /* Endif */
        } /* Endif */

        if (sem_ptr->POLICY & SEM_PRIORITY_QUEUEING)
        {
            /* 
             * We must insert the waiting task into the waiting list in order
             * of the priority of the waiting task.
             */
            _sem_insert_priority_internal(&sem_ptr->WAITING_TASKS, sem_connection_ptr);
        }
        else
        {
            /* Enqueue at end */
            _QUEUE_ENQUEUE(&sem_ptr->WAITING_TASKS, sem_connection_ptr);
        } /* Endif */

        /* Now put the task to sleep */
        td_ptr->STATE = SEM_BLOCKED;
        td_ptr->INFO = SEM_WANT_SEMAPHORE;
        /* Indicate wanting semaphore */

        if (tick_ptr)
        {

            if (ticks_are_absolute)
            {
                _time_delay_until(tick_ptr);
            }
            else
            {
                _time_delay_for(tick_ptr);
            } /* Endif */

#if MQX_COMPONENT_DESTRUCTION
            if (sem_ptr->VALID != SEM_VALID)
            {
                _int_enable();
                return(SEM_SEMAPHORE_DELETED);
            } /* Endif */
#endif

            _QUEUE_REMOVE(&sem_ptr->WAITING_TASKS, sem_connection_ptr);

            if (td_ptr->INFO != SEM_AVAILABLE)
            {
                td_ptr->INFO = 0;
                _INT_ENABLE();
                return(SEM_WAIT_TIMEOUT);
            } /* Endif */

        }
        else
        {

            _task_block();

#if MQX_COMPONENT_DESTRUCTION
            if (sem_ptr->VALID != SEM_VALID)
            {
                _int_enable();
                return(SEM_SEMAPHORE_DELETED);
            } /* Endif */
#endif
            _QUEUE_REMOVE(&sem_ptr->WAITING_TASKS, sem_connection_ptr);

#if MQX_COMPONENT_DESTRUCTION
            if (td_ptr->INFO != SEM_AVAILABLE)
            {
                td_ptr->INFO = 0;
                _INT_ENABLE();
                return(SEM_SEMAPHORE_DELETED);
            } /* Endif */
#endif

        } /* Endif */

    }
    else
    {
        --sem_ptr->COUNT;
    } /* Endif */

    if (sem_ptr->POLICY & SEM_STRICT)
    {
        if (sem_connection_ptr->POST_STATE == 0)
        {
            _QUEUE_ENQUEUE(&sem_ptr->OWNING_TASKS, sem_connection_ptr);
        } /* Endif */
        sem_connection_ptr->POST_STATE++; /* # of posts allowed to do */
    } /* Endif */

    _INT_ENABLE();

    return(MQX_OK);

} /* Endbody */

/*!
 * \brief Wait for the semaphore for the specified number of milliseconds.
 * 
 * If the task cannot get the semaphore, MQX queues the task according to the 
 * semaphore's queuing policy, which is set when the semaphore is created.
 * 
 * \param[in] timeout       One of the following:
 * \li Maximum number of milliseconds to wait for the semaphore. After the 
 * timeout elapses without semaphore signalled, function returns.
 * \li 0 (Unlimited wait.)
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_EDEADLK (Function was aborted to prevent deadlock: the task has 
 * all the semaphore locks and, since the semaphore is strict, the task cannot 
 * post to  "wake" itself.)
 * \return SEM_INVALID_SEMAPHORE_HANDLE (One of the following:
 * \li Sem_handle is not a valid semaphore handle.
 * \li Sem_handle was obtained by another task.)
 * \return SEM_INVALID_SEMAPHORE (Sem_handle is for a semaphore that is no longer 
 * valid.)
 * \return SEM_SEMAPHORE_DELETED (MQX is in the process of destroying the semaphore.)
 * \return SEM_WAIT_TIMEOUT (Timeout expired before the task can get the semaphore.)
 * 
 * \warning Might block the calling task.
 * \warning Cannot be called from an ISR.
 * 
 * \see _sem_wait_for
 * \see _sem_wait_ticks
 * \see _sem_wait_until
 * \see _sem_open
 * \see _sem_open_fast
 * \see _sem_post
 * \see _sem_get_wait_count
 * \see _sem_get_value
 * \see _sem_create
 * \see _sem_create_fast
 * \see MQX_TICK_STRUCT
 */ 
_mqx_uint _sem_wait
(
    void   *users_sem_ptr,
    uint32_t timeout
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    MQX_TICK_STRUCT ticks;
    _mqx_uint result;
    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    
    _KLOGE3(KLOG_sem_wait, users_sem_ptr, timeout);

    if (timeout)
    {
        /* Compute the number of tick events required to accomplish the least amount of time[ms]. */
        /* tick_events = (required_time[ms] + (time_per_tick[ms] - 1)) / time_per_tick[ms]) + 1  --> 
         * tick_events = ((required_time[ms] - 1) / time_per_tick[ms]) + 2
         */
        timeout--;
        /* Convert milliseconds to ticks, truncated */
        PSP_MILLISECONDS_TO_TICKS_QUICK(timeout, &ticks);
        /* Increment timeout by 2 ticks to ensure waiting at least required miliseconds */
        PSP_ADD_TICKS_TO_TICK_STRUCT(&ticks, 2, &ticks);

        result = _sem_wait_internal(users_sem_ptr, &ticks, FALSE);
    }
    else
    {
        result = _sem_wait_internal(users_sem_ptr, NULL, FALSE);
    } /* Endif */

    _KLOGX2(KLOG_sem_wait, result);
    return(result);

} /* Endbody */

/*!
 * \brief Wait for the semaphore for the specified number of ticks (in tick time).
 * 
 * If the task cannot get the semaphore, MQX queues the task according to the 
 * semaphore's queuing policy, which is set when the semaphore is created.
 * 
 * \param[in] users_sem_ptr Semaphore handle from _sem_open() or _sem_open_fast().
 * \param[in] tick_ptr      One of the following:
 * \li Pointer to the maximum number of ticks to wait.
 * \li NULL (Unlimited wait.)
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_EDEADLK (Function was aborted to prevent deadlock: the task has 
 * all the semaphore locks and, since the semaphore is strict, the task cannot 
 * post to  "wake" itself.)
 * \return SEM_INVALID_SEMAPHORE_HANDLE (One of the following:
 * \li Sem_handle is not a valid semaphore handle.
 * \li Sem_handle was obtained by another task.)
 * \return SEM_INVALID_SEMAPHORE (Sem_handle is for a semaphore that is no longer 
 * valid.)
 * \return SEM_SEMAPHORE_DELETED (MQX is in the process of destroying the semaphore.)
 * \return SEM_WAIT_TIMEOUT (Timeout expired before the task can get the semaphore.)
 * 
 * \warning Might block the calling task.
 * \warning Cannot be called from an ISR.
 * 
 * \see _sem_wait
 * \see _sem_wait_ticks
 * \see _sem_wait_until
 * \see _sem_open
 * \see _sem_open_fast
 * \see _sem_post
 * \see _sem_get_wait_count
 * \see _sem_get_value
 * \see _sem_create
 * \see _sem_create_fast
 * \see MQX_TICK_STRUCT
 */ 
_mqx_uint _sem_wait_for
(
    void               *users_sem_ptr,
    MQX_TICK_STRUCT_PTR tick_ptr
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    _mqx_uint result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE3(KLOG_sem_wait_for, users_sem_ptr, tick_ptr);

    result = _sem_wait_internal(users_sem_ptr, tick_ptr, FALSE);

    _KLOGX2(KLOG_sem_wait_for, result);
    return(result);

} /* Endbody */

/*!
 * \brief Wait for the semaphore for the specified number of ticks.
 * 
 * If the task cannot get the semaphore, MQX queues the task according to the 
 * semaphore's queuing policy, which is set when the semaphore is created.
 * 
 * \param[in] users_sem_ptr    Semaphore handle from _sem_open() or _sem_open_fast().
 * \param[in] timeout_in_ticks One of the following:
 * \li Maximum number of ticks to wait.
 * \li 0 (Unlimited wait.)
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_EDEADLK (Function was aborted to prevent deadlock: the task has 
 * all the semaphore locks and, since the semaphore is strict, the task cannot 
 * post to  "wake" itself.)
 * \return SEM_INVALID_SEMAPHORE_HANDLE (One of the following:
 * \li Sem_handle is not a valid semaphore handle.
 * \li Sem_handle was obtained by another task.)
 * \return SEM_INVALID_SEMAPHORE (Sem_handle is for a semaphore that is no longer 
 * valid.)
 * \return SEM_SEMAPHORE_DELETED (MQX is in the process of destroying the semaphore.)
 * \return SEM_WAIT_TIMEOUT (Timeout expired before the task can get the semaphore.)
 * 
 * \warning Might block the calling task.
 * \warning Cannot be called from an ISR.
 * 
 * \see _sem_wait
 * \see _sem_wait_for
 * \see _sem_wait_until
 * \see _sem_open
 * \see _sem_open_fast
 * \see _sem_post
 * \see _sem_get_wait_count
 * \see _sem_get_value
 * \see _sem_create
 * \see _sem_create_fast
 * \see MQX_TICK_STRUCT
 */
_mqx_uint _sem_wait_ticks
(
    void     *users_sem_ptr,
    _mqx_uint timeout_in_ticks
)
{ /* Body */
    MQX_TICK_STRUCT ticks;
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    _mqx_uint result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE3(KLOG_sem_wait_ticks, users_sem_ptr, timeout_in_ticks);

    if (timeout_in_ticks)
    {
        ticks = _mqx_zero_tick_struct;

        PSP_GET_ELEMENT_FROM_TICK_STRUCT(&ticks, 0) = timeout_in_ticks;
        result = _sem_wait_internal(users_sem_ptr, &ticks, FALSE);
    }
    else
    {
        result = _sem_wait_internal(users_sem_ptr, NULL, FALSE);
    } /* Endif */

    _KLOGX2(KLOG_sem_wait_ticks, result);
    return(result);

} /* Endbody */

/*!
 * \brief Wait for the semaphore until the specified time (in tick time).
 * 
 * If the task cannot get the semaphore, MQX queues the task according to the 
 * semaphore's queuing policy, which is set when the semaphore is created.
 * 
 * \param[in] users_sem_ptr Semaphore handle from _sem_open() or _sem_open_fast().
 * \param[in] tick_ptr      One of the following:
 * \li Pointer to the time (in tick time) until which to wait.
 * \li NULL (Unlimited wait.)
 * 
 * \return MQX_OK
 * \return MQX_CANNOT_CALL_FUNCTION_FROM_ISR (Function cannot be called from an ISR.)
 * \return MQX_EDEADLK (Function was aborted to prevent deadlock: the task has 
 * all the semaphore locks and, since the semaphore is strict, the task cannot 
 * post to  "wake" itself.)
 * \return SEM_INVALID_SEMAPHORE_HANDLE (One of the following:
 * \li Sem_handle is not a valid semaphore handle.
 * \li Sem_handle was obtained by another task.)
 * \return SEM_INVALID_SEMAPHORE (Sem_handle is for a semaphore that is no longer 
 * valid.)
 * \return SEM_SEMAPHORE_DELETED (MQX is in the process of destroying the semaphore.)
 * \return SEM_WAIT_TIMEOUT (Timeout expired before the task can get the semaphore.)
 * 
 * \warning Might block the calling task.
 * \warning Cannot be called from an ISR.
 * 
 * \see _sem_wait
 * \see _sem_wait_for
 * \see _sem_wait_ticks
 * \see _sem_open
 * \see _sem_open_fast
 * \see _sem_post
 * \see _sem_get_wait_count
 * \see _sem_get_value
 * \see _sem_create
 * \see _sem_create_fast
 * \see MQX_TICK_STRUCT
 */ 
_mqx_uint _sem_wait_until
(
    void               *users_sem_ptr,
    MQX_TICK_STRUCT_PTR tick_ptr
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
    _mqx_uint result;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));

    _KLOGE3(KLOG_sem_wait_until, users_sem_ptr, tick_ptr);

    result = _sem_wait_internal(users_sem_ptr, tick_ptr, TRUE);

    _KLOGX2(KLOG_sem_wait_until, result);
    return(result);

} /* Endbody */

#endif /* MQX_USE_SEMAPHORES */

/* EOF */
