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

#include "mqx_inc.h"
#if MQX_USE_MESSAGES
#include "message.h"
#include "msg_prv.h"

/*!
 * \brief Allocates a message from the private message pool.
 * 
 * The size of the message is determined by the message size that a task 
 * specified when it called _msgpool_create(). The message is a resource of the 
 * task until the task either frees it (_msg_free()) or puts it on a message 
 * queue (_msgq_send() family of functions.)
 * 
 * \param[in] pool A pool ID from _msgpool_create().
 * 
 * \return Pointer to a message (Success.)
 * \return NULL (Failure.)
 *  
 * \warning On failure, calls _task_set_error() to set one the following task 
 * error codes:
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li MSGPOOL_INVALID_POOL_ID (Pool_id is not valid.)
 * \li MSGPOOL_OUT_OF_MESSAGES (All the messages in the pool are allocated.)
 * \li Task error codes from _mem_alloc_system() (If MQX needs to grow the pool.)
 * 
 * \see _msg_alloc_system
 * \see _msg_free
 * \see _msgpool_create
 * \see _msgpool_destroy
 * \see _task_set_error
 * \see _mem_alloc
 * \see _mem_alloc_from
 * \see _mem_alloc_system
 * \see _mem_alloc_system_from
 * \see _mem_alloc_system_zero
 * \see _mem_alloc_system_zero_from
 * \see _mem_alloc_zero
 * \see _mem_alloc_zero_from
 * \see _mem_alloc_align
 * \see _mem_alloc_align_from
 * \see _mem_alloc_at
 * \see MESSAGE_HEADER_STRUCT     
 */ 
void *_msg_alloc
(
    _pool_id pool
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR               kernel_data;
#if MQX_CHECK_ERRORS
    MSG_COMPONENT_STRUCT_PTR             msg_component_ptr;
#endif
    register INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
    register MESSAGE_HEADER_STRUCT_PTR   message_ptr;
    register MSGPOOL_STRUCT_PTR          msgpool_ptr;
    uint16_t                              grow_number;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE2(KLOG_msg_alloc, pool);

#if MQX_CHECK_ERRORS
    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
    if (msg_component_ptr == NULL)
    {
        _task_set_error(MQX_COMPONENT_DOES_NOT_EXIST);
        _KLOGX3(KLOG_msg_alloc, NULL, MQX_COMPONENT_DOES_NOT_EXIST);
        return(NULL);
    } /* Endif */
#endif

    message_ptr = NULL;
    msgpool_ptr = (MSGPOOL_STRUCT_PTR)pool;

#if MQX_CHECK_VALIDITY || MQX_CHECK_ERRORS
    if (
#if MQX_CHECK_VALIDITY
                    (msgpool_ptr->VALID != MSG_VALID)
#if MQX_CHECK_ERRORS
                    ||
#endif
#endif
#if MQX_CHECK_ERRORS
                    (msgpool_ptr->MSGPOOL_TYPE != MSG_POOL)
#endif
    )
    {
        _task_set_error(MSGPOOL_INVALID_POOL_ID);
        _KLOGX3(KLOG_msg_alloc, message_ptr, MSGPOOL_INVALID_POOL_ID);
        return (message_ptr);
    } /* Endif */
#endif

    if ( (msgpool_ptr->SIZE == 0) && (msgpool_ptr->GROW_NUMBER) &&
                    ( (msgpool_ptr->MAX < msgpool_ptr->GROW_LIMIT) ||
                                    (msgpool_ptr->GROW_LIMIT == 0) ) )
    {
        /* Attempt to add elements to the pool */
        grow_number = msgpool_ptr->GROW_NUMBER;
        if (grow_number > (uint16_t)(msgpool_ptr->GROW_LIMIT - msgpool_ptr->MAX))
        {
            grow_number = msgpool_ptr->GROW_LIMIT - msgpool_ptr->MAX;
        } /* Endif */
        _msgpool_add_internal(msgpool_ptr, grow_number);
    } /* Endif */

    _INT_DISABLE();
    imsg_ptr = msgpool_ptr->MSG_FREE_LIST_PTR;
    if (imsg_ptr == NULL)
    {
        _int_enable();
        _task_set_error(MSGPOOL_OUT_OF_MESSAGES);
        _KLOGX3(KLOG_msg_alloc, message_ptr, MSGPOOL_OUT_OF_MESSAGES);
        return((void *)message_ptr);
    } /* Endif */

    msgpool_ptr->MSG_FREE_LIST_PTR = imsg_ptr->NEXT;
    --msgpool_ptr->SIZE;
    _INT_ENABLE();
    imsg_ptr->FREE = FALSE;
    imsg_ptr->QUEUED = FALSE;
    if (kernel_data->IN_ISR)
    {
        imsg_ptr->TD_PTR = NULL;
    }
    else
    {
        imsg_ptr->TD_PTR = kernel_data->ACTIVE_PTR;
    } /* Endif */
    message_ptr = (MESSAGE_HEADER_STRUCT_PTR)&imsg_ptr->MESSAGE;
    message_ptr->TARGET_QID = MSGQ_NULL_QUEUE_ID;
    message_ptr->SOURCE_QID = MSGQ_NULL_QUEUE_ID;
    message_ptr->SIZE = msgpool_ptr->MESSAGE_SIZE;
    message_ptr->CONTROL = MSG_HDR_ENDIAN | MSG_DATA_ENDIAN;
    _KLOGX3(KLOG_msg_alloc, message_ptr, MQX_OK);
    return (void *)message_ptr;

} /* Endbody */

/*!
 * \brief Creates the message component.
 * 
 * The function uses fields in the MQX initialization structure to create the 
 * number of message pools (MAX_MSGPOOLS) and message queues (MAX_MSGQS). MQX 
 * creates the message component if it is not created when an application calls 
 * one of:
 * \li _msgpool_create()
 * \li _msgpool_create_system()
 * \li _msgq_open()
 * \li _msgq_open_system()
 * 
 * \return MQX_OK
 * \return MQX_OUT_OF_MEMORY (MQX is out of memory.)
 * \return MSGPOOL_POOL_NOT_CREATED (MQX cannot allocate the data structures for 
 * message pools.)
 * \return MSGQ_TOO_MANY_QUEUES (MQX cannot allocate the data structures for 
 * message queues.)
 * \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.)       
 */ 
_mqx_uint _msg_create_component(void)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR            kernel_data;
    register MSG_COMPONENT_STRUCT_PTR msg_component_ptr;
    void                             *pools_ptr;
    void                             *msgqs_ptr;
    _mqx_uint                         error;

    _GET_KERNEL_DATA(kernel_data);

    _KLOGE1(KLOG_msg_create_component);

    error = _lwsem_wait((LWSEM_STRUCT_PTR)&kernel_data->COMPONENT_CREATE_LWSEM);
#if MQX_CHECK_ERRORS
    if (error != MQX_OK)
    {
        _KLOGX2(KLOG_msg_create_component, error);
        return(error);
    } /* Endif */
#endif

    if (kernel_data->KERNEL_COMPONENTS[KERNEL_MESSAGES] != NULL)
    {
        _lwsem_post((LWSEM_STRUCT_PTR)&kernel_data->COMPONENT_CREATE_LWSEM);
        _KLOGX2(KLOG_msg_create_component, MQX_OK);
        return(MQX_OK);
    } /* Endif */

    msg_component_ptr = (MSG_COMPONENT_STRUCT_PTR)
    _mem_alloc_system_zero((_mem_size)sizeof(MSG_COMPONENT_STRUCT));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (msg_component_ptr == NULL)
    {
        _lwsem_post((LWSEM_STRUCT_PTR)&kernel_data->COMPONENT_CREATE_LWSEM);
        _KLOGX2(KLOG_msg_create_component, MQX_OUT_OF_MEMORY);
        return(MQX_OUT_OF_MEMORY);
    } /* Endif */
#endif
    _mem_set_type(msg_component_ptr, MEM_TYPE_MESSAGE_COMPONENT);

    if (kernel_data->INIT.MAX_MSGPOOLS == 0)
    {
        kernel_data->INIT.MAX_MSGPOOLS = 1;
    } /* Endif */
    pools_ptr = _mem_alloc_system_zero((_mem_size)(kernel_data->INIT.MAX_MSGPOOLS *
                                    sizeof(MSGPOOL_STRUCT)));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (pools_ptr == NULL)
    {
        _lwsem_post((LWSEM_STRUCT_PTR)&kernel_data->COMPONENT_CREATE_LWSEM);
        _KLOGX2(KLOG_msg_create_component, MSGPOOL_POOL_NOT_CREATED);
        return MSGPOOL_POOL_NOT_CREATED;
    }/* Endif */
#endif
    _mem_set_type(pools_ptr, MEM_TYPE_MESSAGE_POOLS);

    if (kernel_data->INIT.MAX_MSGQS >= MAX_UINT_16)
    {
        kernel_data->INIT.MAX_MSGQS = MAX_UINT_16 - 1;
    }
    else if (kernel_data->INIT.MAX_MSGQS < 1)
    {
        kernel_data->INIT.MAX_MSGQS = 1;
    } /* Endif */
    msgqs_ptr = _mem_alloc_system_zero( (_mem_size)((kernel_data->INIT.MAX_MSGQS + 1) *
                                    sizeof(MSGQ_STRUCT)));
#if MQX_CHECK_MEMORY_ALLOCATION_ERRORS
    if (msgqs_ptr == NULL)
    {
        _lwsem_post((LWSEM_STRUCT_PTR)&kernel_data->COMPONENT_CREATE_LWSEM);
        _mem_free(pools_ptr);
        _KLOGX2(KLOG_msg_create_component, MSGQ_TOO_MANY_QUEUES);
        return MSGQ_TOO_MANY_QUEUES;
    } /* Endif */
#endif
    _mem_set_type(msgqs_ptr, MEM_TYPE_MESSAGE_QUEUES);

    if (msg_component_ptr->MSGPOOLS_PTR == NULL)
    {
        msg_component_ptr->MAX_MSGPOOLS_EVER = 0;
        msg_component_ptr->SMALLEST_MSGPOOL_PTR = NULL;
        msg_component_ptr->LARGEST_MSGPOOL_PTR = NULL;
        msg_component_ptr->MAX_MSGPOOLS = kernel_data->INIT.MAX_MSGPOOLS;
        msg_component_ptr->MAX_MSGQS = kernel_data->INIT.MAX_MSGQS;
        msg_component_ptr->MSGPOOLS_PTR = (MSGPOOL_STRUCT_PTR)pools_ptr;
        pools_ptr = NULL;
        msg_component_ptr->MSGQS_PTR = (MSGQ_STRUCT_PTR)msgqs_ptr;
        msgqs_ptr = NULL;
    }/* Endif */

    msg_component_ptr->VALID = MESSAGE_VALID;

    kernel_data->KERNEL_COMPONENTS[KERNEL_MESSAGES] = msg_component_ptr;

#if MQX_COMPONENT_DESTRUCTION
    kernel_data->COMPONENT_CLEANUP[KERNEL_MESSAGES] = _msg_cleanup;
#endif

    _lwsem_post((LWSEM_STRUCT_PTR)&kernel_data->COMPONENT_CREATE_LWSEM);

    if (pools_ptr)
    {
        _mem_free(pools_ptr);
    }/* Endif */
    if (msgqs_ptr)
    {
        _mem_free(msgqs_ptr);
    }/* Endif */

    _KLOGX2(KLOG_msg_create_component, MQX_OK);
    return MQX_OK;

} /* Endbody */

/*!
 * \brief Marks the message as "free".
 * 
 * Only the task that has the message as its resource can free the message. A 
 * message becomes a task's resource when the task allocates the message, and it 
 * continues to be a resource until the task either frees it or puts it in a 
 * message queue. A message becomes a resource of the task that got it from a 
 * message queue.
 * \n The function returns the message to the message pool from which it was 
 * allocated.
 * 
 * \param[in] msg_ptr Pointer to a message struct which is to be freed.
 * 
 * \warning On failure, calls _task_set_error() to set one the following task 
 * error codes:
 * \li MQX_INVALID_POINTER (Msg_ptr does not point to a valid message.)
 * \li MQX_NOT_RESOURCE_OWNER (Message is already freed.)
 * \li MSGQ_MESSAGE_IS_QUEUED (Message is in a queue.)
 * 
 * \see _msgpool_create
 * \see _msgpool_create_system
 * \see _msgpool_destroy
 * \see _msg_alloc_system
 * \see _msg_alloc
 * \see _task_set_error
 * \see MESSAGE_HEADER_STRUCT    
 */ 
void _msg_free
(
    void   *msg_ptr
)
{ /* Body */
    _KLOGM(KERNEL_DATA_STRUCT_PTR       kernel_data);
    register INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
    register MSGPOOL_STRUCT_PTR          msgpool_ptr;

    _KLOGM(_GET_KERNEL_DATA(kernel_data));
    _KLOGE2(KLOG_msg_free, msg_ptr);

    imsg_ptr = GET_INTERNAL_MESSAGE_PTR(msg_ptr);
#if MQX_CHECK_VALIDITY
    if ( imsg_ptr->VALID != MSG_VALID )
    {
        _KLOGX2(KLOG_msg_free, MQX_INVALID_POINTER);
        _task_set_error(MQX_INVALID_POINTER);
        return;
    } /* Endif */
#endif

#if MQX_CHECK_ERRORS
    if (imsg_ptr->FREE)
    {
        _KLOGX2(KLOG_msg_free, MQX_NOT_RESOURCE_OWNER);
        _task_set_error(MQX_NOT_RESOURCE_OWNER);
        return;
    } /* Endif */
    if (imsg_ptr->QUEUED)
    {
        _KLOGX2(KLOG_msg_free, MSGQ_MESSAGE_IS_QUEUED);
        _task_set_error(MSGQ_MESSAGE_IS_QUEUED);
        return;
    } /* Endif */
#endif

    msgpool_ptr = imsg_ptr->MSGPOOL_PTR;
    imsg_ptr->FREE = TRUE;
    imsg_ptr->QUEUED = FALSE;

    _INT_DISABLE();
    /* Link onto the free list */
    imsg_ptr->NEXT = msgpool_ptr->MSG_FREE_LIST_PTR;
    msgpool_ptr->MSG_FREE_LIST_PTR = imsg_ptr;
    ++msgpool_ptr->SIZE;
    _INT_ENABLE();

    _KLOGX2(KLOG_msg_free, MQX_OK);

} /* Endbody */

/*!
 * \brief Gets the number of free messages in the message pool.
 * 
 * The function fails if either:
 * \li Message component is not created.
 * \li Pool_id is for a private message pool, but does not represent a valid one.
 * 
 * \param[in] pool One of the following:
 * \li Private message pool for which to get the number of free messages.
 * \li MSGPOOL_NULL_POOL_ID (for system message pools).
 * 
 * \return The number of free messages in the private message pool (success).
 * \return The number of free messages in all system message pools (success).
 * \return 0 (Success: No free messages.)
 * \return 0 (Failure: see Description.)
 * 
 * \warning If pool_id does not represent a valid private message pool, calls 
 * _task_set_error() to set the task error code to MSGPOOL_INVALID_POOL_ID
 * 
 * \see _msgpool_create
 * \see _msgpool_destroy
 * \see _msg_free
 * \see _msg_alloc_system
 * \see _task_set_error
 * \see _msg_create_component      
 */ 
_mqx_uint _msg_available
(
    _pool_id pool
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR      kernel_data;
    MSG_COMPONENT_STRUCT_PTR    msg_component_ptr;
    register MSGPOOL_STRUCT_PTR msgpool_ptr;
    _mqx_uint                   i;
    _mqx_uint                   count;

    _GET_KERNEL_DATA(kernel_data);

    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        return(0);
    } /* Endif */
#endif

    msgpool_ptr = msg_component_ptr->MSGPOOLS_PTR;
#if MQX_CHECK_ERRORS
    if (msgpool_ptr == NULL)
    {
        return(0);
    }/* Endif */
#endif

    if (pool == MSGPOOL_NULL_POOL_ID)
    {

        count = 0;
        _INT_DISABLE();
        i = msg_component_ptr->MAX_MSGPOOLS_EVER + 1;
        while ( --i )
        {
            if (
#if MQX_CHECK_VALIDITY
                (msgpool_ptr->VALID == MSG_VALID) &&
#endif
                (msgpool_ptr->MSGPOOL_TYPE == SYSTEM_MSG_POOL))
            {
                count += msgpool_ptr->SIZE;
            } /* Endif */
            ++msgpool_ptr;
        } /* Endwhile */
        _INT_ENABLE();
        return count;

    }
    else
    {

        msgpool_ptr = (MSGPOOL_STRUCT_PTR)pool;
        if (
#if MQX_CHECK_VALIDITY
            (msgpool_ptr->VALID != MSG_VALID) ||
#endif
            (msgpool_ptr->MSGPOOL_TYPE != MSG_POOL) )
        {
            _task_set_error(MSGPOOL_INVALID_POOL_ID);
            return (0);
        } /* Endif */
        return (_mqx_uint)msgpool_ptr->SIZE;

    } /* Endif */

} /* Endbody */

/*!
 * \brief Converts the messages header from intel to motorola byte order (or vice 
 * versa).
 * 
 * The function is not needed for general application code because the IPC 
 * component converts the message header. Use it only if you are writing IPC 
 * message drivers for a new BSP.
 * \n The function calls _mem_swap_endian() and uses the field sizes of 
 * MESSAGE_HEADER_STRUCT to convert the header to the other endian format.
 * \n The macro MSG_MUST_CONVERT_HDR_ENDIAN determines whether the message 
 * header needs to be converted to the other endian format.
 * 
 * \param[in] message_ptr Pointer to a message whosenn header is to be converted.
 * 
 * \warning Sets CONTROL in the message header to indicate the correct endian 
 * format for the processor.
 * 
 * \see _mem_swap_endian
 * \see _msg_swap_endian_data
 * \see MSG_MUST_CONVERT_HDR_ENDIAN
 * \see MESSAGE_HEADER_STRUCT  
 */ 
static const unsigned char _KRNL_Hdr_def[] =
{
    sizeof(_msg_size),
#if MQX_USE_32BIT_MESSAGE_QIDS
    sizeof(uint16_t),
#endif
    sizeof(_queue_id),
    sizeof(_queue_id),
    0
};

void _msg_swap_endian_header
(
    register MESSAGE_HEADER_STRUCT_PTR message_ptr
)
{ /* Body */

    _mem_swap_endian( (unsigned char *)_KRNL_Hdr_def, (void *)&(message_ptr->SIZE));
    message_ptr->CONTROL &= ~MSG_HDR_ENDIAN_MASK;
    message_ptr->CONTROL |= MSG_HDR_ENDIAN;

} /* Endbody */

/*!
 * \brief Converts the data portion of the message from intel to motorola byte 
 * order ( or vice versa ).
 * 
 * The function calls _mem_swap_endian() and uses definition to swap 
 * single-addressable units: message_ptr + sizeof(MESSAGE_HEADER_STRUCT)
 * \n The macro MSG_MUST_CONVERT_DATA_ENDIAN determines whether the data portion 
 * of the message needs to be converted to the other endian format.
 * 
 * \param[in] definition  Pointer to an array (NULL-terminated), each element of 
 * which defines the size (in single-addressable units) of fields in the data 
 * portion of the message.
 * \param[in] message_ptr Pointer to the message whose data is to be converted.
 * 
 * \warning Sets CONTROL in the message header to indicate the correct endian 
 * format for the processor.
 * 
 * \see _mem_swap_endian
 * \see MSG_MUST_CONVERT_DATA_ENDIAN
 * \see MESSAGE_HEADER_STRUCT 
 */ 
void _msg_swap_endian_data
(
    unsigned char                         *definition,
    register MESSAGE_HEADER_STRUCT_PTR message_ptr
)
{ /* Body */

    _mem_swap_endian( definition, (void *)((unsigned char *)message_ptr +
                                    sizeof(MESSAGE_HEADER_STRUCT)) );
    message_ptr->CONTROL &= ~MSG_DATA_ENDIAN_MASK;
    message_ptr->CONTROL |= MSG_DATA_ENDIAN;

} /* Endbody */

/*!
 * \brief This function is called when a task is being destroyed.
 * 
 * Closes all open message queues and then free all messages owned by this task.
 * 
 * \param[in] td_ptr The task descriptor of the task that is being destroyed.   
 */ 
void _msg_cleanup
(
    TD_STRUCT_PTR td_ptr
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR      kernel_data;
    MSG_COMPONENT_STRUCT_PTR    msg_component_ptr;
    MSGQ_STRUCT_PTR             msgq_ptr;
    MSGQ_STRUCT_PTR             qprev_ptr;
    MSGPOOL_STRUCT_PTR          msgpool_ptr;
    MSGPOOL_BLOCK_STRUCT_PTR    msgpool_block_ptr;
    INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
    INTERNAL_MESSAGE_STRUCT_PTR tmp_imsg_ptr;
    _mqx_uint                   i,j,raw_message_size;

    _GET_KERNEL_DATA(kernel_data);
    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        return;
    } /* Endif */
#endif

    /* Delete the message queues owned by the task, and free the messages
     * on the queues
     */
    msgq_ptr = (MSGQ_STRUCT_PTR)td_ptr->MSG_QUEUE_HEAD;
    while (msgq_ptr != NULL)
    {
        if (msgq_ptr->TD_PTR != NULL)
        {
            msgq_ptr->TD_PTR->MESSAGES_AVAILABLE -= msgq_ptr->NO_OF_ENTRIES;
        } /* Endif */

        imsg_ptr = msgq_ptr->FIRST_MSG_PTR;
        while ( imsg_ptr != NULL )
        {
            tmp_imsg_ptr = imsg_ptr->NEXT;
            imsg_ptr->QUEUED = FALSE;
            _msg_free((void *)&imsg_ptr->MESSAGE);
            imsg_ptr = tmp_imsg_ptr;
        } /* Endwhile */
        qprev_ptr = msgq_ptr;
        msgq_ptr = msgq_ptr->NEXT_MSGQ_PTR;
        qprev_ptr->FIRST_MSG_PTR = NULL;
        qprev_ptr->NEXT_MSGQ_PTR = NULL;
        qprev_ptr->QUEUE = 0;
    } /* Endwhile */

    td_ptr->MSG_QUEUE_HEAD = NULL;
    td_ptr->MSG_QUEUE_TAIL = NULL;

    /* Search through all of the message pools, looking for any messages
     * owned by this task.  If found free them.
     */
    msgpool_ptr = msg_component_ptr->MSGPOOLS_PTR;
    i = msg_component_ptr->MAX_MSGPOOLS + 1;
    while (--i)
    {
        if (msgpool_ptr->VALID == MSG_VALID)
        {

            /* Search through all of the message pool blocks for this pool */
            msgpool_block_ptr = msgpool_ptr->MSGPOOL_BLOCK_PTR;
            while (msgpool_block_ptr != NULL)
            {
                raw_message_size = msgpool_block_ptr->RAW_MESSAGE_SIZE;
                imsg_ptr = (INTERNAL_MESSAGE_STRUCT_PTR)
                ((unsigned char *)msgpool_block_ptr + sizeof(MSGPOOL_BLOCK_STRUCT));

                /* if the message is not free, not queued and the
                 * owner is the task being destroyed, then Free the message
                 */
                j = msgpool_block_ptr->NUM_MESSAGES + 1;
                while (--j)
                {
                    if ( (imsg_ptr->TD_PTR == td_ptr) &&
                                    (!(imsg_ptr->FREE)) &&
                                    (!(imsg_ptr->QUEUED)) )
                    {
                        _msg_free(&imsg_ptr->MESSAGE);
                    } /* Endif */
                    imsg_ptr =(INTERNAL_MESSAGE_STRUCT_PTR)
                    ((unsigned char *)imsg_ptr + raw_message_size);
                } /* Endwhile */

                msgpool_block_ptr = msgpool_block_ptr->NEXT_BLOCK_PTR;
            } /* Endwhile */

        } /* Endif */
        msgpool_ptr++;
    } /* Endwhile */

} /* Endbody */

/*!
 * \brief Allocates a message from a system message pool.
 * 
 * The size of the message is determined by the message size that a task 
 * specified when it called _msgpool_create_system().
 * \n The message is a resource of the task until the task either frees it 
 * (_msg_free()) or puts it on a message queue (_msgq_send family of functions.)
 * 
 * \param[in] message_size Maximum size (in single-addressable units) of the 
 * message.
 * 
 * \return Pointer to a message of at least message_size single-addressable 
 * units (success).
 * \return NULL (Failure: message component is not created.)
 * 
 * \warning On failure, calls _task_set_error() to set one of the following task 
 * error codes:
 * \li MQX_COMPONENT_DOES_NOT_EXIST (Message component is not created.)
 * \li Task error codes from _mem_alloc_system() (If MQX needs to grow the pool.)
 * 
 * \see _mem_alloc
 * \see _mem_alloc_from
 * \see _mem_alloc_system
 * \see _mem_alloc_system_from
 * \see _mem_alloc_system_zero
 * \see _mem_alloc_system_zero_from
 * \see _mem_alloc_zero
 * \see _mem_alloc_zero_from
 * \see _mem_alloc_align
 * \see _mem_alloc_align_from
 * \see _mem_alloc_at        
 * \see _msg_alloc
 * \see _msg_free
 * \see _msgpool_create_system
 * \see _msgq_send
 * \see _task_set_error
 * \see MESSAGE_HEADER_STRUCT 
 */ 
void *_msg_alloc_system
(
    _msg_size message_size
)
{ /* Body */
    KERNEL_DATA_STRUCT_PTR               kernel_data;
    MSG_COMPONENT_STRUCT_PTR             msg_component_ptr;
    register INTERNAL_MESSAGE_STRUCT_PTR imsg_ptr;
    register MESSAGE_HEADER_STRUCT_PTR   message_ptr;
    register MSGPOOL_STRUCT_PTR          msgpool_ptr;
    uint16_t                              grow_number;

    _GET_KERNEL_DATA(kernel_data);
    _KLOGE2(KLOG_msg_alloc_system, message_size );

    msg_component_ptr = _GET_MSG_COMPONENT_STRUCT_PTR(kernel_data);
#if MQX_CHECK_ERRORS
    if (msg_component_ptr == NULL)
    {
        _task_set_error(MQX_COMPONENT_DOES_NOT_EXIST);
        _KLOGX2( KLOG_msg_alloc_system, NULL );
        return(NULL);
    }/* Endif */
#endif

    message_ptr = NULL;
    _INT_DISABLE();
    msgpool_ptr = msg_component_ptr->SMALLEST_MSGPOOL_PTR;
    while (msgpool_ptr != NULL)
    {
        if (msgpool_ptr->MESSAGE_SIZE >= message_size)
        {
            imsg_ptr = msgpool_ptr->MSG_FREE_LIST_PTR;
            if ( (imsg_ptr == NULL) &&
                            (msgpool_ptr->GROW_NUMBER) &&
                            (msgpool_ptr->MAX < msgpool_ptr->GROW_LIMIT) )
            {
                /* Attempt to add elements to the pool */
                grow_number = msgpool_ptr->GROW_NUMBER;
                if ( ((uint16_t)(msgpool_ptr->MAX + grow_number) > msgpool_ptr->GROW_LIMIT))
                {
                    grow_number = msgpool_ptr->GROW_LIMIT - msgpool_ptr->MAX;
                } /* Endif */
                _msgpool_add_internal(msgpool_ptr, grow_number);
                imsg_ptr = msgpool_ptr->MSG_FREE_LIST_PTR;
            } /* Endif */
            if ( imsg_ptr != NULL )
            {
                msgpool_ptr->MSG_FREE_LIST_PTR = imsg_ptr->NEXT;
                --msgpool_ptr->SIZE;
                _INT_ENABLE();
                imsg_ptr->FREE = FALSE;
                imsg_ptr->QUEUED = FALSE;
                if (kernel_data->IN_ISR)
                {
                    imsg_ptr->TD_PTR = NULL;
                }
                else
                {
                    imsg_ptr->TD_PTR = kernel_data->ACTIVE_PTR;
                } /* Endif */
                message_ptr = (MESSAGE_HEADER_STRUCT_PTR)&imsg_ptr->MESSAGE;
                message_ptr->TARGET_QID = MSGQ_NULL_QUEUE_ID;
                message_ptr->SOURCE_QID = MSGQ_NULL_QUEUE_ID;
                message_ptr->SIZE = message_size;
                message_ptr->CONTROL = MSG_HDR_ENDIAN | MSG_DATA_ENDIAN;

                _KLOGX2(KLOG_msg_alloc_system, message_ptr);
                return (void *)message_ptr;
            } /* Endif */
        } /* Endif */
        msgpool_ptr = msgpool_ptr->NEXT_MSGPOOL_PTR;
    } /* Endwhile */

    _int_enable();
    _KLOGX2(KLOG_msg_alloc_system, message_ptr);
    return (void *)message_ptr;

} /* Endbody */

#endif /* MQX_USE_MESSAGES */

/* EOF */
