0
mirror of https://github.com/Indemsys/Frequency_Inverter.git synced 2026-06-17 11:37:42 +00:00
Files
2022-01-04 12:22:53 +02:00

4253 lines
134 KiB
C

/*HEADER**********************************************************************
*
* Copyright (c) 2008 Freescale Semiconductor;
* All Rights Reserved
*
* Copyright (c) 2004-2008 Embedded Access Inc.;
* All Rights Reserved
*
* Copyright (c) 1989-2008 ARC International;
* All Rights Reserved
*
*****************************************************************************
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************
*
* $FileName: mem.c$
* $Version : 3.8.2.0$
* $Date : Jun-25-2012$
*
* Comments:
*
*END************************************************************************/
#define __MEMORY_MANAGER_COMPILE__
#include "mqx_inc.h"
#include "mem_prv.h"
#if MQX_USE_MEM
#if MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE
extern uchar __UNCACHED_DATA_START[];
extern uchar __UNCACHED_DATA_END[];
#endif /* MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE */
/*!
* \brief Allocates a block of memory.
*
* The functions allocate at least size single-addressable units; the actual
* number might be greater. The start address of the block is aligned so that
* tasks can use the returned pointer as a pointer to any data type without
* causing an error.
* \n Tasks cannot use memory blocks as messages. Tasks must use _msg_alloc() or
* _msg_alloc_system() to allocate messages.
* \n Only the task that allocates a memory block with one of the following
* functions can free the memory block:
* \li _mem_alloc()
* \li _mem_alloc_from()
* \li _mem_alloc_zero()
* \li _mem_alloc_zero_from()
* \li _mem_alloc_align()
* \li _mem_alloc_align_from()
* \li _mem_alloc_at()
*
* \n Any task can free a memory block that is allocated with one of the following
* functions:
* \li _mem_alloc_system()
* \li _mem_alloc_system_from()
* \li _mem_alloc_system_zero()
* \li _mem_alloc_system_zero_from()
*
* \n Function types:
* <table>
* <tr>
* <td></td>
* <td><b>Allocate this type of memory block:</b></td>
* <td><b>From:</b></td>
* </tr>
* <tr>
* <td><b>_mem_alloc()</b></td>
* <td>Private</td>
* <td>Default memory pool</td>
* </tr>
* <tr>
* <td><b>_mem_alloc_from()</b></td>
* <td>Private</td>
* <td>Specified memory pool</td>
* </tr>
* <tr>
* <td><b>_mem_alloc_system()</b></td>
* <td>System</td>
* <td>Default memory pool</td>
* </tr>
* <tr>
* <td><b>_mem_alloc_system_from()</b></td>
* <td>System</td>
* <td>Specified memory pool</td>
* </tr>
* <tr>
* <td><b>_mem_alloc_system_zero()</b></td>
* <td>System (zero-filled)</td>
* <td>Default memory pool</td>
* </tr>
* <tr>
* <td><b>_mem_alloc_system_zero_from()</b></td>
* <td>System (zero-filled)</td>
* <td>Specified memory pool</td>
* </tr>
* <tr>
* <td><b>_mem_alloc_zero()</b></td>
* <td>Private (zero-filled)</td>
* <td>Default memory pool</td>
* </tr>
* <tr>
* <td><b>_mem_alloc_zero_from()</b></td>
* <td>Private (zero-filled)</td>
* <td>Specified memory pool</td>
* </tr>
* <tr>
* <td><b>_mem_alloc_align()</b></td>
* <td>Private (aligned)</td>
* <td>Default memory pool</td>
* </tr>
* <tr>
* <td><b>_mem_alloc_align_from()</b></td>
* <td>Private (aligned)</td>
* <td>Specified memory pool</td>
* </tr>
* <tr>
* <td><b>_mem_alloc_at()</b></td>
* <td>Private (start address defined)</td>
* <td>Default memory pool</td>
* </tr>
* </table>
*
* \param[in] size Size of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \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 _mem_create_pool
* \see _mem_free
* \see _mem_get_highwater
* \see _mem_get_highwater_pool
* \see _mem_get_size
* \see _mem_transfer
* \see _mem_free_part
* \see _msg_alloc
* \see _msg_alloc_system
* \see _task_set_error
*/
pointer _mem_alloc
(
_mem_size size
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
_mqx_uint error;
pointer result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc, size);
_INT_DISABLE();
result = _mem_alloc_internal(size, kernel_data->ACTIVE_PTR, (MEMPOOL_STRUCT_PTR) & kernel_data->KD_POOL, &error);
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
kernel_data->KD_POOL.POOL_ALLOC_CURRENT_BLOCK = kernel_data->KD_POOL.POOL_FREE_LIST_PTR;
_INT_ENABLE();
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
_KLOGX3(KLOG_mem_alloc, result, kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR);
return (result);
} /* Endbody */
/*!
* \brief Allocates a block of memory.
*
* See Description of _mem_alloc() function.
*
* \param[in] size Size of the memory block.
* \param[in] align Alignment of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \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_from()
* \see _mem_alloc_at()
* \see _mem_create_pool
* \see _mem_free
* \see _mem_get_highwater
* \see _mem_get_highwater_pool
* \see _mem_get_size
* \see _mem_transfer
* \see _mem_free_part
* \see _msg_alloc
* \see _msg_alloc_system
* \see _task_set_error
*/
pointer _mem_alloc_align
(
_mem_size size,
_mem_size align
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
_mqx_uint error;
pointer result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc, size);
_INT_DISABLE();
result = _mem_alloc_internal_align(size, align, kernel_data->ACTIVE_PTR, (MEMPOOL_STRUCT_PTR)
& kernel_data->KD_POOL, &error);
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
kernel_data->KD_POOL.POOL_ALLOC_CURRENT_BLOCK = kernel_data->KD_POOL.POOL_FREE_LIST_PTR;
_INT_ENABLE();
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
_KLOGX3(KLOG_mem_alloc_align, result, kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR);
return (result);
}
/*!
* \brief Allocates a block of memory.
*
* See Description of _mem_alloc() function.
*
* \param[in] size Size of the memory block.
* \param[in] addr Start address of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \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_create_pool
* \see _mem_free
* \see _mem_get_highwater
* \see _mem_get_highwater_pool
* \see _mem_get_size
* \see _mem_transfer
* \see _mem_free_part
* \see _msg_alloc
* \see _msg_alloc_system
* \see _task_set_error
*/
pointer _mem_alloc_at
(
_mem_size size,
pointer addr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
_mqx_uint error;
pointer result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc, size);
_INT_DISABLE();
result = _mem_alloc_at_internal(size, addr, kernel_data->ACTIVE_PTR, (MEMPOOL_STRUCT_PTR) & kernel_data->KD_POOL,
&error);
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
kernel_data->KD_POOL.POOL_ALLOC_CURRENT_BLOCK = kernel_data->KD_POOL.POOL_FREE_LIST_PTR;
_INT_ENABLE();
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
}
#endif
_KLOGX3(KLOG_mem_alloc_at, result, kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR);
return (result);
}
#if MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE
/*!
* \brief Allocates a block of memory.
*
* \param[in] size Size of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*/
pointer _mem_alloc_uncached
(
_mem_size size
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
pointer result;
_GET_KERNEL_DATA(kernel_data);
//_KLOGE2(KLOG_mem_alloc_uncached, req_size);
result = _mem_alloc_from(kernel_data->UNCACHED_POOL, size);
//_KLOGX3(KLOG_mem_alloc_uncached, result, kernel_data->UNCACHED_POOL.POOL_BLOCK_IN_ERROR);
return result;
}
/*!
* \brief Allocates an aligned block of memory.
*
* \param[in] size Size of the memory block.
* \param[in] align Alignment of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*/
pointer _mem_alloc_align_uncached
(
_mem_size size,
_mem_size align
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
pointer result;
_GET_KERNEL_DATA(kernel_data);
//_KLOGE2(KLOG_mem_alloc_uncached, size);
result = _mem_alloc_align_from(kernel_data->UNCACHED_POOL, size, align);
//_KLOGX3(KLOG_mem_alloc_uncached, result, kernel_data->UNCACHED_POOL.POOL_BLOCK_IN_ERROR);
return result;
}
#endif /* MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE */
/*!
* \brief Allocates a block of memory.
*
* See Description of _mem_alloc() function.
*
* \param[in] pool_id Pool from which to allocate the memory block (from
* _mem_create_pool()).
* \param[in] size Number of single-addressable units to allocate.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \see _mem_alloc()
* \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 _mem_create_pool
* \see _mem_free
* \see _mem_get_highwater
* \see _mem_get_highwater_pool
* \see _mem_get_size
* \see _mem_transfer
* \see _mem_free_part
* \see _msg_alloc
* \see _msg_alloc_system
* \see _task_set_error
*/
pointer _mem_alloc_from
(
_mem_pool_id pool_id,
_mem_size size
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
MEMPOOL_STRUCT_PTR mem_pool_ptr;
_mqx_uint error;
pointer result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc_from, size);
mem_pool_ptr = (MEMPOOL_STRUCT_PTR) pool_id;
_INT_DISABLE();
result = _mem_alloc_internal(size, kernel_data->ACTIVE_PTR, mem_pool_ptr, &error);
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
_INT_ENABLE();
_KLOGX3(KLOG_mem_alloc_from, result, mem_pool_ptr->POOL_BLOCK_IN_ERROR);
return (result);
}
/*!
* \brief Allocates a block of memory.
*
* See Description of _mem_alloc() function.
*
* \param[in] pool_id Pool from which to allocate the memory block (from
* _mem_create_pool()).
* \param[in] size Number of single-addressable units to allocate.
* \param[in] align Alignment of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \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_at
* \see _mem_create_pool
* \see _mem_free
* \see _mem_get_highwater
* \see _mem_get_highwater_pool
* \see _mem_get_size
* \see _mem_transfer
* \see _mem_free_part
* \see _msg_alloc
* \see _msg_alloc_system
* \see _task_set_error
*/
pointer _mem_alloc_align_from
(
_mem_pool_id pool_id,
_mem_size size,
_mem_size align
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
MEMPOOL_STRUCT_PTR mem_pool_ptr;
_mqx_uint error;
pointer result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc_from, size);
mem_pool_ptr = (MEMPOOL_STRUCT_PTR) pool_id;
_INT_DISABLE();
result = _mem_alloc_internal_align(size, align, kernel_data->ACTIVE_PTR, mem_pool_ptr, &error);
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
_INT_ENABLE();
_KLOGX3(KLOG_mem_alloc_from, result, mem_pool_ptr->POOL_BLOCK_IN_ERROR);
return (result);
}
/*!
* \brief Allocates a block of memory.
*
* See Description of _mem_alloc() function.
*
* \param[in] size Number of single-addressable units to allocate.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \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_from()
* \see _mem_alloc_align()
* \see _mem_alloc_align_from()
* \see _mem_alloc_at
* \see _mem_create_pool
* \see _mem_free
* \see _mem_get_highwater
* \see _mem_get_highwater_pool
* \see _mem_get_size
* \see _mem_transfer
* \see _mem_free_part
* \see _msg_alloc
* \see _msg_alloc_system
* \see _task_set_error
*/
pointer _mem_alloc_zero
(
_mem_size size
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
_mqx_uint error;
pointer result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc_zero, size);
_INT_DISABLE();
result = _mem_alloc_internal(size, kernel_data->ACTIVE_PTR, (MEMPOOL_STRUCT_PTR) & kernel_data->KD_POOL, &error);
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
kernel_data->KD_POOL.POOL_ALLOC_CURRENT_BLOCK = kernel_data->KD_POOL.POOL_FREE_LIST_PTR;
_INT_ENABLE();
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
if (result != NULL) {
_mem_zero(result, size);
} /* Endif */
_KLOGX3(KLOG_mem_alloc_zero, result,
kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR);
return (result);
} /* Endbody */
/*!
* \brief Allocates a block of memory.
*
* See Description of _mem_alloc() function.
*
* \param[in] pool_id Pool from which to allocate the memory block (from
* _mem_create_pool()).
* \param[in] size Number of single-addressable units to allocate.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \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_align()
* \see _mem_alloc_align_from()
* \see _mem_alloc_at
* \see _mem_create_pool
* \see _mem_free
* \see _mem_get_highwater
* \see _mem_get_highwater_pool
* \see _mem_get_size
* \see _mem_transfer
* \see _mem_free_part
* \see _msg_alloc
* \see _msg_alloc_system
* \see _task_set_error
*/
pointer _mem_alloc_zero_from
(
pointer pool_id,
_mem_size size
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
MEMPOOL_STRUCT_PTR mem_pool_ptr;
_mqx_uint error;
pointer result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc_zero, size);
mem_pool_ptr = (MEMPOOL_STRUCT_PTR) pool_id;
_INT_DISABLE();
result = _mem_alloc_internal(size, kernel_data->ACTIVE_PTR, mem_pool_ptr, &error);
/*
* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
_INT_ENABLE();
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
if (result != NULL) {
_mem_zero(result, size);
} /* Endif */
_KLOGX3(KLOG_mem_alloc_zero, result, mem_pool_ptr->POOL_BLOCK_IN_ERROR);
return (result);
} /* Endbody */
/*!
* \private
*
* \brief Creates the memory pool from memory that is outside the default memory
* pool.
*
* Tasks use the pool ID to allocate (variable-size) memory blocks from the pool.
*
* \param[in] start Address of the start of the memory pool.
* \param[in] end The end of the memory pool.
* \param[in] mem_pool_ptr Where to store the memory pool context info.
*
* \return MQX_OK
* \return MQX_CORRUPT_MEMORY_SYSTEM (Internal data for the message component is
* corrupted.)
* \return MQX_MEM_POOL_TOO_SMALL (Size is less than the minimum allowable
* message-pool size.)
*
* \see _mem_create_pool
*/
_mqx_uint _mem_create_pool_internal
(
pointer start,
pointer end,
MEMPOOL_STRUCT_PTR mem_pool_ptr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
STOREBLOCK_STRUCT_PTR block_ptr;
STOREBLOCK_STRUCT_PTR end_block_ptr;
_GET_KERNEL_DATA(kernel_data);
#if MQX_CHECK_VALIDITY
_INT_DISABLE();
if (kernel_data->MEM_COMP.VALID != MEMPOOL_VALID) {
/* The RTOS memory system has been corrupted */
_int_enable();
return (MQX_CORRUPT_MEMORY_SYSTEM);
} /* Endif */
_INT_ENABLE();
#endif
/* Align the start of the pool */
mem_pool_ptr->POOL_PTR = (STOREBLOCK_STRUCT_PTR)
_ALIGN_ADDR_TO_HIGHER_MEM(start);
/* Set the end of memory (aligned) */
mem_pool_ptr->POOL_LIMIT = (STOREBLOCK_STRUCT_PTR)
_ALIGN_ADDR_TO_LOWER_MEM(end);
#if MQX_CHECK_ERRORS
if ((uchar_ptr) mem_pool_ptr->POOL_LIMIT <= ((uchar_ptr) mem_pool_ptr->POOL_PTR + MQX_MIN_MEMORY_POOL_SIZE)) {
return MQX_MEM_POOL_TOO_SMALL;
} /* Endif */
#endif
block_ptr = (STOREBLOCK_STRUCT_PTR) mem_pool_ptr->POOL_PTR;
mem_pool_ptr->POOL_HIGHEST_MEMORY_USED = (pointer) block_ptr;
mem_pool_ptr->POOL_CHECK_POOL_PTR = (char _PTR_) mem_pool_ptr->POOL_PTR;
mem_pool_ptr->POOL_BLOCK_IN_ERROR = NULL;
/* Compute the pool size. */
mem_pool_ptr->POOL_SIZE = (_mem_size) ((uchar_ptr) mem_pool_ptr->POOL_LIMIT - (uchar_ptr) mem_pool_ptr->POOL_PTR);
/* Set up the first block as an idle block */
block_ptr->BLOCKSIZE = mem_pool_ptr->POOL_SIZE - MQX_MIN_MEMORY_STORAGE_SIZE;
block_ptr->USER_AREA = NULL;
block_ptr->PREVBLOCK = NULL;
block_ptr->NEXTBLOCK = NULL;
MARK_BLOCK_AS_FREE(block_ptr);
CALC_CHECKSUM(block_ptr);
mem_pool_ptr->POOL_FREE_LIST_PTR = block_ptr;
/*
* Set up last block as an in_use block, so that the _mem_free algorithm
* will work (block coalescing)
*/
end_block_ptr = (STOREBLOCK_STRUCT_PTR)((uchar_ptr) block_ptr + block_ptr->BLOCKSIZE);
end_block_ptr->BLOCKSIZE = (_mem_size) (MQX_MIN_MEMORY_STORAGE_SIZE);
end_block_ptr->USER_AREA = 0;
end_block_ptr->PREVBLOCK = (struct storeblock_struct _PTR_) block_ptr;
end_block_ptr->NEXTBLOCK = NULL;
MARK_BLOCK_AS_USED(end_block_ptr, SYSTEM_TASK_ID(kernel_data));
CALC_CHECKSUM(end_block_ptr);
mem_pool_ptr->POOL_END_PTR = end_block_ptr;
/* Initialize the list of extensions to this pool */
_QUEUE_INIT(&mem_pool_ptr->EXT_LIST, 0);
mem_pool_ptr->VALID = MEMPOOL_VALID;
/* Protect the list of pools while adding new pool */
_lwsem_wait((LWSEM_STRUCT_PTR) &kernel_data->MEM_COMP.SEM);
_QUEUE_ENQUEUE(&kernel_data->MEM_COMP.POOLS, &mem_pool_ptr->LINK);
_lwsem_post((LWSEM_STRUCT_PTR) &kernel_data->MEM_COMP.SEM);
return MQX_OK;
} /* Endbody */
/*!
* \brief Creates the memory pool from memory that is outside the default memory
* pool.
*
* Tasks use the pool ID to allocate (variable-size) memory blocks from the pool.
*
* \param[in] start Address of the start of the memory pool.
* \param[in] size Size of the memory pool.
*
* \return MQX_OK
* \return NULL
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_MEMORY_SYSTEM (Internal data for the message component is
* corrupted.)
* \li MQX_MEM_POOL_TOO_SMALL (Size is less than the minimum allowable
* message-pool size.)
*
* \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 _task_set_error
*/
_mem_pool_id _mem_create_pool
(
pointer start,
_mem_size size
)
{ /* Body */
_KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data;)
MEMPOOL_STRUCT_PTR mem_pool_ptr;
uchar_ptr end;
_mqx_uint error;
_KLOGM(_GET_KERNEL_DATA(kernel_data);)
_KLOGE3(KLOG_mem_create_pool, start, size);
#if MQX_CHECK_ERRORS
if (size < MQX_MIN_MEMORY_POOL_SIZE) {
error = MQX_MEM_POOL_TOO_SMALL;
_task_set_error(error);
_KLOGX4(KLOG_mem_create_pool, start, size, error);
return NULL;
} /* Endif */
#endif
mem_pool_ptr = (MEMPOOL_STRUCT_PTR)_ALIGN_ADDR_TO_HIGHER_MEM(start);
_mem_zero((pointer) mem_pool_ptr, (_mem_size) sizeof(MEMPOOL_STRUCT));
end = (uchar_ptr) start + size;
start = (pointer) ((uchar_ptr) mem_pool_ptr + sizeof(MEMPOOL_STRUCT));
error = _mem_create_pool_internal(start, (pointer) end, mem_pool_ptr);
#if (MQX_CHECK_ERRORS)
if (error != MQX_OK) {
_task_set_error(error);
_KLOGX4(KLOG_mem_create_pool, start, size, error);
return NULL;
} /* Endif */
#endif
return ((_mem_pool_id) mem_pool_ptr);
} /* Endbody */
/*!
* \brief Adds the specified memory area for use by the memory manager.
*
* The function adds the specified memory to the default memory pool.
* \n The function fails if size is less than (3 * MQX_MIN_MEMORY_STORAGE_SIZE),
* as defined in mem_prv.h
*
* \param[in] start_of_pool Pointer to the start of the memory to add.
* \param[in] size Size of the memory pool to add.
*
* \return MQX_OK
* \return MQX_INVALID_SIZE (Failure, see Description.)
* \return MQX_INVALID_COMPONENT_HANDLE (Memory pool to extend is not valid.)
*
* \see _mem_get_highwater
* \see MQX_INITIALIZATION_STRUCT
*/
_mqx_uint _mem_extend
(
pointer start_of_pool,
_mem_size size
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
_mqx_uint result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE3(KLOG_mem_extend, start_of_pool, size);
result = _mem_extend_pool_internal(start_of_pool, size, (MEMPOOL_STRUCT_PTR) & kernel_data->KD_POOL);
_KLOGX2(KLOG_mem_extend, result);
return (result);
} /* Endbody */
/*!
* \private
*
* \brief Adds physical memory to the memory pool, which is outside the default
* memory pool.
*
* \param[in] start_of_pool Pointer to the start of the memory to add.
* \param[in] size Size of the memory pool addition.
* \param[in] mem_pool_ptr The memory pool to extend.
*
* \return MQX_OK
* \return MQX_INVALID_SIZE (Failure, see Description.)
* \return MQX_INVALID_COMPONENT_HANDLE (Memory pool to extend is not valid.)
*
* \see _mem_create_pool
* \see _mem_get_highwater_pool
*/
_mqx_uint _mem_extend_pool_internal
(
pointer start_of_pool,
_mem_size size,
MEMPOOL_STRUCT_PTR mem_pool_ptr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
STOREBLOCK_STRUCT_PTR block_ptr;
STOREBLOCK_STRUCT_PTR end_ptr;
STOREBLOCK_STRUCT_PTR free_ptr;
STOREBLOCK_STRUCT_PTR tmp_ptr;
MEMPOOL_EXTENSION_STRUCT_PTR ext_ptr;
uchar_ptr real_start_ptr;
uchar_ptr end_of_pool;
_mem_size block_size;
_mem_size real_size;
_mem_size free_block_size;
_GET_KERNEL_DATA(kernel_data);
#if MQX_CHECK_ERRORS
if (size < (_mem_size) (3 * MQX_MIN_MEMORY_STORAGE_SIZE)) {
/* Pool must be big enough to hold at least 3 memory blocks */
return (MQX_INVALID_SIZE);
}/* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (mem_pool_ptr->VALID != MEMPOOL_VALID) {
return (MQX_INVALID_COMPONENT_HANDLE);
}/* Endif */
#endif
ext_ptr = (MEMPOOL_EXTENSION_STRUCT_PTR)
_ALIGN_ADDR_TO_HIGHER_MEM(start_of_pool);
real_start_ptr = (uchar_ptr) ext_ptr + sizeof(MEMPOOL_EXTENSION_STRUCT);
real_start_ptr = (uchar_ptr) _ALIGN_ADDR_TO_HIGHER_MEM(real_start_ptr);
end_of_pool = (uchar_ptr) start_of_pool + size;
end_of_pool = (uchar_ptr) _ALIGN_ADDR_TO_LOWER_MEM(end_of_pool);
real_size = (_mem_size) (end_of_pool - real_start_ptr);
ext_ptr->START = start_of_pool;
ext_ptr->SIZE = size;
ext_ptr->REAL_START = real_start_ptr;
block_ptr = (STOREBLOCK_STRUCT_PTR) real_start_ptr;
block_size = MQX_MIN_MEMORY_STORAGE_SIZE;
free_ptr = (STOREBLOCK_STRUCT_PTR)((uchar_ptr) block_ptr + block_size);
free_block_size = real_size - (_mem_size) (2 * MQX_MIN_MEMORY_STORAGE_SIZE);
end_ptr = (STOREBLOCK_STRUCT_PTR)((uchar_ptr) free_ptr + free_block_size);
/*
* Make a small minimal sized memory block to be as
* the first block in the pool. This will be an in-use block
* and will thus avoid problems with memory co-allescing during
* memory frees
*/
block_ptr->BLOCKSIZE = block_size;
block_ptr->MEM_TYPE = 0;
block_ptr->USER_AREA = 0;
block_ptr->PREVBLOCK = (struct storeblock_struct _PTR_) NULL;
block_ptr->NEXTBLOCK = free_ptr;
MARK_BLOCK_AS_USED(block_ptr, SYSTEM_TASK_ID(kernel_data));
CALC_CHECKSUM(block_ptr);
/*
* Let the next block be the actual free block that will be added
* to the free list
*/
free_ptr->BLOCKSIZE = free_block_size;
free_ptr->MEM_TYPE = 0;
free_ptr->USER_AREA = 0;
free_ptr->PREVBLOCK = block_ptr;
free_ptr->NEXTBLOCK = end_ptr;
MARK_BLOCK_AS_FREE(free_ptr);
CALC_CHECKSUM(free_ptr);
/*
* Set up a minimal sized block at the end of the pool, and also
* mark it as being allocated. Again this is to comply with the
* _mem_free algorithm
*/
end_ptr->BLOCKSIZE = block_size;
end_ptr->MEM_TYPE = 0;
end_ptr->USER_AREA = 0;
end_ptr->PREVBLOCK = free_ptr;
end_ptr->NEXTBLOCK = NULL;
MARK_BLOCK_AS_USED(end_ptr, SYSTEM_TASK_ID(kernel_data));
CALC_CHECKSUM(end_ptr);
_int_disable(); /* Add the block to the free list */
tmp_ptr = mem_pool_ptr->POOL_FREE_LIST_PTR;
mem_pool_ptr->POOL_FREE_LIST_PTR = free_ptr;
if (tmp_ptr != NULL) {
PREV_FREE( tmp_ptr) = free_ptr;
} /* Endif */
PREV_FREE( free_ptr) = NULL;
NEXT_FREE( free_ptr) = tmp_ptr;
/* Reset the free list queue walker for some other task */
mem_pool_ptr->POOL_FREE_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
/* Link in the extension */
_QUEUE_ENQUEUE(&mem_pool_ptr->EXT_LIST, &ext_ptr->LINK);
_int_enable();
return (MQX_OK);
} /* Endbody */
/*!
* \brief Adds physical memory to the memory pool, which is outside the default
* memory pool.
*
* The function adds the specified memory to the memory pool.
* \n The function fails if size is less than (3 * MIN_MEMORY_STORAGE_SIZE), as
* defined in mem_prv.h.
*
* \param[in] pool_id Pool to which to add memory (from _mem_create_pool()).
* \param[in] start_of_pool Pointer to the start of the memory to add.
* \param[in] size Size of the memory pool addition.
*
* \return MQX_OK
* \return MQX_INVALID_SIZE (Failure, see Description.)
* \return MQX_INVALID_COMPONENT_HANDLE (Memory pool to extend is not valid.)
*
* \see _mem_create_pool
* \see _mem_get_highwater_pool
*/
_mqx_uint _mem_extend_pool
(
_mem_pool_id pool_id,
pointer start_of_pool,
_mem_size size
)
{ /* Body */
_KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data;)
_mqx_uint result;
_KLOGM(_GET_KERNEL_DATA(kernel_data);)
_KLOGE4(KLOG_mem_extend_pool, start_of_pool, size, pool_id);
result = _mem_extend_pool_internal(start_of_pool, size, (MEMPOOL_STRUCT_PTR) pool_id);
_KLOGX2(KLOG_mem_extend_pool, result);
return (result);
} /* Endbody */
/*!
* \brief Free part of the memory block.
*
* Under the same restriction as for _mem_free(), the function trims from the
* end of the memory block.
* \n A successful call to the function frees memory only if requested_size is
* sufficiently smaller than the size of the original block. To determine whether
* the function freed memory, call _mem_get_size() before and after calling
* _mem_free_part().
*
* \param[in] mem_ptr Pointer to the memory block to trim.
* \param[in] requested_size New size for the block.
*
* \return MQX_OK
* \return MQX_INVALID_POINTER (Mem_ptr is NULL, not in the pool, or misaligned.)
* \return MQX_INVALID_CHECKSUM (Block's checksum is not correct, indicating
* that at least some of the block was overwritten.)
* \return MQX_NOT_RESOURCE_OWNER (If the block was allocated with _mem_alloc()
* or _mem_alloc_zero(), only the task that allocated it can free part of it.)
* \return MQX_INVALID_SIZE (Size of the original block is less than requested_size
* or requested_size is less than 0.).
*
* \warning On failure, calls _task_set_error() to set the task error code (see
* return values)
*
* \see _mem_free
* \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 _mem_get_size
* \see _task_set_error
*/
_mqx_uint _mem_free_part
(
pointer mem_ptr,
_mem_size requested_size
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
STOREBLOCK_STRUCT_PTR block_ptr;
STOREBLOCK_STRUCT_PTR prev_block_ptr;
STOREBLOCK_STRUCT_PTR next_block_ptr;
STOREBLOCK_STRUCT_PTR new_block_ptr;
MEMPOOL_STRUCT_PTR mem_pool_ptr;
TD_STRUCT_PTR td_ptr;
_mem_size size;
_mem_size block_size;
_mem_size new_block_size;
_mqx_uint result_code;
_GET_KERNEL_DATA(kernel_data);
_KLOGE3(KLOG_mem_free_part, mem_ptr, requested_size);
#if MQX_CHECK_ERRORS
/* Make sure a correct pointer was passed in. */
if (mem_ptr == NULL) {
_task_set_error(MQX_INVALID_POINTER);
_KLOGX2(KLOG_mem_free_part, MQX_INVALID_POINTER);
return (MQX_INVALID_POINTER);
} /* Endif */
#endif
/* Verify the block size */
block_ptr = GET_MEMBLOCK_PTR(mem_ptr);
#if MQX_CHECK_ERRORS
if (!_MEMORY_ALIGNED(block_ptr)) {
_task_set_error(MQX_INVALID_POINTER);
_KLOGX2(KLOG_mem_free_part, MQX_INVALID_POINTER);
return (MQX_INVALID_POINTER);
} /* Endif */
if ((block_ptr->BLOCKSIZE < MQX_MIN_MEMORY_STORAGE_SIZE) || BLOCK_IS_FREE(block_ptr)) {
_task_set_error(MQX_INVALID_POINTER);
kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR = block_ptr;
_KLOGX3(KLOG_mem_free_part, MQX_INVALID_POINTER, block_ptr);
return (MQX_INVALID_POINTER);
} /* Endif */
#endif
_INT_DISABLE();
#if MQX_CHECK_VALIDITY
if (!VALID_CHECKSUM(block_ptr)) {
_int_enable();
_task_set_error(MQX_INVALID_CHECKSUM);
kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR = block_ptr;
_KLOGX3(KLOG_mem_free_part, MQX_INVALID_CHECKSUM, block_ptr);
return (MQX_INVALID_CHECKSUM);
} /* Endif */
#endif
mem_pool_ptr = (MEMPOOL_STRUCT_PTR) block_ptr->MEM_POOL_PTR;
td_ptr = SYSTEM_TD_PTR(kernel_data);
if (block_ptr->TASK_NUMBER != (TASK_NUMBER_FROM_TASKID(td_ptr->TASK_ID))) {
td_ptr = kernel_data->ACTIVE_PTR;
}
/* Walk through the memory resources of the task descriptor.
* Two pointers are maintained, one to the current block
* and one to the previous block.
*/
next_block_ptr = (STOREBLOCK_STRUCT_PTR) td_ptr->MEMORY_RESOURCE_LIST;
prev_block_ptr = (STOREBLOCK_STRUCT_PTR)((uchar_ptr) (&td_ptr->MEMORY_RESOURCE_LIST)
- FIELD_OFFSET(STOREBLOCK_STRUCT,NEXTBLOCK));
/* Scan the task's memory resource list searching for the block to
* free, Stop when the current pointer is equal to the block to free
* or the end of the list is reached.
*/
while (next_block_ptr && ((pointer) next_block_ptr != mem_ptr)) {
/* The block is not found, and the end of the list has not been
* reached, so move down the list.
*/
prev_block_ptr = GET_MEMBLOCK_PTR(next_block_ptr);
next_block_ptr = (STOREBLOCK_STRUCT_PTR) prev_block_ptr->NEXTBLOCK;
} /* Endwhile */
#if MQX_CHECK_ERRORS
if (next_block_ptr == NULL) {
_int_enable();
/* The specified block does not belong to the calling task. */
_task_set_error(MQX_NOT_RESOURCE_OWNER);
_KLOGX2(KLOG_mem_free_part, MQX_NOT_RESOURCE_OWNER);
return (MQX_NOT_RESOURCE_OWNER);
} /* Endif */
#endif
/* determine the size of the block. */
block_size = block_ptr->BLOCKSIZE;
size = requested_size + (_mem_size) FIELD_OFFSET(STOREBLOCK_STRUCT,USER_AREA);
if (size < MQX_MIN_MEMORY_STORAGE_SIZE) {
size = MQX_MIN_MEMORY_STORAGE_SIZE;
} /* Endif */
_MEMORY_ALIGN_VAL_LARGER(size);
#if MQX_CHECK_ERRORS
/* Verify that the size parameter is within range of the block size. */
if (size <= block_size) {
#endif
/* Adjust the size to allow for the overhead and force alignment */
/* Compute the size of the new_ block that would be created. */
new_block_size = block_size - size;
/* Decide if it worthwile to split the block. If the amount of space
* returned is not at least twice the size of the block overhead,
* then dont bother.
*/
if (new_block_size >= (2 * MQX_MIN_MEMORY_STORAGE_SIZE)) {
/* Create an 'inuse' block */
new_block_ptr = (STOREBLOCK_STRUCT_PTR)((char _PTR_) block_ptr + size);
new_block_ptr->BLOCKSIZE = new_block_size;
PREV_PHYS( new_block_ptr) = block_ptr;
new_block_ptr->TASK_NUMBER = block_ptr->TASK_NUMBER;
new_block_ptr->MEM_POOL_PTR = block_ptr->MEM_POOL_PTR;
CALC_CHECKSUM(new_block_ptr);
/* Split the block */
block_ptr->BLOCKSIZE = size;
CALC_CHECKSUM(block_ptr);
/* make sure right physical neighbour knows about it */
block_ptr = NEXT_PHYS(new_block_ptr);
PREV_PHYS( block_ptr) = new_block_ptr;
CALC_CHECKSUM(block_ptr);
/* Link the new block onto the requestor's task descriptor. */
new_block_ptr->NEXTBLOCK = td_ptr->MEMORY_RESOURCE_LIST;
td_ptr->MEMORY_RESOURCE_LIST = (char _PTR_) (&new_block_ptr->USER_AREA);
result_code = _mem_free((pointer) &new_block_ptr->USER_AREA);
}
else {
result_code = MQX_OK;
} /* Endif */
#if MQX_CHECK_ERRORS
}
else {
result_code = MQX_INVALID_SIZE;
} /* Endif */
#endif
#if MQX_CHECK_ERRORS
if (result_code != MQX_OK) {
_task_set_error(result_code);
} /* Endif */
#endif
_INT_ENABLE();
_KLOGX2(KLOG_mem_free_part, result_code);
return (result_code);
}
/*!
* \brief Frees the given memory block.
*
* If the memory block was allocated with one of the following functions, only
* the task that owns the block can free it:
* \li _mem_alloc()
* \li _mem_alloc_from()
* \li _mem_alloc_zero()
* \li _mem_alloc_zero_from()
*
* \n Any task can free a memory block that is allocated with one of the following
* functions:
* \li _mem_alloc_system()
* \li _mem_alloc_system_from()
* \li _mem_alloc_system_zero()
* \li _mem_alloc_system_zero_from()
*
* \param[in] mem_ptr Pointer to the memory block to free.
*
* \return MQX_OK
* \return MQX_INVALID_POINTER (Mem_ptr is NULL, not in the pool, or misaligned.)
* \return MQX_INVALID_CHECKSUM (Block's checksum is not correct, indicating
* that at least some of the block was overwritten.)
* \return MQX_NOT_RESOURCE_OWNER (If the block was allocated with _mem_alloc()
* or _mem_alloc_zero(), only the task that allocated it can free part of it.)
*
* \warning On failure, calls _task_set_error() to set the task error code (see
* return values).
*
* \see _mem_free_part
* \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 _task_set_error
*/
_mqx_uint _mem_free
(
pointer mem_ptr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
STOREBLOCK_STRUCT_PTR block_ptr;
STOREBLOCK_STRUCT_PTR prev_block_ptr;
STOREBLOCK_STRUCT_PTR next_block_ptr;
MEMPOOL_STRUCT_PTR mem_pool_ptr;
TD_STRUCT_PTR td_ptr;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_free, mem_ptr);
#if MQX_CHECK_ERRORS
/* Verify the passed in parameter */
if (mem_ptr == NULL) {
_task_set_error(MQX_INVALID_POINTER);
_KLOGX2(KLOG_mem_free, MQX_INVALID_POINTER);
return (MQX_INVALID_POINTER);
} /* Endif */
#endif
block_ptr = GET_MEMBLOCK_PTR(mem_ptr);
#if MQX_CHECK_ERRORS
/* Verify pointer alignment */
if (!_MEMORY_ALIGNED(block_ptr) || (block_ptr->BLOCKSIZE < MQX_MIN_MEMORY_STORAGE_SIZE) || BLOCK_IS_FREE(block_ptr)) {
_task_set_error(MQX_INVALID_POINTER);
_KLOGX2(KLOG_mem_free, MQX_INVALID_POINTER);
return (MQX_INVALID_POINTER);
} /* Endif */
#endif
_INT_DISABLE();
#if MQX_CHECK_VALIDITY
if (!VALID_CHECKSUM(block_ptr)) {
_int_enable();
_task_set_error(MQX_INVALID_CHECKSUM);
_KLOGX2(KLOG_mem_free, MQX_INVALID_CHECKSUM);
return (MQX_INVALID_CHECKSUM);
} /* Endif */
#endif
mem_pool_ptr = (MEMPOOL_STRUCT_PTR) block_ptr->MEM_POOL_PTR;
td_ptr = SYSTEM_TD_PTR(kernel_data);
if (block_ptr->TASK_NUMBER != (TASK_NUMBER_FROM_TASKID(td_ptr->TASK_ID))) {
td_ptr = kernel_data->ACTIVE_PTR;
} /* Endif */
/*
* Walk through the memory resources of the task descriptor.
* Two pointers are maintained, one to the current block
* and one to the previous block.
*/
next_block_ptr = (STOREBLOCK_STRUCT_PTR) td_ptr->MEMORY_RESOURCE_LIST;
prev_block_ptr = (STOREBLOCK_STRUCT_PTR)((uchar_ptr) (&td_ptr->MEMORY_RESOURCE_LIST)
- FIELD_OFFSET(STOREBLOCK_STRUCT,NEXTBLOCK));
/*
* Scan the task's memory resource list searching for the block to
* free, Stop when the current pointer is equal to the block to free
* or the end of the list is reached.
*/
while (next_block_ptr && ((pointer) next_block_ptr != mem_ptr)) {
/*
* The block is not found, and the end of the list has not been
* reached, so move down the list.
*/
prev_block_ptr = GET_MEMBLOCK_PTR(next_block_ptr);
next_block_ptr = (STOREBLOCK_STRUCT_PTR) prev_block_ptr->NEXTBLOCK;
} /* Endwhile */
#if MQX_CHECK_ERRORS
if (next_block_ptr == NULL) {
_int_enable();
/* The specified block does not belong to the calling task. */
_task_set_error(MQX_NOT_RESOURCE_OWNER);
_KLOGX2(KLOG_mem_free, MQX_NOT_RESOURCE_OWNER);
return (MQX_NOT_RESOURCE_OWNER);
} /* Endif */
#endif
/* Remove the memory block from the resource list of the calling task. */
prev_block_ptr->NEXTBLOCK = block_ptr->NEXTBLOCK;
#if MQX_ALLOW_TYPED_MEMORY
block_ptr->MEM_TYPE = 0;
#endif
/*
* Check if the neighbouring blocks are free, so we
* can coalesce the blocks.
*/
if (_mem_check_coalesce_internal(block_ptr)) {
/* No need to add block to free list if coalesced */
_INT_ENABLE();
_KLOGX2(KLOG_mem_free, MQX_OK);
return (MQX_OK);
} /* Endif */
#if MQX_MEMORY_FREE_LIST_SORTED == 1
next_block_ptr = mem_pool_ptr->POOL_FREE_LIST_PTR;
if (next_block_ptr != NULL) {
/* Insertion sort into the free list by address*/
while (next_block_ptr < block_ptr) {
/* This takes some time, so allow higher priority tasks
* to interrupt us.
*/
if (NEXT_FREE(next_block_ptr) == NULL) {
/* At end of free list */
break;
} /* Endif */
next_block_ptr = (STOREBLOCK_STRUCT_PTR) NEXT_FREE(next_block_ptr);
/* Save the current location in case premption occurs */
mem_pool_ptr->POOL_FREE_CURRENT_BLOCK = next_block_ptr;
_INT_ENABLE();
_INT_DISABLE();
/* Pick up where left off */
next_block_ptr = mem_pool_ptr->POOL_FREE_CURRENT_BLOCK;
if (_mem_check_coalesce_internal(block_ptr)) {
/* No need to add block to free list if coalesced */
_INT_ENABLE();
_KLOGX2(KLOG_mem_free, MQX_OK);
return (MQX_OK);
} /* Endif */
} /* Endwhile */
} /* Endif */
/* We have found the correct location */
/* Make the block a free block */
block_ptr->NEXTBLOCK = NULL;
block_ptr->BLOCKSIZE = block_ptr->BLOCKSIZE;
MARK_BLOCK_AS_FREE(block_ptr);
CALC_CHECKSUM(block_ptr);
/* Insert current block just before next block */
if (next_block_ptr == mem_pool_ptr->POOL_FREE_LIST_PTR) {
/* We are inserting at the head of the free list */
mem_pool_ptr->POOL_FREE_LIST_PTR = block_ptr;
if (next_block_ptr != NULL) {
PREV_FREE( next_block_ptr) = (pointer) block_ptr;
} /* Endif */
PREV_FREE( block_ptr) = NULL;
NEXT_FREE( block_ptr) = (pointer) next_block_ptr;
}
else if (next_block_ptr < block_ptr) {
/* We are inserting at the end of the free list */
NEXT_FREE( block_ptr) = NULL;
PREV_FREE( block_ptr) = (pointer) next_block_ptr;
NEXT_FREE( next_block_ptr) = (pointer) block_ptr;
}
else {
/* We are inserting into the middle of the free list */
PREV_FREE( block_ptr) = PREV_FREE(next_block_ptr);
PREV_FREE( next_block_ptr) = (pointer) block_ptr;
NEXT_FREE( block_ptr) = (pointer) next_block_ptr;
NEXT_FREE( PREV_FREE(
block_ptr)) = (pointer) block_ptr;
} /* Endif */
/*
* Reset the freelist current block pointer in case we pre-empted
* another task
*/
mem_pool_ptr->POOL_FREE_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
#else
/* Make the block a free block */
block_ptr->NEXTBLOCK = NULL;
MARK_BLOCK_AS_FREE(block_ptr);
CALC_CHECKSUM(block_ptr);
/* Put the block at the head of the free list */
next_block_ptr = mem_pool_ptr->POOL_FREE_LIST_PTR;
mem_pool_ptr->POOL_FREE_LIST_PTR = block_ptr;
if ( next_block_ptr != NULL ) {
PREV_FREE(next_block_ptr) = (pointer)block_ptr;
} /* Endif */
PREV_FREE(block_ptr) = NULL;
NEXT_FREE(block_ptr) = (pointer)next_block_ptr;
#endif
/* Reset the _mem_test pointers */
mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK = (STOREBLOCK_STRUCT_PTR) mem_pool_ptr->POOL_PTR;
mem_pool_ptr->POOL_FREE_CHECK_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
_INT_ENABLE();
_KLOGX2(KLOG_mem_free, MQX_OK);
return (MQX_OK);
} /* Endbody */
/*!
* \private
*
* \brief This function coalesces any free block found adjacent to the provided
* block.
*
* \param[in] passed_block_ptr An Address of a memory block, whose neighbours
* has to be checked to see if they are free.
*
* \return TRUE (Coalescing was performed), FALSE (Coalescing was not performed).
*/
boolean _mem_check_coalesce_internal
(
STOREBLOCK_STRUCT_PTR passed_block_ptr
)
{ /* Body */
register STOREBLOCK_STRUCT_PTR block_ptr;
register STOREBLOCK_STRUCT_PTR prev_block_ptr;
register STOREBLOCK_STRUCT_PTR next_block_ptr;
MEMPOOL_STRUCT_PTR mem_pool_ptr;
boolean have_coalesced = FALSE;
block_ptr = passed_block_ptr;
mem_pool_ptr = (MEMPOOL_STRUCT_PTR) block_ptr->MEM_POOL_PTR;
/* Check the previous physical neighbour */
prev_block_ptr = PREV_PHYS(block_ptr);
if ((prev_block_ptr != NULL) && BLOCK_IS_FREE(prev_block_ptr)) {
/* the block previous to this one is free */
/* make the current block a free block so it can't be freed again */
block_ptr->NEXTBLOCK = NULL;
MARK_BLOCK_AS_FREE(block_ptr);
/* Add the current block to the previous block */
prev_block_ptr->BLOCKSIZE += block_ptr->BLOCKSIZE;
/* Modify the next physical block to point to the previous block */
next_block_ptr = NEXT_PHYS(block_ptr);
PREV_PHYS( next_block_ptr) = prev_block_ptr;
CALC_CHECKSUM(prev_block_ptr);
CALC_CHECKSUM(next_block_ptr);
block_ptr = prev_block_ptr; /* Set up as the current block */
have_coalesced = TRUE;
} /* Endif */
/* Now, check the next block to see if it is free */
next_block_ptr = NEXT_PHYS(block_ptr);
if (BLOCK_IS_FREE(next_block_ptr)) {
/* the next block is free */
if (mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK == next_block_ptr) {
/* We must modify the _mem_alloc pointer to not point
** at the next block
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = block_ptr;
} /* Endif */
if (have_coalesced) {
/* the current block is already on the free list */
/* Remove the block from the free list */
if (block_ptr == mem_pool_ptr->POOL_FREE_LIST_PTR) {
mem_pool_ptr->POOL_FREE_LIST_PTR = (STOREBLOCK_STRUCT_PTR) NEXT_FREE(block_ptr);
if (NEXT_FREE(block_ptr) != NULL) {
PREV_FREE( NEXT_FREE(
block_ptr)) = 0;
} /* Endif */
}
else {
NEXT_FREE( PREV_FREE(
block_ptr)) = NEXT_FREE(block_ptr);
if (NEXT_FREE(block_ptr) != NULL) {
PREV_FREE( NEXT_FREE(
block_ptr)) = PREV_FREE(block_ptr);
} /* Endif */
} /* Endif */
}
else {
/* Make the block a free block */
block_ptr->NEXTBLOCK = NULL;
MARK_BLOCK_AS_FREE(block_ptr);
} /* Endif */
/*
* The current block is now a free block not on the free list .
* the freelist pointers have to be modified so that the next
* block is removed from the list, replace with the current block.
*/
/* set the next free block to be the same as the one on the free list */
NEXT_FREE( block_ptr) = NEXT_FREE(next_block_ptr);
/*
* And set the back pointer of the block after the next free block
* to point back to the current block
*/
if (NEXT_FREE(block_ptr) != NULL) {
PREV_FREE( NEXT_FREE(
block_ptr)) = (STOREBLOCK_STRUCT_PTR) block_ptr;
} /* Endif */
if (next_block_ptr == mem_pool_ptr->POOL_FREE_LIST_PTR) {
/*
* If the next block pointer was at the head of the free list,
* the kernel free list pointer must be updated
*/
mem_pool_ptr->POOL_FREE_LIST_PTR = block_ptr;
PREV_FREE( block_ptr) = NULL;
}
else {
/*
* Otherwise we need to adjust the pointers of the block that
* was previous to the next block on the free list
*/
PREV_FREE( block_ptr) = PREV_FREE(next_block_ptr);
if (PREV_FREE(block_ptr) != NULL) {
NEXT_FREE( PREV_FREE(
block_ptr)) = (pointer) block_ptr;
} /* Endif */
} /* Endif */
/* Add the next block onto the current block */
block_ptr->BLOCKSIZE += next_block_ptr->BLOCKSIZE;
/*
* Reset the previous physical block pointer of
* the block after the next block (ie the next next block)
*/
prev_block_ptr = NEXT_PHYS(next_block_ptr);
PREV_PHYS( prev_block_ptr) = block_ptr;
CALC_CHECKSUM(prev_block_ptr);
CALC_CHECKSUM(block_ptr);
have_coalesced = TRUE;
} /* Endif */
if (have_coalesced) {
/* Reset the _mem_test pointers */
mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK = (STOREBLOCK_STRUCT_PTR) mem_pool_ptr->POOL_PTR;
mem_pool_ptr->POOL_FREE_CHECK_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
#if MQX_MEMORY_FREE_LIST_SORTED == 1
/*
* Reset the freelist current block pointer in case we pre-empted
* another task
*/
mem_pool_ptr->POOL_FREE_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
#endif
} /* Endif */
return (have_coalesced);
} /* Endbody */
/*!
* \brief Allocates a block of memory.
*
* See Description of _mem_alloc() function.
*
* \param[in] pool_id Pool from which to allocate the memory block (from
* _mem_create_pool()).
* \param[in] size Size of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \see _mem_alloc()
* \see _mem_alloc_from()
* \see _mem_alloc_system()
* \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 _mem_create_pool
* \see _mem_free
* \see _mem_get_highwater
* \see _mem_get_highwater_pool
* \see _mem_get_size
* \see _mem_transfer
* \see _mem_free_part
* \see _msg_alloc
* \see _msg_alloc_system
* \see _task_set_error
*/
pointer _mem_alloc_system_from
(
_mem_pool_id pool_id,
_mem_size size
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
MEMPOOL_STRUCT_PTR mem_pool_ptr = (MEMPOOL_STRUCT_PTR) pool_id;
_mqx_uint error;
pointer result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc_system_from, size);
_INT_DISABLE();
result = _mem_alloc_internal(size, SYSTEM_TD_PTR(kernel_data), mem_pool_ptr, &error);
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
_INT_ENABLE();
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
_KLOGX3(KLOG_mem_alloc_system_from, result, mem_pool_ptr->POOL_BLOCK_IN_ERROR);
return (result);
} /* Endbody */
/*!
* \brief Allocates a block of memory.
*
* See Description of _mem_alloc() function.
*
* \param[in] size Size of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \see _mem_alloc()
* \see _mem_alloc_from()
* \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 _mem_create_pool
* \see _mem_free
* \see _mem_get_highwater
* \see _mem_get_highwater_pool
* \see _mem_get_size
* \see _mem_transfer
* \see _mem_free_part
* \see _msg_alloc
* \see _msg_alloc_system
* \see _task_set_error
*/
pointer _mem_alloc_system
(
_mem_size size
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
_mqx_uint error;
pointer result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc_system, size);
_INT_DISABLE();
result = _mem_alloc_internal(size, SYSTEM_TD_PTR(kernel_data), (MEMPOOL_STRUCT_PTR) & kernel_data->KD_POOL, &error);
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
kernel_data->KD_POOL.POOL_ALLOC_CURRENT_BLOCK = kernel_data->KD_POOL.POOL_FREE_LIST_PTR;
_INT_ENABLE();
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
_KLOGX3(KLOG_mem_alloc_system, result, kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR);
return (result);
}
#if MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE
/*!
* \brief Allocates uncached memory that is available system wide.
*
* \param[in] size Size of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*/
pointer _mem_alloc_system_uncached
(
_mem_size size
)
{
KERNEL_DATA_STRUCT_PTR kernel_data;
_mqx_uint error;
pointer result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc_system, size);
_INT_DISABLE();
result = _mem_alloc_internal(size, SYSTEM_TD_PTR(kernel_data), (MEMPOOL_STRUCT_PTR)kernel_data->UNCACHED_POOL, &error);
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
kernel_data->UNCACHED_POOL->POOL_ALLOC_CURRENT_BLOCK = kernel_data->UNCACHED_POOL->POOL_FREE_LIST_PTR;
_INT_ENABLE();
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
_KLOGX3(KLOG_mem_alloc_system, result, kernel_data->UNCACHED_POOL->POOL_BLOCK_IN_ERROR);
return(result);
}
#endif /* MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE */
/*!
* \private
*
* \brief This function initializes the memory storage pool.
*
* \return MQX_OK
* \return MQX_CORRUPT_MEMORY_SYSTEM (Internal data for the message component is
* corrupted.)
* \return MQX_MEM_POOL_TOO_SMALL (Size is less than the minimum allowable
* message-pool size.)
*/
_mqx_uint _mem_init_internal
(
void
)
{ /* Body */
#if MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE
pointer __uncached_data_start = (pointer )__UNCACHED_DATA_START;
pointer __uncached_data_end = (pointer )__UNCACHED_DATA_END;
#endif /* MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE */
KERNEL_DATA_STRUCT_PTR kernel_data;
pointer start;
_mqx_uint result;
_GET_KERNEL_DATA(kernel_data);
_QUEUE_INIT(&kernel_data->MEM_COMP.POOLS, 0);
_lwsem_create((LWSEM_STRUCT_PTR) &kernel_data->MEM_COMP.SEM, 1);
kernel_data->MEM_COMP.VALID = MEMPOOL_VALID;
/*
* Move the MQX memory pool pointer past the end of kernel data.
*/
start = (pointer) ((uchar_ptr) kernel_data + sizeof(KERNEL_DATA_STRUCT));
result = _mem_create_pool_internal(start, kernel_data->INIT.END_OF_KERNEL_MEMORY, (MEMPOOL_STRUCT_PTR)
& kernel_data->KD_POOL);
#if MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE
if (result == MQX_OK) {
if ((__uncached_data_start <= start) && (start <= __uncached_data_end)) {
kernel_data->UNCACHED_POOL = &kernel_data->KD_POOL;
}
else {
/* The pool state structure is created at the bottom of the pool */
kernel_data->UNCACHED_POOL = (MEMPOOL_STRUCT_PTR)_mem_create_pool(__uncached_data_start, (_mem_size)__uncached_data_end - (_mem_size)__uncached_data_start);
}
}
#endif /* MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE */
return result;
} /* Endbody */
/*!
* \private
*
* \brief This routine returns what the next memory block is for a given memory
* block (where the memory block is on a tasks resource list).
*
* \param[in] td_ptr The task descriptor being checked.
* \param[in] memory_ptr The address (USERS_AREA) of the memory block.
*
* return Pointer to next block.
*/
pointer _mem_get_next_block_internal
(
TD_STRUCT_PTR td_ptr,
pointer memory_ptr
)
{ /* Body */
STOREBLOCK_STRUCT_PTR block_ptr;
if (memory_ptr == NULL) {
return (td_ptr->MEMORY_RESOURCE_LIST);
}
else {
block_ptr = GET_MEMBLOCK_PTR(memory_ptr);
return (block_ptr->NEXTBLOCK);
} /* Endif */
} /* Endbody */
/*!
* \brief Gets the allocated size (in bytes) of a block allocated using the MQX
* storage allocator (_mem_alloc).
*
* The size is the actual size of the memory block and might be larger than the
* size that a task requested.
*
* \param[in] mem_ptr Address of the memory block whose size is wanted.
*
* \return Number of single-addressable units in the block (Success.)
* \return 0 (Failure.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL (Memory is corrupted or mem_ptr does not point
* to a block that was allocated with a function from the _mem_alloc family.)
* \li MQX_INVALID_CHECKSUM (Checksum is not correct because part of the memory
* block header was overwritten.)
* \li MQX_INVALID_POINTER (Mem_ptr is NULL or improperly aligned.)
*
* \see _mem_free
* \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 _mem_free_part
* \see _task_set_error
*/
_mem_size _mem_get_size
(
pointer mem_ptr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
STOREBLOCK_STRUCT_PTR block_ptr;
_mem_size size;
_GET_KERNEL_DATA(kernel_data);
#if MQX_CHECK_ERRORS
if (mem_ptr == NULL) {
_task_set_error(MQX_INVALID_POINTER);
return (0);
} /* Endif */
#endif
/* Compute the start of the block */
block_ptr = GET_MEMBLOCK_PTR(mem_ptr);
#if MQX_CHECK_ERRORS
if (!_MEMORY_ALIGNED(block_ptr)) {
_task_set_error(MQX_INVALID_POINTER);
return (0);
} /* Endif */
#endif
size = block_ptr->BLOCKSIZE;
#if MQX_CHECK_ERRORS
/* For all free blocks, a check is made to ensure that the user
* has not corrupted the storage pool. This is done by checking the
* 'magic value', which should not be corrupted. Alternatively, the
* user could have passed in an invalid memory pointer.
*/
if (BLOCK_IS_FREE(block_ptr)) {
kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR = block_ptr;
_task_set_error(MQX_CORRUPT_STORAGE_POOL);
return (0);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if ((!VALID_CHECKSUM(block_ptr))) {
kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR = block_ptr;
_task_set_error(MQX_INVALID_CHECKSUM);
return (0);
} /* Endif */
#endif
/* The size includes the block overhead, which the user is not
* interested in. If the size is less than the overhead,
* then there is a bad block or bad block pointer.
*/
#if MQX_CHECK_ERRORS
if (size <= (_mem_size) FIELD_OFFSET(STOREBLOCK_STRUCT,USER_AREA)) {
kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR = block_ptr;
_task_set_error(MQX_CORRUPT_STORAGE_POOL);
return (0);
} /* Endif */
#endif
return (size - (_mem_size) FIELD_OFFSET(STOREBLOCK_STRUCT,USER_AREA));
} /* Endbody */
/*!
* \brief This function checks the all memory pool for any errors.
*
* \param[out] pool_error_ptr Pointer to the memory pool in error (initialized
* only if an error was found).
*
* \return MQX_OK (No errors found.)
* \return Errors from _mem_test() (A memory pool has an error.)
* \return Errors from _queue_test() (Memory-pool queue has an error.)
*
* \see _mem_test
* \see _mem_test_pool
* \see _queue_test
*/
_mqx_uint _mem_test_all
(
_mem_pool_id _PTR_ pool_error_ptr
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
MEMPOOL_STRUCT_PTR pool_ptr;
_mqx_uint result;
_GET_KERNEL_DATA(kernel_data);
/* Use a semaphore to protect the list of pools */
_lwsem_wait((LWSEM_STRUCT_PTR) &kernel_data->MEM_COMP.SEM);
/* Make sure that the queue of memory pools is ok */
result = _queue_test((QUEUE_STRUCT_PTR) &kernel_data->MEM_COMP.POOLS, (pointer _PTR_) pool_error_ptr);
_lwsem_post((LWSEM_STRUCT_PTR) &kernel_data->MEM_COMP.SEM);
if (result != MQX_OK) {
return (result);
} /* Endif */
/* Now test application pools */
_lwsem_wait((LWSEM_STRUCT_PTR) &kernel_data->MEM_COMP.SEM);
pool_ptr = (MEMPOOL_STRUCT_PTR)((pointer) kernel_data->MEM_COMP.POOLS.NEXT);
while (pool_ptr != (MEMPOOL_STRUCT_PTR)((pointer) &kernel_data->MEM_COMP.POOLS)) {
result = _mem_test_pool(pool_ptr);
if (result != MQX_OK) {
break;
} /* Endif */
pool_ptr = (MEMPOOL_STRUCT_PTR)((pointer) pool_ptr->LINK.NEXT);
} /* Endwhile */
_lwsem_post((LWSEM_STRUCT_PTR) &kernel_data->MEM_COMP.SEM);
*pool_error_ptr = (_mem_pool_id) pool_ptr;
return (result);
} /* Endbody */
/*!
* \brief Tests the memory in the memory pool.
*
* If _mem_test_pool() indicates an error, _mem_get_error_pool() indicates which
* block has the error.
*
* \param[in] pool_id The pool to check.
*
* \return MQX_OK (No errors found.)
* \return MQX_CORRUPT_STORAGE_POOL (A memory pool pointer is not correct.)
* \return MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \return MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect (header is corrupted).)
*
* \see _mem_get_error_pool
* \see _mem_test
* \see _task_set_error
*/
_mqx_uint _mem_test_pool
(
_mem_pool_id pool_id
)
{ /* Body */
_KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data;)
STOREBLOCK_STRUCT_PTR next_block_ptr;
MEMPOOL_STRUCT_PTR mem_pool_ptr;
_mqx_uint result = MQX_OK;
_KLOGM(_GET_KERNEL_DATA(kernel_data);)
_KLOGE2(KLOG_mem_test_pool, pool_id);
mem_pool_ptr = (MEMPOOL_STRUCT_PTR) pool_id;
/* First check the physical blocks */
mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK = (STOREBLOCK_STRUCT_PTR) mem_pool_ptr->POOL_PTR;
while (mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK < mem_pool_ptr->POOL_END_PTR) {
if ((!mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK) || (!_MEMORY_ALIGNED(mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK))) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = (STOREBLOCK_STRUCT_PTR) mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK;
result = MQX_CORRUPT_STORAGE_POOL;
break;
} /* Endif */
_int_disable();
if (!VALID_CHECKSUM(mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK)) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = (STOREBLOCK_STRUCT_PTR) mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK;
_int_enable();
result = MQX_INVALID_CHECKSUM;
break;
} /* Endif */
next_block_ptr = NEXT_PHYS(mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK);
if (next_block_ptr->PREVBLOCK != mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = next_block_ptr;
_int_enable();
result = MQX_CORRUPT_STORAGE_POOL;
break;
} /* Endif */
mem_pool_ptr->POOL_PHYSICAL_CHECK_BLOCK = next_block_ptr;
_int_enable();
} /* Endwhile */
if (result != MQX_OK) {
_KLOGX3(KLOG_mem_test_pool, result, mem_pool_ptr->POOL_BLOCK_IN_ERROR);
return (result);
} /* Endif */
/* Now check the free list */
_int_disable();
if (mem_pool_ptr->POOL_FREE_LIST_PTR == NULL) { /* no free list to check */
_int_enable();
return MQX_OK;
} /* Endif */
mem_pool_ptr->POOL_FREE_CHECK_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
next_block_ptr = mem_pool_ptr->POOL_FREE_CHECK_BLOCK;
if (next_block_ptr->USER_AREA != (pointer) NULL) {
_KLOGX3(KLOG_mem_test_pool, MQX_CORRUPT_STORAGE_POOL_FREE_LIST, next_block_ptr );
mem_pool_ptr->POOL_BLOCK_IN_ERROR = next_block_ptr;
_int_enable();
return (MQX_CORRUPT_STORAGE_POOL_FREE_LIST);
} /* Endif */
_int_enable();
while (mem_pool_ptr->POOL_FREE_CHECK_BLOCK < mem_pool_ptr->POOL_END_PTR) {
if ((!mem_pool_ptr->POOL_FREE_CHECK_BLOCK) || (!_MEMORY_ALIGNED(mem_pool_ptr->POOL_FREE_CHECK_BLOCK))) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = mem_pool_ptr->POOL_FREE_CHECK_BLOCK;
result = MQX_CORRUPT_STORAGE_POOL_FREE_LIST;
break;
} /* Endif */
_int_disable();
if (!VALID_CHECKSUM(mem_pool_ptr->POOL_FREE_CHECK_BLOCK)) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = mem_pool_ptr->POOL_FREE_CHECK_BLOCK;
_int_enable();
result = MQX_INVALID_CHECKSUM;
break;
} /* Endif */
_int_enable();
_int_disable();
if (BLOCK_IS_USED(mem_pool_ptr->POOL_FREE_CHECK_BLOCK)) {
/* An allocated block on the free list */
mem_pool_ptr->POOL_BLOCK_IN_ERROR = mem_pool_ptr->POOL_FREE_CHECK_BLOCK;
_int_enable();
result = MQX_CORRUPT_STORAGE_POOL_FREE_LIST;
break;
} /* Endif */
next_block_ptr = (STOREBLOCK_STRUCT_PTR) NEXT_FREE(mem_pool_ptr->POOL_FREE_CHECK_BLOCK);
if (!next_block_ptr) {
_int_enable(); /* If zero, free list has been completed */
break;
} /* Endif */
if (next_block_ptr->USER_AREA != (char _PTR_) mem_pool_ptr->POOL_FREE_CHECK_BLOCK) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = mem_pool_ptr->POOL_FREE_CHECK_BLOCK;
_int_enable();
result = MQX_CORRUPT_STORAGE_POOL_FREE_LIST;
break;
} /* Endif */
mem_pool_ptr->POOL_FREE_CHECK_BLOCK = next_block_ptr;
_int_enable();
} /* Endwhile */
if (result == MQX_OK) {
_KLOGX2(KLOG_mem_test_pool, result);
}
else {
_KLOGX3(KLOG_mem_test_pool, result, mem_pool_ptr->POOL_BLOCK_IN_ERROR);
} /* Endif */
return (result);
} /* Endbody */
/*!
* \brief Tests memory that the memory component uses to allocate memory from
* the default memory pool.
*
* The function checks the checksums of all memory-block headers. If the
* function detects an error, _mem_get_error() gets the block in error.
* \n The function can be called by only one task at a time because it keeps
* state-in-progress variables that MQX controls. This mechanism lets other
* tasks allocate and free memory while _mem_test() runs.
*
* \return MQX_OK (No errors found.)
* \return MQX_CORRUPT_STORAGE_POOL (A memory pool pointer is not correct.)
* \return MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \return MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect (header is corrupted).)
*
* \warning Can be called by only one task at a time (see Description).
* \warning Disables and enables interrupts.
*
* \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 _mem_get_error
* \see _mem_test_pool
*/
_mqx_uint _mem_test
(
void
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
_mqx_uint result;
_GET_KERNEL_DATA(kernel_data);
result = _mem_test_pool((_mem_pool_id) &kernel_data->KD_POOL);
return (result);
} /* Endbody */
/*!
* \brief Gets the highest memory address that MQX has allocated in the default
* memory pool.
*
* The function gets the highwater mark; that is, the highest memory address
* ever allocated by MQX in the default memory pool. The mark does not decrease
* if tasks free memory in the default memory pool.
* \n If a task extends the default memory pool (_mem_extend()) with an area
* above the highwater mark and MQX subsequently allocates memory from the
* extended memory, the function returns an address from the extended memory.
*
* \return Highest address allocated in the default memory 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 _mem_extend
* \see _mem_get_highwater_pool
*/
pointer _mem_get_highwater
(
void
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
_GET_KERNEL_DATA(kernel_data);
return (kernel_data->KD_POOL.POOL_HIGHEST_MEMORY_USED);
} /* Endbody */
/*!
* \brief Gets the highest memory address that MQX has allocated in the pool.
*
* The function gets the highwater mark; that is, the highest memory address
* ever allocated in the memory pool. The mark does not decrease if tasks free
* blocks in the pool.
* \n If a task extends the memory pool (_mem_extend_pool()) with an area above
* the highwater mark and MQX subsequently allocates memory from the extended
* memory, the function returns an address from the extended memory.
*
* \param[in] pool_id Pool for which to get the highwater mark (from
* _mem_create_pool()).
*
* \return Highest address allocated in the memory 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 _mem_create_pool
* \see _mem_extend_pool
* \see _mem_get_highwater
*/
pointer _mem_get_highwater_pool
(
_mem_pool_id pool_id
)
{ /* Body */
MEMPOOL_STRUCT_PTR mem_pool_ptr = (MEMPOOL_STRUCT_PTR) pool_id;
return (mem_pool_ptr->POOL_HIGHEST_MEMORY_USED);
} /* Endbody */
/*!
* \brief Gets the last memory block which caused a corrupt memory pool error in
* kernel data.
*
* If _mem_test() indicates an error in the default memory pool, _mem_get_error()
* indicates which block has the error.
* \n In each memory block header, MQX maintains internal information, including
* a checksum of the information. As tasks call functions from the _mem family,
* MQX recalculates the checksum and compares it with the original. If the
* checksums do not match, MQX marks the block as corrupted.
* \n A block will be corrupted if:
* \n - A task writes past the end of an allocated memory block and into the
* header information in the next block. This can occur if:
* \li The task allocated a block smaller than it needed.
* \li A task overflows its stack.
* \li A pointer is out of range.
*
* \n - A task randomly overwrites memory in the default memory pool.
*
* \return Pointer to the memory block that is corrupted.
*
* \see _mem_test
*/
pointer _mem_get_error
(
void
)
{ /* Body */
register KERNEL_DATA_STRUCT_PTR kernel_data;
register pointer user_ptr;
_GET_KERNEL_DATA(kernel_data);
user_ptr = (pointer) ((uchar_ptr) kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR
+ FIELD_OFFSET(STOREBLOCK_STRUCT,USER_AREA));
return (user_ptr);
} /* Endbody */
/*!
* \brief Gets the last memory block which caused a corrupt memory pool error in
* the specified pool.
*
* \param[in] pool_id Memory pool from which to get the block.
*
* \return Pointer to the memory block.
*
* \see _mem_test_pool
*/
pointer _mem_get_error_pool
(
_mem_pool_id pool_id
)
{ /* Body */
MEMPOOL_STRUCT_PTR mem_pool_ptr = (MEMPOOL_STRUCT_PTR) pool_id;
register pointer user_ptr;
user_ptr = (pointer) ((uchar_ptr) mem_pool_ptr->POOL_BLOCK_IN_ERROR + FIELD_OFFSET(STOREBLOCK_STRUCT,USER_AREA));
return (user_ptr);
} /* Endbody */
/*!
* \brief Gets the pool ID of the system pool.
*
* \return system pool ID.
*/
_mem_pool_id _mem_get_system_pool_id
(
void
)
{
register KERNEL_DATA_STRUCT_PTR kernel_data;
_GET_KERNEL_DATA(kernel_data);
return (_mem_pool_id) &kernel_data->KD_POOL;
}
#if MQX_ALLOW_TYPED_MEMORY
/*!
* \brief Gets the type of the specified block.
*
* \param[in] mem_ptr Address of the memory block to get type of.
*
* \return Pointer to the memory block type.
*/
_mem_type _mem_get_type
(
pointer mem_ptr
)
{
STOREBLOCK_STRUCT_PTR block_ptr;
block_ptr = GET_MEMBLOCK_PTR(mem_ptr);
return block_ptr->MEM_TYPE;
}
/*!
* \brief Sets type of the specified block.
*
* \param[in] mem_ptr Address of the memory block to set type.
* \param[in] mem_type Memory type to set.
*
* \return TRUE (Type has been set.), FALSE (Type has not been set.).
*/
boolean _mem_set_type
(
pointer mem_ptr,
_mem_type mem_type
)
{
STOREBLOCK_STRUCT_PTR block_ptr;
if (mem_ptr != NULL) {
block_ptr = GET_MEMBLOCK_PTR(mem_ptr);
_int_disable();
block_ptr->MEM_TYPE = mem_type;
CALC_CHECKSUM(block_ptr);
_int_enable();
return TRUE;
}
else {
return FALSE;
}
}
#endif /* MQX_ALLOW_TYPED_MEMORY */
/*!
* \brief Transfers the ownership of a block of memory from an owner task to
* another task.
*
* \param[in] memory_ptr A memory block whose ownership is to be transferred.
* \param[in] source_id Task ID of the current owner.
* \param[in] target_id Task ID of the new owner.
*
* \return MQX_OK
* \return MQX_INVALID_CHECKSUM (Block's checksum is not correct, indicating
* that at least some of the block was overwritten.)
* \return MQX_INVALID_POINTER (Block_ptr is NULL or misaligned.)
* \return MQX_INVALID_TASK_ID (Source or target does not represent a valid task.)
* \return MQX_NOT_RESOURCE_OWNER (Memory block is not a resource of the task
* represented by source.)
*
* \warning On failure, calls _task_set_error() to set the error code (see Return).
*
* \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 _mqx_get_system_task_id
* \see _task_set_error
*/
_mqx_uint _mem_transfer
(
pointer memory_ptr,
_task_id source_id,
_task_id target_id
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
STOREBLOCK_STRUCT_PTR block_ptr;
TD_STRUCT_PTR source_td;
TD_STRUCT_PTR target_td;
_mqx_uint result;
_GET_KERNEL_DATA(kernel_data);
_KLOGE4(KLOG_mem_transfer, memory_ptr, source_id, target_id);
#if MQX_CHECK_ERRORS
if (memory_ptr == NULL) {
_task_set_error(MQX_INVALID_POINTER);
_KLOGX2(KLOG_mem_transfer, MQX_INVALID_POINTER);
return (MQX_INVALID_POINTER);
} /* Endif */
#endif
/* Verify the block */
block_ptr = GET_MEMBLOCK_PTR(memory_ptr);
#if MQX_CHECK_ERRORS
if (!_MEMORY_ALIGNED(block_ptr)) {
_task_set_error(MQX_INVALID_POINTER);
_KLOGX2(KLOG_mem_transfer, MQX_INVALID_POINTER);
return (MQX_INVALID_POINTER);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (!VALID_CHECKSUM(block_ptr)) {
_task_set_error(MQX_INVALID_CHECKSUM);
kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR = block_ptr;
_KLOGX2(KLOG_mem_transfer, MQX_INVALID_CHECKSUM);
return (MQX_INVALID_CHECKSUM);
} /* Endif */
#endif
source_td = (TD_STRUCT_PTR) _task_get_td(source_id);
target_td = (TD_STRUCT_PTR) _task_get_td(target_id);
#if MQX_CHECK_ERRORS
if ((source_td == NULL) || (target_td == NULL)) {
_task_set_error(MQX_INVALID_TASK_ID);
_KLOGX2(KLOG_mem_transfer, MQX_INVALID_TASK_ID);
return (MQX_INVALID_TASK_ID);
} /* Endif */
#endif
_INT_DISABLE();
result = _mem_transfer_td_internal(memory_ptr, source_td, target_td);
if (result != MQX_OK) _task_set_error(result);
_INT_ENABLE();
_KLOGX2(KLOG_mem_transfer, result);
return (result);
} /* Endbody */
/*!
* \private
*
* \brief Transfers the ownership of a block of memory from an owner task to
* another task.
*
* \param[in] memory_ptr Address of the USER_AREA in the memory block to transfer.
* \param[in] target_td Target task descriptor.
*/
void _mem_transfer_internal
(
pointer memory_ptr,
TD_STRUCT_PTR target_td
)
{ /* Body */
STOREBLOCK_STRUCT_PTR block_ptr;
/* Verify the block */
block_ptr = GET_MEMBLOCK_PTR(memory_ptr);
/* Link the block onto the target's task descriptor. */
block_ptr->NEXTBLOCK = target_td->MEMORY_RESOURCE_LIST;
target_td->MEMORY_RESOURCE_LIST = (char _PTR_) (&block_ptr->USER_AREA);
block_ptr->TASK_NUMBER = TASK_NUMBER_FROM_TASKID(target_td->TASK_ID);
CALC_CHECKSUM(block_ptr);
} /* Endbody */
/*!
* \private
*
* \brief Transfers the ownership of a block of memory from an owner task to
* another task.
*
* \param[in] memory_ptr A memory block whose ownership is to be transferred.
* \param[in] source_td Task ID of the current owner.
* \param[in] target_td Task ID of the new owner.
*
* \return MQX_OK
* \return MQX_NOT_RESOURCE_OWNER
*/
_mqx_uint _mem_transfer_td_internal
(
pointer memory_ptr,
TD_STRUCT_PTR source_td,
TD_STRUCT_PTR target_td
)
{ /* Body */
STOREBLOCK_STRUCT_PTR block_ptr;
STOREBLOCK_STRUCT_PTR prev_block_ptr = NULL; /* Initialize to supress compiler warning */
STOREBLOCK_STRUCT_PTR next_block_ptr;
block_ptr = GET_MEMBLOCK_PTR(memory_ptr);
next_block_ptr = (STOREBLOCK_STRUCT_PTR) source_td->MEMORY_RESOURCE_LIST;
/* prev_block_ptr = GET_MEMBLOCK_PTR(&source_td->MEMORY_RESOURCE_LIST); */
if (memory_ptr == next_block_ptr) {
/*
* This is the last item on the resource list of the
* source task. Remove it from the resource list by
* pointing the resource list to the next item.
*/
source_td->MEMORY_RESOURCE_LIST = block_ptr->NEXTBLOCK;
}
else {
/* Scan the task's memory resource list searching for the block.
* Stop when the current pointer is equal to the block,
* or the end of the list is reached.
*/
while (next_block_ptr && ((pointer) next_block_ptr != memory_ptr)) {
prev_block_ptr = GET_MEMBLOCK_PTR(next_block_ptr);
next_block_ptr = (STOREBLOCK_STRUCT_PTR) prev_block_ptr->NEXTBLOCK;
} /* Endwhile */
if (!next_block_ptr) {
/* The specified block does not belong to the source task. */
return (MQX_NOT_RESOURCE_OWNER);
} /* Endif */
/* Remove the memory block from the resource list of the
* source task.
*/
prev_block_ptr->NEXTBLOCK = block_ptr->NEXTBLOCK;
} /* Endif */
_mem_transfer_internal(memory_ptr, target_td);
return (MQX_OK);
} /* Endbody */
/*!
* \brief Allocates a block of memory.
*
* See Description of _mem_alloc() function.
*
* \param[in] pool_id Pool from which to allocate the memory block (from
* _mem_create_pool()).
* \param[in] size Size of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \see _mem_alloc()
* \see _mem_alloc_from()
* \see _mem_alloc_system()
* \see _mem_alloc_system_from()
* \see _mem_alloc_system_zero()
* \see _mem_alloc_zero()
* \see _mem_alloc_zero_form()
* \see _mem_alloc_align()
* \see _mem_alloc_align_from()
* \see _mem_alloc_at()
* \see _mem_create_pool
* \see _mem_free
* \see _mem_get_highwater
* \see _mem_get_highwater_pool
* \see _mem_get_size
* \see _mem_transfer
* \see _mem_free_part
* \see _msg_alloc
* \see _msg_alloc_system
* \see _task_set_error
*/
pointer _mem_alloc_system_zero_from
(
_mem_pool_id pool_id,
_mem_size size
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
MEMPOOL_STRUCT_PTR mem_pool_ptr;
pointer result;
_mqx_uint error;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc_system_zero_from, size);
mem_pool_ptr = (MEMPOOL_STRUCT_PTR) pool_id;
_INT_DISABLE();
result = _mem_alloc_internal(size, SYSTEM_TD_PTR(kernel_data), mem_pool_ptr, &error);
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
_INT_ENABLE();
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
if (result != NULL) {
_mem_zero(result, size);
} /* Endif */
_KLOGX3(KLOG_mem_alloc_system_zero_from, result, mem_pool_ptr->POOL_BLOCK_IN_ERROR);
return (result);
} /* Endbody */
/*!
* \brief Allocates a block of memory.
*
* See Description of _mem_alloc() function.
*
* \param[in] size Size of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \see _mem_alloc()
* \see _mem_alloc_from()
* \see _mem_alloc_system()
* \see _mem_alloc_system_from()
* \see _mem_alloc_system_zero_from()
* \see _mem_alloc_zero()
* \see _mem_alloc_zero_form()
* \see _mem_alloc_align()
* \see _mem_alloc_align_from()
* \see _mem_alloc_at()
* \see _mem_create_pool
* \see _mem_free
* \see _mem_get_highwater
* \see _mem_get_highwater_pool
* \see _mem_get_size
* \see _mem_transfer
* \see _mem_free_part
* \see _msg_alloc
* \see _msg_alloc_system
* \see _task_set_error
*/
pointer _mem_alloc_system_zero
(
_mem_size size
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
pointer result;
_mqx_uint error;
_GET_KERNEL_DATA(kernel_data);
_KLOGE2(KLOG_mem_alloc_system_zero, size);
_INT_DISABLE();
result = _mem_alloc_internal(size, SYSTEM_TD_PTR(kernel_data), (MEMPOOL_STRUCT_PTR) & kernel_data->KD_POOL, &error);
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
kernel_data->KD_POOL.POOL_ALLOC_CURRENT_BLOCK = kernel_data->KD_POOL.POOL_FREE_LIST_PTR;
_INT_ENABLE();
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
if (result != NULL) {
_mem_zero(result, size);
} /* Endif */
_KLOGX3(KLOG_mem_alloc_system_zero, result, kernel_data->KD_POOL.POOL_BLOCK_IN_ERROR);
return (result);
}
#if MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE
/*!
* \brief Allocates uncached memory from the system, zeroed.
*
* \param[in] size Size of the memory block.
*
* \return Pointer to the memory block (Success.)
* \return NULL (Failure: see task error codes.)
*
* \warning On failure, calls _task_set_error() to set one of the following
* task error codes:
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*/
pointer _mem_alloc_system_zero_uncached
(
_mem_size size
)
{ /* Body */
KERNEL_DATA_STRUCT_PTR kernel_data;
pointer result;
_mqx_uint error;
_GET_KERNEL_DATA(kernel_data);
/*_KLOGE2(KLOG_mem_alloc_system_zero_uncached, size);*/
_INT_DISABLE();
result = _mem_alloc_internal(size, SYSTEM_TD_PTR(kernel_data), (MEMPOOL_STRUCT_PTR)kernel_data->UNCACHED_POOL, &error);
/* update the memory allocation pointer in case a lower priority
* task was preempted inside _mem_alloc_internal
*/
kernel_data->UNCACHED_POOL->POOL_ALLOC_CURRENT_BLOCK = kernel_data->UNCACHED_POOL->POOL_FREE_LIST_PTR;
_INT_ENABLE();
#if MQX_CHECK_ERRORS
if (error != MQX_OK) {
_task_set_error(error);
} /* Endif */
#endif
if (result != NULL) {
_mem_zero(result, size);
} /* Endif */
/*_KLOGX3(KLOG_mem_alloc_system_zero_uncached, result, kernel_data->UNCACHED_POOL.POOL_BLOCK_IN_ERROR);*/
return(result);
}
#endif /* MQX_USE_UNCACHED_MEM && PSP_HAS_DATA_CACHE */
/*!
* \private
*
* \brief Internal function for memory allocation.
*
* This function must be called disabled.
* \n A pointer to memory that can be used is returned. _mem_alloc_internal
* walks down the free list, looking for a block big enough to satisfy the
* request. If the found block is bigger than needed, then a new free block is
* created from the remnants, and added into the free list.
* \n A global memory pointer is used, this allows higher priority tasks to
* pre-empt the current task in _mem_alloc_internal. Care is taken to make sure
* that when the higher priority task is completed, the memory pool search
* pointer is reset to the beginning of the free list.
* \n Since the memory test function may be running concurrently with the
* allocator, the memory test pointers are reset.
*
* \param[in] requested_size Size of the memory block.
* \param[in] td_ptr Owner's TD.
* \param[in] mem_pool_ptr Which pool to allocate from.
* \param[out] error_ptr Error code for operation:
* \li MQX_OK
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \return Pointer to the memory block (success)
* \return NULL (Failure: see task error codes.)
* \return (pointer) NULL (Failure: see task error codes.)
*/
pointer _mem_alloc_internal
(
_mem_size requested_size,
TD_STRUCT_PTR td_ptr,
MEMPOOL_STRUCT_PTR mem_pool_ptr,
_mqx_uint_ptr error_ptr
)
{ /* Body */
STOREBLOCK_STRUCT_PTR block_ptr;
STOREBLOCK_STRUCT_PTR next_block_ptr;
STOREBLOCK_STRUCT_PTR next_next_block_ptr;
_mem_size block_size;
_mem_size next_block_size;
*error_ptr = MQX_OK;
/*
* Adjust message size to allow for block management overhead
* and force size to be aligned.
*/
requested_size += (_mem_size) (FIELD_OFFSET(STOREBLOCK_STRUCT,USER_AREA));
#if MQX_CHECK_ERRORS
if (requested_size < MQX_MIN_MEMORY_STORAGE_SIZE) {
requested_size = MQX_MIN_MEMORY_STORAGE_SIZE;
} /* Endif */
#endif
_MEMORY_ALIGN_VAL_LARGER(requested_size);
block_ptr = mem_pool_ptr->POOL_FREE_LIST_PTR;
while (TRUE) {
/*
* Save the current block pointer.
* We will be enabling access to higher priority tasks.
* A higher priority task may pre-empt the current task
* and may do a memory allocation. If this is true,
* the higher priority task will reset the POOL_ALLOC_CURRENT_BLOCK
* upon exit, and the current task will start the search over again.
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = block_ptr;
/* allow pending interrupts */
_int_enable();
_int_disable();
/* Get block pointer in case reset by a higher priority task */
block_ptr = mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK;
if (block_ptr == NULL) { /* Null pointer */
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_OUT_OF_MEMORY;
return (NULL); /* request failed */
} /* Endif */
#if MQX_CHECK_VALIDITY
if (!_MEMORY_ALIGNED(block_ptr) || BLOCK_IS_USED(block_ptr)) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_CORRUPT_STORAGE_POOL_FREE_LIST;
return ((pointer) NULL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (!VALID_CHECKSUM(block_ptr)) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_INVALID_CHECKSUM;
return ((pointer) NULL);
} /* Endif */
#endif
block_size = block_ptr->BLOCKSIZE;
if (block_size >= requested_size) {
/* request fits into this block */
next_block_size = block_size - requested_size;
if (next_block_size >= (2 * MQX_MIN_MEMORY_STORAGE_SIZE)) {
/*
* The current block is big enough to split.
* into 2 blocks.... the part to be allocated is one block,
* and the rest remains as a free block on the free list.
*/
next_block_ptr = (STOREBLOCK_STRUCT_PTR)((char _PTR_) block_ptr + requested_size);
/* Initialize the new physical block values */
next_block_ptr->BLOCKSIZE = next_block_size;
next_block_ptr->PREVBLOCK = (STOREBLOCK_STRUCT_PTR) block_ptr;
MARK_BLOCK_AS_FREE(next_block_ptr);
CALC_CHECKSUM(next_block_ptr);
/* Link new block into the free list */
next_block_ptr->NEXTBLOCK = block_ptr->NEXTBLOCK;
block_ptr->NEXTBLOCK = (pointer) next_block_ptr;
next_block_ptr->USER_AREA = (pointer) block_ptr;
if (next_block_ptr->NEXTBLOCK != NULL) {
((STOREBLOCK_STRUCT_PTR) next_block_ptr->NEXTBLOCK)-> USER_AREA = (pointer) next_block_ptr;
} /* Endif */
/*
* Modify the block on the other side of the next block
* (the next next block) so that it's previous block pointer
* correctly point to the next block.
*/
next_next_block_ptr = (STOREBLOCK_STRUCT_PTR) NEXT_PHYS(next_block_ptr);
PREV_PHYS( next_next_block_ptr) = next_block_ptr;
CALC_CHECKSUM(next_next_block_ptr);
}
else {
/* Take the entire block */
requested_size = block_size;
} /* Endif */
/* Set the size of the block */
block_ptr->BLOCKSIZE = requested_size;
/* Indicate the block is in use */
MARK_BLOCK_AS_USED(block_ptr, td_ptr->TASK_ID);
block_ptr->MEM_TYPE = 0;
CALC_CHECKSUM(block_ptr);
/* Unlink the block from the free list */
if (block_ptr == mem_pool_ptr->POOL_FREE_LIST_PTR) {
/* At the head of the free list */
mem_pool_ptr->POOL_FREE_LIST_PTR = (STOREBLOCK_STRUCT_PTR) NEXT_FREE(block_ptr);
if (mem_pool_ptr->POOL_FREE_LIST_PTR != NULL) {
PREV_FREE(mem_pool_ptr->POOL_FREE_LIST_PTR) = 0;
} /* Endif */
}
else {
/*
* NOTE: PREV_FREE guaranteed to be non-zero
* Have to make the PREV_FREE of this block
* point to the NEXT_FREE of this block
*/
NEXT_FREE( PREV_FREE(
block_ptr)) = NEXT_FREE(block_ptr);
if (NEXT_FREE(block_ptr) != NULL) {
/*
* Now have to make the NEXT_FREE of this block
* point to the PREV_FREE of this block
*/
PREV_FREE( NEXT_FREE(
block_ptr)) = PREV_FREE(block_ptr);
} /* Endif */
} /* Endif */
#if MQX_MEMORY_FREE_LIST_SORTED == 1
if (block_ptr == mem_pool_ptr->POOL_FREE_CURRENT_BLOCK) {
/* Reset the freelist insertion sort by _mem_free */
mem_pool_ptr->POOL_FREE_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
} /* Endif */
#endif
/* Reset the __mem_test freelist pointer */
mem_pool_ptr->POOL_FREE_CHECK_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
/*
* Set the curent pool block to the start of the free list, so
* that if this task pre-empted another that was performing a
* _mem_alloc, the other task will restart it's search for a block
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
/* Remember some statistics - only for blocks which fall into the
* main pool area. Ignore blocks in the extended areas (EXT_LIST)
*/
next_block_ptr = NEXT_PHYS(block_ptr);
if (((char _PTR_)(next_block_ptr) > (char _PTR_) mem_pool_ptr->POOL_HIGHEST_MEMORY_USED) &&
((char _PTR_)(next_block_ptr) > (char _PTR_) mem_pool_ptr->POOL_PTR) &&
((char _PTR_)(next_block_ptr) < (char _PTR_) mem_pool_ptr->POOL_END_PTR)
)
{
mem_pool_ptr->POOL_HIGHEST_MEMORY_USED = ((char _PTR_)(next_block_ptr) - 1);
} /* Endif */
/* Link the block onto the task descriptor. */
block_ptr->NEXTBLOCK = td_ptr->MEMORY_RESOURCE_LIST;
td_ptr->MEMORY_RESOURCE_LIST = (pointer) (&block_ptr->USER_AREA);
block_ptr->MEM_POOL_PTR = (pointer) mem_pool_ptr;
#if MQX_CHECK_VALIDITY
/* Check that user area is aligned on a cache line boundary */
if (!_MEMORY_ALIGNED(&block_ptr->USER_AREA)) {
*error_ptr = MQX_INVALID_CONFIGURATION;
return ((pointer) NULL);
} /* Endif */
#endif
return ((pointer) (&block_ptr->USER_AREA));
}
else {
block_ptr = (STOREBLOCK_STRUCT_PTR) NEXT_FREE(block_ptr);
} /* Endif */
} /* Endwhile */
#ifdef lint
return( NULL ); /* to satisfy lint */
#endif
} /* Endbody */
/*!
* \private
*
* \brief Internal function for memory allocation at specified position.
*
* \param[in] requested_size Size of the memory block.
* \param[in] requested_addr Address of the memory block to allocate.
* \param[in] td_ptr Owner TD.
* \param[in] mem_pool_ptr Which pool to allocate from.
* \param[out] error_ptr Error code for operation:
* \li MQX_OK
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \return Pointer to the memory block (success)
* \return NULL (Failure: see task error codes.)
* \return (pointer) NULL (Failure: see task error codes.)
*/
pointer _mem_alloc_at_internal
(
_mem_size requested_size,
pointer requested_addr,
TD_STRUCT_PTR td_ptr,
MEMPOOL_STRUCT_PTR mem_pool_ptr,
_mqx_uint_ptr error_ptr
)
{ /* Body */
STOREBLOCK_STRUCT_PTR block_ptr, free_block_ptr;
STOREBLOCK_STRUCT_PTR next_block_ptr;
STOREBLOCK_STRUCT_PTR next_next_block_ptr;
_mem_size block_size, next_block_size, free_block_size;
*error_ptr = MQX_OK;
/*
* Adjust message size to allow for block management overhead
* and force size to be aligned.
*/
requested_size += (_mem_size) (FIELD_OFFSET(STOREBLOCK_STRUCT,USER_AREA));
#if MQX_CHECK_ERRORS
if (requested_size < MQX_MIN_MEMORY_STORAGE_SIZE) {
requested_size = MQX_MIN_MEMORY_STORAGE_SIZE;
} /* Endif */
#endif
_MEMORY_ALIGN_VAL_LARGER(requested_size);
block_ptr = mem_pool_ptr->POOL_FREE_LIST_PTR;
while (TRUE) {
/*
* Save the current block pointer.
* We will be enabling access to higher priority tasks.
* A higher priority task may pre-empt the current task
* and may do a memory allocation. If this is true,
* the higher priority task will reset the POOL_ALLOC_CURRENT_BLOCK
* upon exit, and the current task will start the search over
* again.
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = block_ptr;
/* allow pending interrupts */
_int_enable();
_int_disable();
/* Get block pointer in case reset by a higher priority task */
block_ptr = mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK;
if (block_ptr == NULL) { /* Null pointer */
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_OUT_OF_MEMORY;
return (NULL); /* request failed */
} /* Endif */
#if MQX_CHECK_VALIDITY
if (!_MEMORY_ALIGNED(block_ptr) || BLOCK_IS_USED(block_ptr)) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_CORRUPT_STORAGE_POOL_FREE_LIST;
return ((pointer) NULL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if (!VALID_CHECKSUM(block_ptr)) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_INVALID_CHECKSUM;
return ((pointer) NULL);
} /* Endif */
#endif
block_size = block_ptr->BLOCKSIZE;
if ((uchar_ptr) &block_ptr->USER_AREA <= (uchar_ptr) requested_addr && (uchar_ptr) &block_ptr->USER_AREA
+ block_size >= (uchar_ptr) requested_addr + requested_size && block_size >= requested_size) {
/* request fits into this block */
/* create new free block */
free_block_ptr = (STOREBLOCK_STRUCT_PTR)((char _PTR_) block_ptr);
block_ptr = (STOREBLOCK_STRUCT_PTR)((uchar_ptr) requested_addr
- (_mem_size) (FIELD_OFFSET(STOREBLOCK_STRUCT,USER_AREA)));
free_block_size = (uchar_ptr) block_ptr - (uchar_ptr) free_block_ptr;
next_block_size = block_size - requested_size - free_block_size;
if (next_block_size >= (2 * MQX_MIN_MEMORY_STORAGE_SIZE)) {
/*
* The current block is big enough to split.
* into 2 blocks.... the part to be allocated is one block,
* and the rest remains as a free block on the free list.
*/
next_block_ptr = (STOREBLOCK_STRUCT_PTR)((char _PTR_) block_ptr + requested_size);
/* Initialize the new physical block values */
next_block_ptr->BLOCKSIZE = next_block_size;
next_block_ptr->PREVBLOCK = (STOREBLOCK_STRUCT_PTR) block_ptr;
MARK_BLOCK_AS_FREE(next_block_ptr);
CALC_CHECKSUM(next_block_ptr);
/* Link new block into the free list */
next_block_ptr->NEXTBLOCK = free_block_ptr->NEXTBLOCK;
block_ptr->NEXTBLOCK = (pointer) next_block_ptr;
next_block_ptr->USER_AREA = (pointer) block_ptr;
if (next_block_ptr->NEXTBLOCK != NULL) {
((STOREBLOCK_STRUCT_PTR) next_block_ptr->NEXTBLOCK)->USER_AREA = (pointer) next_block_ptr;
}
/*
* Modify the current block, to point to this newly created
* block which is now the next physical block.
*/
block_ptr->BLOCKSIZE = requested_size;
/*
* Modify the block on the other side of the next block
* (the next next block) so that it's previous block pointer
* correctly point to the next block.
*/
next_next_block_ptr = (STOREBLOCK_STRUCT_PTR) NEXT_PHYS(next_block_ptr);
PREV_PHYS( next_next_block_ptr) = next_block_ptr;
CALC_CHECKSUM(next_next_block_ptr);
}
else {
/* Take the entire block */
requested_size += next_block_size;
next_block_ptr = free_block_ptr->NEXTBLOCK;
}
if (free_block_size >= (2 * MQX_MIN_MEMORY_STORAGE_SIZE)) {
/* modify the new physical block values */
free_block_ptr->BLOCKSIZE = free_block_size;
free_block_ptr->NEXTBLOCK = (pointer) next_block_ptr;
MARK_BLOCK_AS_FREE(free_block_ptr);
CALC_CHECKSUM(free_block_ptr);
/* Set the size of the block */
block_ptr->BLOCKSIZE = requested_size;
block_ptr->PREVBLOCK = (STOREBLOCK_STRUCT_PTR) free_block_ptr;
block_ptr->MEM_TYPE = 0;
MARK_BLOCK_AS_USED(block_ptr, td_ptr->TASK_ID);
CALC_CHECKSUM(block_ptr);
}
else {
/* Set the size of the block */
block_ptr->PREVBLOCK = PREV_PHYS(free_block_ptr);/*->PREVBLOCK;*/
block_ptr->BLOCKSIZE = requested_size;
block_ptr->MEM_TYPE = 0;
MARK_BLOCK_AS_USED(block_ptr, td_ptr->TASK_ID);
CALC_CHECKSUM(block_ptr);
(block_ptr->PREVBLOCK)->BLOCKSIZE += free_block_size;
CALC_CHECKSUM(block_ptr->PREVBLOCK);
/* Unlink the block from the free list */
if (free_block_ptr == mem_pool_ptr->POOL_FREE_LIST_PTR) {
/* At the head of the free list */
mem_pool_ptr->POOL_FREE_LIST_PTR = next_block_ptr;
if (mem_pool_ptr->POOL_FREE_LIST_PTR != NULL) {
PREV_FREE(mem_pool_ptr->POOL_FREE_LIST_PTR) = 0;
}
}
else {
/*
* NOTE: PREV_FREE guaranteed to be non-zero
* Have to make the PREV_FREE of this block
* point to the NEXT_FREE of this block
*/
NEXT_FREE( PREV_FREE(
free_block_ptr)) = NEXT_FREE(free_block_ptr);
if (NEXT_FREE(free_block_ptr) != NULL) {
/*
* Now have to make the NEXT_FREE of this block
* point to the PREV_FREE of this block
*/
PREV_FREE( NEXT_FREE(
free_block_ptr)) = PREV_FREE(free_block_ptr);
}
}
#if MQX_MEMORY_FREE_LIST_SORTED == 1
if (free_block_ptr == mem_pool_ptr->POOL_FREE_CURRENT_BLOCK) {
/* Reset the freelist insertion sort by _mem_free */
mem_pool_ptr->POOL_FREE_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
}
#endif
}
/* Reset the __mem_test freelist pointer */
mem_pool_ptr->POOL_FREE_CHECK_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
/*
* Set the curent pool block to the start of the free list, so
* that if this task pre-empted another that was performing a
* _mem_alloc, the other task will restart it's search for a block
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
/* Remember some statistics */
next_block_ptr = NEXT_PHYS(block_ptr);
if (((char _PTR_)(next_block_ptr) > (char _PTR_) mem_pool_ptr->POOL_HIGHEST_MEMORY_USED) &&
((char _PTR_)(next_block_ptr) > (char _PTR_) mem_pool_ptr->POOL_PTR) &&
((char _PTR_)(next_block_ptr) < (char _PTR_) mem_pool_ptr->POOL_END_PTR)
)
{
mem_pool_ptr->POOL_HIGHEST_MEMORY_USED = ((char _PTR_)(next_block_ptr) - 1);
}
/* Link the block onto the task descriptor. */
block_ptr->NEXTBLOCK = td_ptr->MEMORY_RESOURCE_LIST;
td_ptr->MEMORY_RESOURCE_LIST = (pointer) (&block_ptr->USER_AREA);
block_ptr->MEM_POOL_PTR = (pointer) mem_pool_ptr;
#if MQX_CHECK_VALIDITY
/* Check that user area is aligned on a cache line boundary */
if (!_MEMORY_ALIGNED(&block_ptr->USER_AREA)) {
*error_ptr = MQX_INVALID_CONFIGURATION;
return ((pointer) NULL);
} /* Endif */
#endif
return ((pointer) (&block_ptr->USER_AREA));
}
else {
block_ptr = (STOREBLOCK_STRUCT_PTR) NEXT_FREE(block_ptr);
}
}
#ifdef lint
return( NULL ); /* to satisfy lint */
#endif
}
#if MQX_ALLOC_ALLIGN_RESIZE
/*!
* \private
*
* \brief Allocate an aligned block of memory for a task from the free list.
*
* \param[in] requested_size Size of the memory block.
* \param[in] req_align Requested alignment.
* \param[in] td_ptr Owner TD.
* \param[in] mem_pool_ptr Which pool to allocate from.
* \param[out] error_ptr Error code for operation:
* \li MQX_OK
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \return Pointer to the memory block (success)
* \return NULL (Failure: see task error codes.)
* \return (pointer) NULL (Failure: see task error codes.)
*/
pointer _mem_alloc_internal_align
(
_mem_size requested_size,
_mem_size req_align,
TD_STRUCT_PTR td_ptr,
MEMPOOL_STRUCT_PTR mem_pool_ptr,
_mqx_uint_ptr error_ptr
)
{ /* Body */
STOREBLOCK_STRUCT_PTR block_ptr, old_block_ptr;
STOREBLOCK_STRUCT_PTR next_block_ptr;
STOREBLOCK_STRUCT_PTR next_next_block_ptr;
_mem_size block_size;
_mem_size next_block_size;
_mem_size shift;
STOREBLOCK_STRUCT saved_block;
*error_ptr = MQX_OK;
/*
* Adjust message size to allow for block management overhead
* and force size to be aligned.
*/
requested_size += (_mem_size)(FIELD_OFFSET(STOREBLOCK_STRUCT,USER_AREA));
#if MQX_CHECK_ERRORS
if (requested_size < MQX_MIN_MEMORY_STORAGE_SIZE) {
requested_size = MQX_MIN_MEMORY_STORAGE_SIZE;
} /* Endif */
/* Check if reg_align is power of 2 */
if ((req_align != 0) && (req_align & (req_align - 1))) {
*error_ptr = MQX_INVALID_PARAMETER;
return (NULL); /* request failed */
} /* Endif */
/* If aligment is less than PSP_MEMORY_ALIGNMENT correction is needed. */
if (req_align <= PSP_MEMORY_ALIGNMENT) {
req_align = (PSP_MEMORY_ALIGNMENT + 1);
} /* Endif */
#endif
_MEMORY_ALIGN_VAL_LARGER(requested_size);
block_ptr = mem_pool_ptr->POOL_FREE_LIST_PTR;
while ( TRUE ) {
/*
* Save the current block pointer.
* We will be enabling access to higher priority tasks.
* A higher priority task may pre-empt the current task
* and may do a memory allocation. If this is true,
* the higher priority task will reset the POOL_ALLOC_CURRENT_BLOCK
* upon exit, and the current task will start the search over
* again.
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = block_ptr;
/* allow pending interrupts */
_int_enable();
_int_disable();
/* Get block pointer in case reset by a higher priority task */
block_ptr = mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK;
if (block_ptr == NULL) { /* Null pointer */
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_OUT_OF_MEMORY;
return( NULL ); /* request failed */
} /* Endif */
#if MQX_CHECK_VALIDITY
if ( !_MEMORY_ALIGNED(block_ptr) || BLOCK_IS_USED(block_ptr) ) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_CORRUPT_STORAGE_POOL_FREE_LIST;
return((pointer)NULL);
} /* Endif */
#endif
#if MQX_CHECK_VALIDITY
if ( ! VALID_CHECKSUM(block_ptr) ) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_INVALID_CHECKSUM;
return((pointer)NULL);
} /* Endif */
#endif
block_size = block_ptr->BLOCKSIZE;
shift = (((_mem_size)&block_ptr->USER_AREA + req_align) & ~(req_align - 1)) - (_mem_size)&block_ptr->USER_AREA;
if (block_size >= requested_size + shift) {
old_block_ptr = block_ptr;
if (shift) {
_mem_copy(block_ptr, &saved_block, sizeof(STOREBLOCK_STRUCT));
/* move block by shift*/
(char _PTR_)block_ptr += shift;
_mem_copy(&saved_block, block_ptr, sizeof(STOREBLOCK_STRUCT));
block_ptr->BLOCKSIZE -= shift;
CALC_CHECKSUM(block_ptr);
/*PREV_PHYS(block_ptr)->NEXTBLOCK = &block_ptr->USER_AREA;*/
PREV_PHYS(block_ptr)->BLOCKSIZE += shift;
CALC_CHECKSUM(PREV_PHYS(block_ptr));
block_size = block_ptr->BLOCKSIZE;
}
#if MQX_CHECK_VALIDITY
/* Check that user area is aligned on a cache line boundary */
if ( !_MEMORY_ALIGNED(&block_ptr->USER_AREA) ) {
*error_ptr = MQX_INVALID_CONFIGURATION;
return((pointer)NULL);
} /* Endif */
#endif
/* request fits into this block */
next_block_size = block_size - requested_size;
if ( next_block_size >= (2 * MQX_MIN_MEMORY_STORAGE_SIZE) ) {
/*
* The current block is big enough to split.
* into 2 blocks.... the part to be allocated is one block,
* and the rest remains as a free block on the free list.
*/
next_block_ptr = (STOREBLOCK_STRUCT_PTR)
((char _PTR_)block_ptr + requested_size);
/* Initialize the new physical block values */
next_block_ptr->BLOCKSIZE = next_block_size;
next_block_ptr->PREVBLOCK = (STOREBLOCK_STRUCT_PTR)block_ptr;
MARK_BLOCK_AS_FREE(next_block_ptr);
CALC_CHECKSUM(next_block_ptr);
/* Link new block into the free list */
next_block_ptr->NEXTBLOCK = block_ptr->NEXTBLOCK;
block_ptr->NEXTBLOCK = (pointer)next_block_ptr;
next_block_ptr->USER_AREA = (pointer)free_block_ptr;
if ( next_block_ptr->NEXTBLOCK != NULL ) {
((STOREBLOCK_STRUCT_PTR)next_block_ptr->NEXTBLOCK)->
USER_AREA = (pointer)next_block_ptr;
} /* Endif */
/*
* Modify the current block, to point to this newly created
* block which is now the next physical block.
*/
block_ptr->BLOCKSIZE = requested_size;
/*
* Modify the block on the other side of the next block
* (the next next block) so that it's previous block pointer
* correctly point to the next block.
*/
next_next_block_ptr = (STOREBLOCK_STRUCT_PTR)
NEXT_PHYS(next_block_ptr);
PREV_PHYS(next_next_block_ptr) = next_block_ptr;
CALC_CHECKSUM(next_next_block_ptr);
}
else {
/* Take the entire block */
requested_size = block_size;
} /* Endif */
/* Set the size of the block */
block_ptr->BLOCKSIZE = requested_size;
block_ptr->MEM_TYPE = 0;
/* Indicate the block is in use */
MARK_BLOCK_AS_USED(block_ptr, td_ptr->TASK_ID);
CALC_CHECKSUM(block_ptr);
/* Unlink the block from the free list */
if (old_block_ptr == mem_pool_ptr->POOL_FREE_LIST_PTR ) {
/* At the head of the free list */
mem_pool_ptr->POOL_FREE_LIST_PTR = (STOREBLOCK_STRUCT_PTR)NEXT_FREE(block_ptr);
if (mem_pool_ptr->POOL_FREE_LIST_PTR != NULL ) {
PREV_FREE(mem_pool_ptr->POOL_FREE_LIST_PTR) = 0;
} /* Endif */
}
else {
/*
* NOTE: PREV_FREE guaranteed to be non-zero
* Have to make the PREV_FREE of this block
* point to the NEXT_FREE of this block
*/
NEXT_FREE(PREV_FREE(block_ptr)) = NEXT_FREE(block_ptr);
if ( NEXT_FREE(block_ptr) != NULL ) {
/*
* Now have to make the NEXT_FREE of this block
* point to the PREV_FREE of this block
*/
PREV_FREE(NEXT_FREE(block_ptr)) = PREV_FREE(block_ptr);
} /* Endif */
} /* Endif */
#if MQX_MEMORY_FREE_LIST_SORTED == 1
if (old_block_ptr == mem_pool_ptr->POOL_FREE_CURRENT_BLOCK ) {
/* Reset the freelist insertion sort by _mem_free */
mem_pool_ptr->POOL_FREE_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
} /* Endif */
#endif
/* Reset the __mem_test freelist pointer */
mem_pool_ptr->POOL_FREE_CHECK_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
/*
* Set the curent pool block to the start of the free list, so
* that if this task pre-empted another that was performing a
* _mem_alloc, the other task will restart it's search for a block
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = mem_pool_ptr->POOL_FREE_LIST_PTR;
/* Remember some statistics */
next_block_ptr = NEXT_PHYS(block_ptr);
if (((char _PTR_)(next_block_ptr) > (char _PTR_) mem_pool_ptr->POOL_HIGHEST_MEMORY_USED) &&
((char _PTR_)(next_block_ptr) > (char _PTR_) mem_pool_ptr->POOL_PTR) &&
((char _PTR_)(next_block_ptr) < (char _PTR_) mem_pool_ptr->POOL_END_PTR)
)
{
mem_pool_ptr->POOL_HIGHEST_MEMORY_USED = ((char _PTR_)(next_block_ptr) - 1);
} /* Endif */
/* Link the block onto the task descriptor. */
block_ptr->NEXTBLOCK = td_ptr->MEMORY_RESOURCE_LIST;
td_ptr->MEMORY_RESOURCE_LIST = (pointer)(&block_ptr->USER_AREA);
block_ptr->MEM_POOL_PTR = (pointer)mem_pool_ptr;
return( (pointer)(&block_ptr->USER_AREA ) );
}
else {
block_ptr = (STOREBLOCK_STRUCT_PTR)NEXT_FREE(block_ptr);
} /* Endif */
} /* Endwhile */
#ifdef lint
return( NULL ); /* to satisfy lint */
#endif
} /* Endbody */
#else
/*!
* \private
*
* \brief Allocate an aligned block of memory for a task from the free list.
*
* \param[in] requested_size Size of the memory block.
* \param[in] req_align Requested alignment.
* \param[in] td_ptr Owner TD.
* \param[in] mem_pool_ptr Which pool to allocate from.
* \param[out] error_ptr Error code for operation:
* \li MQX_OK
* \li MQX_OUT_OF_MEMORY (MQX cannot find a block of the requested size.)
* \li MQX_CORRUPT_STORAGE_POOL_FREE_LIST (Memory pool freelist is corrupted.)
* \li MQX_INVALID_CHECKSUM (Checksum of the current memory block header is
* incorrect.)
* \li MQX_INVALID_CONFIGURATION (User area not aligned on a cache line
* boundary.)
*
* \return Pointer to the memory block (success)
* \return NULL (Failure: see task error codes.)
* \return (pointer) NULL (Failure: see task error codes.)
*/
pointer _mem_alloc_internal_align
(
_mem_size requested_size,
_mem_size req_align,
TD_STRUCT_PTR td_ptr,
MEMPOOL_STRUCT_PTR mem_pool_ptr,
_mqx_uint_ptr error_ptr
)
{ /* Body */
STOREBLOCK_STRUCT_PTR block_ptr, free_block_ptr;
STOREBLOCK_STRUCT_PTR next_block_ptr = NULL;
STOREBLOCK_STRUCT_PTR next_next_block_ptr;
_mem_size block_size;
_mem_size next_block_size;
_mem_size shift;
*error_ptr = MQX_OK;
/*
* Adjust message size to allow for block management overhead
* and force size to be aligned.
*/
requested_size += (_mem_size) (FIELD_OFFSET(STOREBLOCK_STRUCT,USER_AREA));
#if MQX_CHECK_ERRORS
if (requested_size < MQX_MIN_MEMORY_STORAGE_SIZE) {
requested_size = MQX_MIN_MEMORY_STORAGE_SIZE;
} /* Endif */
/* Check if reg_align is power of 2 */
if ((req_align != 0) && (req_align & (req_align - 1))) {
*error_ptr = MQX_INVALID_PARAMETER;
return (NULL); /* request failed */
} /* Endif */
/* If aligment is less than PSP_MEMORY_ALIGNMENT correction is needed. */
if (req_align <= PSP_MEMORY_ALIGNMENT) {
req_align = (PSP_MEMORY_ALIGNMENT + 1);
} /* Endif */
#endif
_MEMORY_ALIGN_VAL_LARGER(requested_size);
block_ptr = mem_pool_ptr->POOL_FREE_LIST_PTR;
while (TRUE) {
/*
* Save the current block pointer.
* We will be enabling access to higher priority tasks.
* A higher priority task may pre-empt the current task
* and may do a memory allocation. If this is true,
* the higher priority task will reset the POOL_ALLOC_CURRENT_BLOCK
* upon exit, and the current task will start the search over
* again.
*/
mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK = block_ptr;
/* allow pending interrupts */
_int_enable();
_int_disable();
/* Get block pointer in case reset by a higher priority task */
block_ptr = mem_pool_ptr->POOL_ALLOC_CURRENT_BLOCK;
if (block_ptr == NULL) { /* Null pointer */
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_OUT_OF_MEMORY;
return (NULL); /* request failed */
} /* Endif */
#if MQX_CHECK_VALIDITY
if (!_MEMORY_ALIGNED(block_ptr) || BLOCK_IS_USED(block_ptr)) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_CORRUPT_STORAGE_POOL_FREE_LIST;
return ((pointer) NULL);
}
if (!VALID_CHECKSUM(block_ptr)) {
mem_pool_ptr->POOL_BLOCK_IN_ERROR = block_ptr;
*error_ptr = MQX_INVALID_CHECKSUM;
return ((pointer) NULL);
}
#endif
block_size = block_ptr->BLOCKSIZE;
shift = (((_mem_size) &block_ptr->USER_AREA + req_align) & ~(req_align - 1))
- (_mem_size) &block_ptr->USER_AREA;
if (shift < (2 * MQX_MIN_MEMORY_STORAGE_SIZE)) {
shift = (((_mem_size) &block_ptr->USER_AREA + (3 * MQX_MIN_MEMORY_STORAGE_SIZE) + req_align) & ~(req_align
- 1)) - (_mem_size) &block_ptr->USER_AREA;
}
if (block_size >= requested_size + shift) {
/* request fits into this block */
/* create new free block */
free_block_ptr = (STOREBLOCK_STRUCT_PTR)((char _PTR_) block_ptr);
block_ptr = (STOREBLOCK_STRUCT_PTR)(((char _PTR_) block_ptr) + shift);
#if MQX_CHECK_VALIDITY
/* Assert that user area is aligned on a cache line boundary */
if (!_MEMORY_ALIGNED(&block_ptr->USER_AREA)) {
*error_ptr = MQX_INVALID_CONFIGURATION;
return ((pointer) NULL);
} /* Endif */
#endif
block_ptr->PREVBLOCK = (STOREBLOCK_STRUCT_PTR) free_block_ptr;
next_block_size = block_size - requested_size - shift;
if (next_block_size >= (2 * MQX_MIN_MEMORY_STORAGE_SIZE)) {
/*
* The current block is big enough to split.
* into 2 blocks.... the part to be allocated is one block,
* and the rest remains as a free block on the free list.
*/
next_block_ptr = (STOREBLOCK_STRUCT_PTR)((char _PTR_) block_ptr + requested_size);
/* Initialize the new physical block values */
next_block_ptr->BLOCKSIZE = next_block_size;
next_block_ptr->PREVBLOCK = (STOREBLOCK_STRUCT_PTR) block_ptr;
MARK_BLOCK_AS_FREE(next_block_ptr);
CALC_CHECKSUM(next_block_ptr);
/* Link new block into the free list */
next_block_ptr->NEXTBLOCK = free_block_ptr->NEXTBLOCK;
block_ptr->NEXTBLOCK = (pointer) next_block_ptr;
next_block_ptr->USER_AREA = (pointer) free_block_ptr;
if (next_block_ptr->NEXTBLOCK != NULL) {
((STOREBLOCK_STRUCT_PTR) next_block_ptr->NEXTBLOCK)->USER_AREA = (pointer) next_block_ptr;
}
/*
* Modify the current block, to point to this newly created
* block which is now the next physical block.
*/
block_ptr->BLOCKSIZE = requested_size;
/*
* Modify the block on the other side of the next block
* (the next next block) so that it's previous block pointer
* correctly point to the next block.
*/
next_next_block_ptr = (STOREBLOCK_STRUCT_PTR) NEXT_PHYS(next_block_ptr);
PREV_PHYS( next_next_block_ptr) = next_block_ptr;
CALC_CHECKSUM(next_next_block_ptr);
}
else {
/* Take the entire block */
requested_size = next_block_size;
} /* Endif */
/* modify the new physical block values */
free_block_ptr->BLOCKSIZE = shift;
free_block_ptr->NEXTBLOCK = (pointer) next_block_ptr;
MARK_BLOCK_AS_FREE(free_block_ptr);
CALC_CHECKSUM(free_block_ptr);
/* Set the size of the block */
block_ptr->BLOCKSIZE = requested_size;
block_ptr->PREVBLOCK = (STOREBLOCK_STRUCT_PTR) free_block_ptr;
block_ptr->MEM_TYPE = 0;
MARK_BLOCK_AS_USED(block_ptr, td_ptr->TASK_ID);
CALC_CHECKSUM(block_ptr);
/* Remember some statistics */
next_block_ptr = NEXT_PHYS(block_ptr);
if (((char _PTR_)(next_block_ptr) > (char _PTR_) mem_pool_ptr->POOL_HIGHEST_MEMORY_USED) &&
((char _PTR_)(next_block_ptr) > (char _PTR_) mem_pool_ptr->POOL_PTR) &&
((char _PTR_)(next_block_ptr) < (char _PTR_) mem_pool_ptr->POOL_END_PTR)
)
{
mem_pool_ptr->POOL_HIGHEST_MEMORY_USED = ((char _PTR_)(next_block_ptr) - 1);
} /* Endif */
/* Link the block onto the task descriptor. */
block_ptr->NEXTBLOCK = td_ptr->MEMORY_RESOURCE_LIST;
td_ptr->MEMORY_RESOURCE_LIST = (pointer) (&block_ptr->USER_AREA);
block_ptr->MEM_POOL_PTR = (pointer) mem_pool_ptr;
return ((pointer) (&block_ptr->USER_AREA));
}
else {
block_ptr = (STOREBLOCK_STRUCT_PTR) NEXT_FREE(block_ptr);
}
}
#ifdef lint
return( NULL ); /* to satisfy lint */
#endif
}
#endif /* MQX_ALLOC_ALLIGN_RESIZE */
#endif /* MQX_USE_MEM */
#if MQX_USE_MEM || MQX_USE_LWMEM
/*!
* \brief Converts data to the other endian format.
*
* Converts data from Big to Little Endian byte order (or vice versa). The size
* of the fields in the data are defined by the null terminated array of 8-bit
* numbers.
*
* \param[in] definition Pointer to a NULL-terminated array, each element of
* which defines the size (in single-addressable units) of each field in the
* data structure that defines the data to convert.
* \param[in] data Pointer to the data to convert.
*
* \see _mem_swap_endian_len
* \see _msg_swap_endian_data
* \see _msg_swap_endian_header
*/
void _mem_swap_endian
(
register uchar _PTR_ definition,
pointer data
)
{ /* Body */
register uchar _PTR_ data_ptr;
register uchar _PTR_ next_ptr;
uchar _PTR_ b_ptr;
_mqx_uint i;
register _mqx_uint size;
uchar c;
data_ptr = (uchar _PTR_) data;
size = (_mqx_uint) *definition++;
while (size) {
switch (size)
{
case 0: /* For compiler optimizations */
break;
case 1: /* No need to swap */
++data_ptr;
break;
/* Cases 2 & 4 are common sizes */
case 2:
c = data_ptr[0];
data_ptr[0] = data_ptr[1];
data_ptr[1] = c;
data_ptr += 2;
break;
case 4:
c = data_ptr[0];
data_ptr[0] = data_ptr[3];
data_ptr[3] = c;
c = data_ptr[1];
data_ptr[1] = data_ptr[2];
data_ptr[2] = c;
data_ptr += 4;
break;
/* All others done long hand */
default:
next_ptr = data_ptr + size;
b_ptr = data_ptr + size - 1;
i = (size / 2) + 1;
while (--i) {
c = *data_ptr;
*data_ptr++ = *b_ptr;
*b_ptr-- = c;
} /* Endwhile */
data_ptr = next_ptr;
break;
} /* Endswitch */
size = *definition++;
} /* Endwhile */
} /* Endbody */
/*!
* \brief Converts data to the other endian format.
*
* Converts data from Big to Little Endian byte order (or vice versa). The size
* of the fields in the data are defined by the null terminated array of 8-bit
* numbers.
*
* \param[in] definition Pointer to a NULL-terminated array, each element of
* which defines the size (in single-addressable units) of each field in the
* data structure that defines the data to convert.
* \param[in] data Pointer to the data to convert.
* \param[in] len The fields in the definition array to process.
*
* \see _mem_swap_endian
* \see _msg_swap_endian_data
* \see _msg_swap_endian_header
*/
void _mem_swap_endian_len
(
register uchar _PTR_ definition,
pointer data,
_mqx_uint len
)
{ /* Body */
register uchar _PTR_ data_ptr;
register uchar _PTR_ next_ptr;
uchar _PTR_ b_ptr;
_mqx_uint i;
register _mqx_uint size;
uchar c;
data_ptr = (uchar _PTR_) data;
size = (_mqx_uint) *definition++;
while (size && len--) {
switch (size)
{
case 0: /* For compiler optimizations */
break;
case 1: /* No need to swap */
++data_ptr;
break;
/* Cases 2 & 4 are common sizes */
case 2:
c = data_ptr[0];
data_ptr[0] = data_ptr[1];
data_ptr[1] = c;
data_ptr += 2;
break;
case 4:
c = data_ptr[0];
data_ptr[0] = data_ptr[3];
data_ptr[3] = c;
c = data_ptr[1];
data_ptr[1] = data_ptr[2];
data_ptr[2] = c;
data_ptr += 4;
break;
/* All others done long hand */
default:
next_ptr = data_ptr + size;
b_ptr = data_ptr + size - 1;
i = (size / 2) + 1;
while (--i) {
c = *data_ptr;
*data_ptr++ = *b_ptr;
*b_ptr-- = c;
} /* Endwhile */
data_ptr = next_ptr;
break;
} /* Endswitch */
size = (_mqx_uint) *definition++;
} /* Endwhile */
} /* Endbody */
#endif /* MQX_USE_MEM || MQX_USE_LWMEM */
/*!
* \brief Checks whether memory can be read and written without corruption.
*
* It aligns the addresses it's given to a PSP specified value and then writes
* every 32-bit element in the memory range once with values that change every
* bit. Then it reads back the data and returns an error if the value read back
* does not equal the value written.
*
* \param[in] base
* \param[in] extent
*
* \return MQX_OK
* \return MQX_INVALID_SIZE
* \return MQX_CORRUPT_MEMORY_SYSTEM
*/
_mqx_uint _mem_verify
(
pointer base,
pointer extent
)
{ /* Body */
_mqx_uint result = MQX_INVALID_SIZE;
if (extent > base) {
uchar_ptr cbase = (uchar_ptr) _ALIGN_ADDR_TO_HIGHER_MEM(base);
uchar_ptr cextent = (uchar_ptr) _ALIGN_ADDR_TO_LOWER_MEM(extent);
if (cextent > cbase) {
uint_32 length = cextent - cbase;
uint_32_ptr p, p1 = (uint_32_ptr) cbase;
uint_32_ptr eom = (uint_32_ptr) (cbase + length);
uint_32 v = 0x12345678;
for (p = p1; p < eom; p++) {
*p = v;
v += 0x11111111;
} /* Endfor */
result = MQX_OK;
v = 0x12345678;
for (p = p1; p < eom; p++) {
if (*p != v) {
result = MQX_CORRUPT_MEMORY_SYSTEM;
break;
} /* Endif */
v += 0x11111111;
} /* Endfor */
} /* Endif */
} /* Endif */
return (result);
} /* Endbody */
/* EOF */