From f6ae2fbe1fc36d122853a7928902b81aad1bed6e Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Tue, 29 Sep 2020 09:37:30 -0400 Subject: [PATCH] Fix #651, Use resource ID for memory pools Instead of identifying a memory pool by its memory address, use a resource ID. IDs are a constant size, regardless of whether the host machine is 32 or 64 bits. - IDs can be put into commands/telemetry and maintain a more consistent format with consistent alignment requirements. - IDs can be independently verified without dereferencing memory. Previously the only way to validate a memory pool was to read the address pointed to, which results in a SEGV if the address was bad. --- cmake/sample_defs/cpu1_platform_cfg.h | 34 + fsw/cfe-core/src/es/cfe_es_apps.c | 34 + fsw/cfe-core/src/es/cfe_es_generic_pool.c | 725 +++++++++++++++++++++ fsw/cfe-core/src/es/cfe_es_generic_pool.h | 296 +++++++++ fsw/cfe-core/src/es/cfe_es_global.h | 6 + fsw/cfe-core/src/es/cfe_es_mempool.c | 691 ++++++++++++++++++++ fsw/cfe-core/src/es/cfe_es_mempool.h | 175 ++++++ fsw/cfe-core/src/es/cfe_es_task.c | 9 +- fsw/cfe-core/src/es/cfe_esmempool.c | 700 --------------------- fsw/cfe-core/src/es/cfe_esmempool.h | 78 --- fsw/cfe-core/src/inc/cfe_error.h | 31 + fsw/cfe-core/src/inc/cfe_es.h | 97 ++- fsw/cfe-core/src/sb/cfe_sb_init.c | 4 +- fsw/cfe-core/src/sb/cfe_sb_task.c | 2 +- fsw/cfe-core/src/tbl/cfe_tbl_api.c | 4 +- fsw/cfe-core/src/tbl/cfe_tbl_internal.c | 4 +- fsw/cfe-core/src/tbl/cfe_tbl_task_cmds.c | 2 +- fsw/cfe-core/unit-test/es_UT.c | 730 +++++++++++++++------- fsw/cfe-core/unit-test/es_UT.h | 3 +- fsw/cfe-core/unit-test/ut_support.h | 2 +- fsw/cfe-core/ut-stubs/ut_es_stubs.c | 58 +- 21 files changed, 2638 insertions(+), 1047 deletions(-) create mode 100644 fsw/cfe-core/src/es/cfe_es_generic_pool.c create mode 100644 fsw/cfe-core/src/es/cfe_es_generic_pool.h create mode 100644 fsw/cfe-core/src/es/cfe_es_mempool.c create mode 100644 fsw/cfe-core/src/es/cfe_es_mempool.h delete mode 100644 fsw/cfe-core/src/es/cfe_esmempool.c delete mode 100644 fsw/cfe-core/src/es/cfe_esmempool.h diff --git a/cmake/sample_defs/cpu1_platform_cfg.h b/cmake/sample_defs/cpu1_platform_cfg.h index 8e7504fd3..cb80a5824 100644 --- a/cmake/sample_defs/cpu1_platform_cfg.h +++ b/cmake/sample_defs/cpu1_platform_cfg.h @@ -1365,6 +1365,40 @@ #define CFE_PLATFORM_ES_MAX_PROCESSOR_RESETS 2 +/** \cfeescfg Maximum number of block sizes in pool structures +** +** \par Description: +** The upper limit for the number of block sizes supported in the generic +** pool implementation, which in turn implements the memory pools and CDS. +** +** \par Limits: +** Must be at least one. No specific upper limit, but the number is +** anticipated to be reasonably small (i.e. tens, not hundreds). Large +** values have not been tested. +** +** The ES and CDS block size lists must correlate with this value + */ +#define CFE_PLATFORM_ES_POOL_MAX_BUCKETS 17 + +/** \cfeescfg Maximum number of memory pools +** +** \par Description: +** The upper limit for the number of memory pools than can concurrently +** exist within the system. +** +** The CFE_SB and CFE_TBL core subsystems each define a memory pool. +** +** Individual applications may also create memory pools, so this value +** should be set sufficiently high enough to support the applications +** being used on this platform. +** +** \par Limits: +** Must be at least 2 to support CFE core - SB and TBL pools. No +** specific upper limit. + */ +#define CFE_PLATFORM_ES_MAX_MEMORY_POOLS 10 + + /** ** \cfeescfg Define Default ES Memory Pool Block Sizes ** diff --git a/fsw/cfe-core/src/es/cfe_es_apps.c b/fsw/cfe-core/src/es/cfe_es_apps.c index 8eb008b10..a4c877ebe 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.c +++ b/fsw/cfe-core/src/es/cfe_es_apps.c @@ -1088,6 +1088,8 @@ int32 CFE_ES_CleanUpApp(CFE_ES_AppRecord_t *AppRecPtr) CFE_ES_ResourceID_t CurrTaskId; int32 ReturnCode = CFE_SUCCESS; CFE_ES_TaskRecord_t *TaskRecPtr; + CFE_ES_MemPoolRecord_t *MemPoolRecPtr; + CFE_ES_MemHandle_t PoolId; CFE_ES_ResourceID_t AppId; /* @@ -1191,6 +1193,38 @@ int32 CFE_ES_CleanUpApp(CFE_ES_AppRecord_t *AppRecPtr) CFE_ES_AppRecordSetFree(AppRecPtr); + /* + ** Delete any memory pools associated with this app + */ + MemPoolRecPtr = CFE_ES_Global.MemPoolTable; + for ( i = 0; i < CFE_PLATFORM_ES_MAX_MEMORY_POOLS; i++ ) + { + if ( CFE_ES_MemPoolRecordIsUsed(MemPoolRecPtr) && + CFE_ES_ResourceID_Equal(MemPoolRecPtr->OwnerAppID, AppId)) + { + PoolId = CFE_ES_MemPoolRecordGetID(MemPoolRecPtr); + + /* + * This needs to release the lock first because + * CFE_ES_PoolDelete acquires the lock. + */ + CFE_ES_UnlockSharedData(__func__, __LINE__); + Status = CFE_ES_PoolDelete(PoolId); + CFE_ES_LockSharedData(__func__, __LINE__); + + if ( Status != CFE_SUCCESS ) + { + CFE_ES_SysLogWrite_Unsync("CFE_ES_MemPoolCleanupApp: delete pool %lu returned Error: 0x%08X\n", + CFE_ES_ResourceID_ToInteger(PoolId), (unsigned int)Status); + ReturnCode = CFE_ES_APP_CLEANUP_ERR; + } + } + + ++MemPoolRecPtr; + } /* end for */ + + + CFE_ES_UnlockSharedData(__func__,__LINE__); return(ReturnCode); diff --git a/fsw/cfe-core/src/es/cfe_es_generic_pool.c b/fsw/cfe-core/src/es/cfe_es_generic_pool.c new file mode 100644 index 000000000..cbf451cbf --- /dev/null +++ b/fsw/cfe-core/src/es/cfe_es_generic_pool.c @@ -0,0 +1,725 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/* +** File: +** cfe_es_generic_pool.c +** +** Purpose: +** Set of services for management of discrete sized memory pools. +** +** References: +** Flight Software Branch C Coding Standard Version 1.0a +** cFE Flight Software Application Developers Guide +** +*/ + +/* +** Includes +*/ +#include +#include +#include + +#include "common_types.h" +#include "osapi.h" +#include "cfe_es.h" +#include "cfe_es_generic_pool.h" +#include "cfe_es_global.h" +#include "cfe_platform_cfg.h" + + +/*****************************************************************************/ +/* +** Functions +*/ + + + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolFindBucket +** +** Local Helper function to find the appropriate bucket given a requested block size +**--------------------------------------------------------------------------------------- +*/ +uint16 CFE_ES_GenPoolFindBucket(CFE_ES_GenPoolRecord_t *PoolRecPtr, CFE_ES_MemOffset_t ReqSize) +{ + uint16 Index; + + for (Index=0; Index < PoolRecPtr->NumBuckets; ++Index) + { + if (ReqSize <= PoolRecPtr->Buckets[Index].BlockSize) + { + /* it fits - stop here */ + break; + } + } + + /* + * Invert output such that if a bucket wasn't found, this + * will return 0. A valid bucket ID will be nonzero. + */ + return (PoolRecPtr->NumBuckets - Index); +} + + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolGetBucketState +** +** Local Helper function to obtain the structure associated with a given bucket ID. +**--------------------------------------------------------------------------------------- +*/ +CFE_ES_GenPoolBucket_t *CFE_ES_GenPoolGetBucketState(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 BucketId) +{ + uint16 Index; + + Index = PoolRecPtr->NumBuckets - BucketId; + if (Index >= PoolRecPtr->NumBuckets) + { + return NULL; + } + + return &PoolRecPtr->Buckets[Index]; +} + + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolRecyclePoolBlock +** +** Local helper function to find and re-allocate a previously returned block +**--------------------------------------------------------------------------------------- +*/ +int32 CFE_ES_GenPoolRecyclePoolBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 BucketId, + CFE_ES_MemOffset_t NewSize, CFE_ES_MemOffset_t *BlockOffsetPtr) +{ + CFE_ES_GenPoolBucket_t *BucketPtr; + CFE_ES_MemOffset_t DescOffset; + CFE_ES_MemOffset_t BlockOffset; + CFE_ES_MemOffset_t NextOffset; + CFE_ES_GenPoolBD_t *BdPtr; + uint16 RecycleBucketId; + int32 Status; + + BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId); + if (BucketPtr == NULL || + BucketPtr->RecycleCount == BucketPtr->ReleaseCount || + BucketPtr->FirstOffset == 0) + { + /* no buffers in pool to recycle */ + return CFE_ES_BUFFER_NOT_IN_POOL; + } + + BlockOffset = BucketPtr->FirstOffset; + DescOffset = BlockOffset - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE; + Status = PoolRecPtr->Retrieve(PoolRecPtr, DescOffset, &BdPtr); + if (Status == CFE_SUCCESS) + { + RecycleBucketId = BdPtr->Allocated - CFE_ES_MEMORY_DEALLOCATED; + if (BdPtr->CheckBits != CFE_ES_CHECK_PATTERN || + RecycleBucketId != BucketId) + { + /* sanity check failed - possible pool corruption? */ + Status = CFE_ES_BUFFER_NOT_IN_POOL; + } + else + { + /* + * Get it off the top on the list + */ + NextOffset = BdPtr->NextOffset; + + BdPtr->Allocated = CFE_ES_MEMORY_ALLOCATED + BucketId; /* Flag memory block as allocated */ + BdPtr->ActualSize = NewSize; + BdPtr->NextOffset = 0; + + Status = PoolRecPtr->Commit(PoolRecPtr, DescOffset, BdPtr); + if (Status == CFE_SUCCESS) + { + *BlockOffsetPtr = BlockOffset; + BucketPtr->FirstOffset = NextOffset; + ++BucketPtr->RecycleCount; + } + } + } + + return Status; +} + + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolCreatePoolBlock +** +** Local helper function to create a new block of the given size +**--------------------------------------------------------------------------------------- +*/ +int32 CFE_ES_GenPoolCreatePoolBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 BucketId, + CFE_ES_MemOffset_t NewSize, CFE_ES_MemOffset_t *BlockOffsetPtr) +{ + CFE_ES_GenPoolBucket_t *BucketPtr; + CFE_ES_MemOffset_t DescOffset; + CFE_ES_MemOffset_t BlockOffset; + CFE_ES_MemOffset_t NextTailPosition; + CFE_ES_GenPoolBD_t *BdPtr; + int32 Status; + + BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId); + if (BucketPtr == NULL) + { + /* no buffers in pool to create */ + return CFE_ES_BUFFER_NOT_IN_POOL; + } + + /* + * Determine the offsets of the new user block, + * which must be aligned according to the AlignMask member. + * + * Note - just pre-calculating offsets here, nothing is committed yet. + */ + BlockOffset = PoolRecPtr->TailPosition + CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE; + BlockOffset += PoolRecPtr->AlignMask; + BlockOffset &= ~PoolRecPtr->AlignMask; + + DescOffset = BlockOffset - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE; + NextTailPosition = BlockOffset + BucketPtr->BlockSize; + + /* + * Check if there is enough space remaining in the pool -- the + * proposed start address plus the block size must not exceed the pool end. + */ + if ( NextTailPosition > PoolRecPtr->PoolMaxOffset ) + { + /* can't fit in remaining mem */ + return CFE_ES_ERR_MEM_BLOCK_SIZE; + } + + /* + * Now commit the new block + */ + Status = PoolRecPtr->Retrieve(PoolRecPtr, DescOffset, &BdPtr); + if (Status == CFE_SUCCESS) + { + BdPtr->CheckBits = CFE_ES_CHECK_PATTERN; + BdPtr->Allocated = CFE_ES_MEMORY_ALLOCATED + BucketId; /* Flag memory block as allocated */ + BdPtr->ActualSize = NewSize; + BdPtr->NextOffset = 0; + + Status = PoolRecPtr->Commit(PoolRecPtr, DescOffset, BdPtr); + if (Status == CFE_SUCCESS) + { + /* + ** adjust pool current pointer and other record keeping + */ + PoolRecPtr->TailPosition = NextTailPosition; + ++BucketPtr->AllocationCount; + ++PoolRecPtr->AllocationCount; + + *BlockOffsetPtr = BlockOffset; + } + + } + + return Status; +} + + + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolInitialize +** +** ES Internal API - See Prototype for full API description +**--------------------------------------------------------------------------------------- +*/ +int32 CFE_ES_GenPoolInitialize( + CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t StartOffset, + CFE_ES_MemOffset_t PoolSize, + CFE_ES_MemOffset_t AlignSize, + uint16 NumBlockSizes, + const CFE_ES_MemOffset_t *BlockSizeList, + CFE_ES_PoolRetrieve_Func_t RetrieveFunc, + CFE_ES_PoolCommit_Func_t CommitFunc) +{ + cpuaddr AlignMask; + uint32 i; + uint32 j; + CFE_ES_GenPoolBucket_t *BucketPtr; + + /* + * Note - being an internal/non-public API this does not need to + * check the directly-supplied arguments, it is assumed they are already + * sanity checked. + */ + memset(PoolRecPtr, 0, sizeof(*PoolRecPtr)); + + /* + * Convert alignment to a bit mask. + * This sets all LSBs if the passed in value was not actually a power of 2. + */ + if (AlignSize <= 1) + { + AlignMask = 0; + } + else + { + AlignMask = AlignSize - 1; + AlignMask |= AlignMask >> 1; + AlignMask |= AlignMask >> 2; + AlignMask |= AlignMask >> 4; + AlignMask |= AlignMask >> 8; + AlignMask |= AlignMask >> 16; + } + + /* complete initialization of pool record entry */ + PoolRecPtr->AlignMask = AlignMask; + PoolRecPtr->PoolTotalSize = PoolSize; + PoolRecPtr->PoolMaxOffset = PoolSize + StartOffset; + PoolRecPtr->NumBuckets = NumBlockSizes; + PoolRecPtr->Retrieve = RetrieveFunc; + PoolRecPtr->Commit = CommitFunc; + PoolRecPtr->TailPosition = StartOffset; + + /* initially copy all block sizes */ + BucketPtr = PoolRecPtr->Buckets; + for (i=0; i < NumBlockSizes; ++i) + { + BucketPtr->BlockSize = BlockSizeList[i]; + ++BucketPtr; + } + + /* Sort by block size - a simple bubble sort - + * this does not run often and the list is relatively small. */ + do + { + j = 0; + BucketPtr = PoolRecPtr->Buckets; + for (i=1; i < NumBlockSizes; ++i) + { + if (BucketPtr[0].BlockSize > BucketPtr[1].BlockSize) + { + /* swap */ + BucketPtr[0].BlockSize ^= BucketPtr[1].BlockSize; + BucketPtr[1].BlockSize ^= BucketPtr[0].BlockSize; + BucketPtr[0].BlockSize ^= BucketPtr[1].BlockSize; + ++j; + } + ++BucketPtr; + } + } + while (j > 0); + + /* + * Additional sanity check - after sorting the list, + * confirm that the smallest block size (first entry) + * is not zero. + */ + if (PoolRecPtr->Buckets[0].BlockSize == 0) + { + return CFE_ES_ERR_MEM_BLOCK_SIZE; + } + + + return CFE_SUCCESS; +} + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolCalcMinSize +** +** ES Internal API - See Prototype for full API description +**--------------------------------------------------------------------------------------- +*/ +CFE_ES_MemOffset_t CFE_ES_GenPoolCalcMinSize(uint16 NumBlockSizes, + const CFE_ES_MemOffset_t *BlockSizeList, + uint32 NumBlocks) +{ + uint16 BucketId; + CFE_ES_MemOffset_t MinBlockSize; + + MinBlockSize = 0; + + if (NumBlockSizes > 0) + { + MinBlockSize = BlockSizeList[0]; + for (BucketId = 1; BucketId < NumBlockSizes; ++BucketId) + { + if (BlockSizeList[BucketId] < MinBlockSize) + { + MinBlockSize = BlockSizeList[BucketId]; + } + } + } + + MinBlockSize += sizeof(CFE_ES_GenPoolBD_t); + + return (NumBlocks * MinBlockSize); +} + + + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolGetBlock +** +** ES Internal API - See Prototype for full API description +**--------------------------------------------------------------------------------------- +*/ +int32 CFE_ES_GenPoolGetBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t *BlockOffsetPtr, + CFE_ES_MemOffset_t ReqSize ) +{ + int32 Status; + uint16 BucketId; + + /* Find the bucket which can accommodate the requested size. */ + BucketId = CFE_ES_GenPoolFindBucket(PoolRecPtr, ReqSize); + if (BucketId == 0) + { + CFE_ES_WriteToSysLog("CFE_ES:getPoolBlock err:size(%lu) > max(%lu).\n", + (unsigned long)ReqSize, + (unsigned long)PoolRecPtr->Buckets[PoolRecPtr->NumBuckets-1].BlockSize); + return(CFE_ES_ERR_MEM_BLOCK_SIZE); + } + + /* first attempt to recycle any buffers from the same bucket that were freed */ + Status = CFE_ES_GenPoolRecyclePoolBlock(PoolRecPtr, BucketId, ReqSize, BlockOffsetPtr); + if (Status != CFE_SUCCESS) + { + /* recycling not available - try making a new one instead */ + Status = CFE_ES_GenPoolCreatePoolBlock(PoolRecPtr, BucketId, ReqSize, BlockOffsetPtr); + } + + return(Status); +} + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolGetBlockSize +** +** ES Internal API - See Prototype for full API description +**--------------------------------------------------------------------------------------- +*/ +int32 CFE_ES_GenPoolGetBlockSize(CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t *BlockSizePtr, + CFE_ES_MemOffset_t BlockOffset) +{ + CFE_ES_MemOffset_t DescOffset; + CFE_ES_GenPoolBucket_t *BucketPtr; + CFE_ES_GenPoolBD_t *BdPtr; + int32 Status; + uint16 BucketId; + + if (BlockOffset >= PoolRecPtr->TailPosition || BlockOffset < CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE) + { + /* outside the bounds of the pool */ + return CFE_ES_BUFFER_NOT_IN_POOL; + } + + DescOffset = BlockOffset - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE; + + Status = PoolRecPtr->Retrieve(PoolRecPtr, DescOffset, &BdPtr); + if (Status == CFE_SUCCESS) + { + BucketId = BdPtr->Allocated - CFE_ES_MEMORY_ALLOCATED; + BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId); + + if (BdPtr->CheckBits != CFE_ES_CHECK_PATTERN || + BucketPtr == NULL || + BdPtr->ActualSize == 0 || + BucketPtr->BlockSize < BdPtr->ActualSize) + { + /* This does not appear to be a valid data buffer */ + Status = CFE_ES_POOL_BLOCK_INVALID; + } + else + { + *BlockSizePtr = BdPtr->ActualSize; + Status = CFE_SUCCESS; + } + } + + return Status; +} + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolPutBlock +** +** ES Internal API - See Prototype for full API description +**--------------------------------------------------------------------------------------- +*/ +int32 CFE_ES_GenPoolPutBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t *BlockSizePtr, + CFE_ES_MemOffset_t BlockOffset) +{ + CFE_ES_MemOffset_t DescOffset; + CFE_ES_GenPoolBucket_t *BucketPtr; + CFE_ES_GenPoolBD_t *BdPtr; + int32 Status; + uint16 BucketId; + + if (BlockOffset >= PoolRecPtr->TailPosition || BlockOffset < CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE) + { + /* outside the bounds of the pool */ + return CFE_ES_BUFFER_NOT_IN_POOL; + } + + DescOffset = BlockOffset - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE; + + Status = PoolRecPtr->Retrieve(PoolRecPtr, DescOffset, &BdPtr); + if (Status == CFE_SUCCESS) + { + BucketId = BdPtr->Allocated - CFE_ES_MEMORY_ALLOCATED; + BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId); + + if (BdPtr->CheckBits != CFE_ES_CHECK_PATTERN || + BucketPtr == NULL || + BdPtr->ActualSize == 0 || + BucketPtr->BlockSize < BdPtr->ActualSize) + { + /* This does not appear to be a valid data buffer */ + ++PoolRecPtr->ValidationErrorCount; + Status = CFE_ES_POOL_BLOCK_INVALID; + } + else + { + BdPtr->Allocated = CFE_ES_MEMORY_DEALLOCATED + BucketId; + BdPtr->NextOffset = BucketPtr->FirstOffset; + *BlockSizePtr = BdPtr->ActualSize; + + Status = PoolRecPtr->Commit(PoolRecPtr, DescOffset, BdPtr); + if (Status == CFE_SUCCESS) + { + BucketPtr->FirstOffset = BlockOffset; + ++BucketPtr->ReleaseCount; + } + } + } + + return Status; +} + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolRebuild +** +** ES Internal API - See Prototype for full API description +**--------------------------------------------------------------------------------------- +*/ +int32 CFE_ES_GenPoolRebuild(CFE_ES_GenPoolRecord_t *PoolRecPtr) +{ + int32 Status; + CFE_ES_MemOffset_t DescOffset; + CFE_ES_MemOffset_t BlockOffset; + CFE_ES_GenPoolBucket_t *BucketPtr; + CFE_ES_GenPoolBD_t *BdPtr; + uint16 BucketId; + bool IsDeallocatedBlock; + + Status = CFE_SUCCESS; + + /* Scan the pool to find blocks that were created and freed */ + while (true) + { + IsDeallocatedBlock = false; + BucketId = 0; + BucketPtr = NULL; + + /* + * Determine the offsets of the next user block, + * which must be aligned according to the AlignMask member. + */ + BlockOffset = PoolRecPtr->TailPosition + CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE; + BlockOffset += PoolRecPtr->AlignMask; + BlockOffset &= ~PoolRecPtr->AlignMask; + + if (BlockOffset > PoolRecPtr->PoolMaxOffset) + { + /* End of pool reached, stop now */ + break; + } + + DescOffset = BlockOffset - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE; + Status = PoolRecPtr->Retrieve(PoolRecPtr, DescOffset, &BdPtr); + if (Status != CFE_SUCCESS) + { + /* Failed to read descriptor */ + break; + } + + /* + * If the CheckBits indicate the block was in use, + * then do further inspection to find the block size + * and allocated/deallocated status. + */ + if (BdPtr->CheckBits == CFE_ES_CHECK_PATTERN) + { + /* Test if block is deallocated */ + BucketId = BdPtr->Allocated - CFE_ES_MEMORY_DEALLOCATED; + BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId); + if (BucketPtr != 0) + { + IsDeallocatedBlock = true; + } + else + { + /* + * Test if block is allocated. + * In this case there is nothing more to do, just + * get the size and skip the block. + */ + BucketId = BdPtr->Allocated - CFE_ES_MEMORY_ALLOCATED; + BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId); + } + } + + + /* + * Sanity check that the actual size is less than the bucket size - + * it always should be, as long as the pool was created with the same + * set of bucket sizes. + */ + if (BucketPtr == NULL || BucketPtr->BlockSize < BdPtr->ActualSize) + { + /* Not a valid block signature - stop recovery now */ + break; + } + + PoolRecPtr->TailPosition = BlockOffset + BucketPtr->BlockSize; + + BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId); + ++BucketPtr->AllocationCount; + ++PoolRecPtr->AllocationCount; + + /* + * If it was a deallocated block, then add it to the local + * pool linked list structure and rewrite the descriptor. + */ + if (IsDeallocatedBlock) + { + ++BucketPtr->ReleaseCount; + BdPtr->NextOffset = BucketPtr->FirstOffset; + BucketPtr->FirstOffset = BlockOffset; + Status = PoolRecPtr->Commit(PoolRecPtr, DescOffset, BdPtr); + if (Status != CFE_SUCCESS) + { + break; + } + } + } + + return Status; +} + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolValidateState +** +** ES Internal API - See Prototype for full API description +**--------------------------------------------------------------------------------------- +*/ +bool CFE_ES_GenPoolValidateState(const CFE_ES_GenPoolRecord_t *PoolRecPtr) +{ + return (PoolRecPtr->PoolTotalSize > 0 && + PoolRecPtr->TailPosition <= PoolRecPtr->PoolMaxOffset && + PoolRecPtr->NumBuckets > 0 && + PoolRecPtr->NumBuckets < CFE_PLATFORM_ES_POOL_MAX_BUCKETS); +} + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolGetUsage +** +** ES Internal API - See Prototype for full API description +**--------------------------------------------------------------------------------------- +*/ +void CFE_ES_GenPoolGetUsage(CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t *FreeSizeBuf, + CFE_ES_MemOffset_t *TotalSizeBuf) +{ + if (TotalSizeBuf != NULL) + { + *TotalSizeBuf = PoolRecPtr->PoolTotalSize; + } + if (FreeSizeBuf != NULL) + { + *FreeSizeBuf = PoolRecPtr->PoolMaxOffset - PoolRecPtr->TailPosition; + } +} + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolGetCounts +** +** ES Internal API - See Prototype for full API description +**--------------------------------------------------------------------------------------- +*/ +void CFE_ES_GenPoolGetCounts(CFE_ES_GenPoolRecord_t *PoolRecPtr, + uint16 *NumBucketsBuf, + uint32 *AllocCountBuf, + uint32 *ValidationErrorCountBuf) +{ + if (NumBucketsBuf != NULL) + { + *NumBucketsBuf = PoolRecPtr->NumBuckets; + } + if (AllocCountBuf != NULL) + { + *AllocCountBuf = PoolRecPtr->AllocationCount; + } + if (ValidationErrorCountBuf != NULL) + { + *ValidationErrorCountBuf = PoolRecPtr->ValidationErrorCount; + } +} + + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_GenPoolGetFreeSize +** +** ES Internal API - See Prototype for full API description +**--------------------------------------------------------------------------------------- +*/ +void CFE_ES_GenPoolGetBucketUsage(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 BucketId, + CFE_ES_BlockStats_t *BlockStatsBuf) +{ + const CFE_ES_GenPoolBucket_t *BucketPtr; + static const CFE_ES_GenPoolBucket_t ZeroBucket = { 0 }; + + BucketPtr = CFE_ES_GenPoolGetBucketState(PoolRecPtr, BucketId); + if (BucketPtr == NULL) + { + /* bucket ID is not valid */ + BucketPtr = &ZeroBucket; + } + + if (BlockStatsBuf != NULL) + { + BlockStatsBuf->NumCreated = BucketPtr->AllocationCount; + BlockStatsBuf->BlockSize = BucketPtr->BlockSize; + BlockStatsBuf->NumFree = BucketPtr->ReleaseCount - BucketPtr->RecycleCount; + } +} + diff --git a/fsw/cfe-core/src/es/cfe_es_generic_pool.h b/fsw/cfe-core/src/es/cfe_es_generic_pool.h new file mode 100644 index 000000000..6439f686c --- /dev/null +++ b/fsw/cfe-core/src/es/cfe_es_generic_pool.h @@ -0,0 +1,296 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/* +** File: +** cfe_es_generic_pool.h +** +** Purpose: +** This file contains the Internal interface for the cFE Critical Data Store +** memory pool functions. +** +** References: +** Flight Software Branch C Coding Standard Version 1.0a +** cFE Flight Software Application Developers Guide +** +** Notes: +** +*/ + + +#ifndef cfe_es_generic_pool_h +#define cfe_es_generic_pool_h + +/* +** Include Files +*/ +#include "common_types.h" +#include "private/cfe_private.h" + +/* +** Macro Definitions +*/ +#define CFE_ES_CHECK_PATTERN ((uint16)0x5a5a) +#define CFE_ES_MEMORY_ALLOCATED ((uint16)0xaaaa) +#define CFE_ES_MEMORY_DEALLOCATED ((uint16)0xdddd) + + +#define CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE sizeof(CFE_ES_GenPoolBD_t) /* amount of space to reserve with every allocation */ + +/* +** Type Definitions +*/ + +typedef struct CFE_ES_GenPoolBD +{ + uint16 CheckBits; /**< Set to a fixed bit pattern after init */ + uint16 Allocated; /**< Set to a bit pattern depending on allocation state */ + CFE_ES_MemOffset_t ActualSize; /**< The actual requested size of the block */ + CFE_ES_MemOffset_t NextOffset; /**< The offset of the next descriptor in the free stack */ +} CFE_ES_GenPoolBD_t; + + +typedef struct CFE_ES_GenPoolBucket +{ + CFE_ES_MemOffset_t BlockSize; + CFE_ES_MemOffset_t FirstOffset; /**< Top of the "free stack" of buffers which have been returned */ + uint32 AllocationCount; /**< Total number of buffers of this block size that exist (initial get) */ + uint32 ReleaseCount; /**< Total number of buffers that have been released (put back) */ + uint32 RecycleCount; /**< Total number of buffers that have been recycled (get after put) */ +} CFE_ES_GenPoolBucket_t; + +/* + * Forward struct typedef so it can be used in retrieve/commit prototype + */ +typedef struct CFE_ES_GenPoolRecord CFE_ES_GenPoolRecord_t; + +/** + * \brief Function to retrieve a buffer descriptor from the pool storage + * + * The generic pool implementation does not assume that buffers can be + * directly accessed as memory. This routine obtains a reference to + * the descriptor data. On memory mapped pools it may output a direct + * pointer to the data instead of copying it. + */ +typedef int32 (*CFE_ES_PoolRetrieve_Func_t)(CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t Offset, + CFE_ES_GenPoolBD_t **BdPtr); + +/** + * \brief Function to commit a buffer descriptor to the pool storage + * + * The generic pool implementation does not assume that buffers can be + * directly accessed as memory. This routine writes data back to pool + * storage. It may be a no-op for memory mapped pools. + */ +typedef int32 (*CFE_ES_PoolCommit_Func_t)(CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t Offset, + const CFE_ES_GenPoolBD_t *BdPtr); + + +/** + * \brief Generic Memory Pool Type + */ +struct CFE_ES_GenPoolRecord +{ + CFE_ES_MemOffset_t PoolTotalSize; /**< Total size of the pool area, in bytes */ + CFE_ES_MemOffset_t PoolMaxOffset; /**< End offset (position) of the pool */ + CFE_ES_MemOffset_t AlignMask; /**< Alignment mask applied to all new allocations */ + CFE_ES_MemOffset_t TailPosition; /**< Current high watermark of the pool, end of last allocation */ + + CFE_ES_PoolRetrieve_Func_t Retrieve; /**< Function to access a buffer descriptor in the pool storage */ + CFE_ES_PoolCommit_Func_t Commit; /**< Function to commit a buffer descriptor to the pool storage */ + + uint32 AllocationCount; /**< Total number of block allocations of any size */ + uint32 ValidationErrorCount; /**< Count of validation errors */ + + uint16 NumBuckets; /**< Number of entries in the "Buckets" array that are valid */ + CFE_ES_GenPoolBucket_t Buckets[CFE_PLATFORM_ES_POOL_MAX_BUCKETS]; /**< Bucket States */ +}; + +/*****************************************************************************/ +/* +** Function prototypes +*/ + +/** + * \brief Initialize a generic pool structure + * + * Resets the pool to its initial state, given the size + * and alignment specifications. + * + * \param[out] PoolRecPtr Pointer to pool structure + * \param[in] StartOffset Initial starting location of pool + * \param[in] PoolSize Size of pool (beyond start offset) + * \param[in] AlignSize Required Alignment of blocks + * \param[in] NumBlockSizes Number of entries in the BlockSizeList + * \param[in] BlockSizeList Size of pool blocks + * \param[in] RetrieveFunc Function to retrieve buffer descriptors + * \param[in] CommitFunc Function to commit buffer descriptors + * + * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes + */ +int32 CFE_ES_GenPoolInitialize(CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t StartOffset, + CFE_ES_MemOffset_t PoolSize, + CFE_ES_MemOffset_t AlignSize, + uint16 NumBlockSizes, + const CFE_ES_MemOffset_t *BlockSizeList, + CFE_ES_PoolRetrieve_Func_t RetrieveFunc, + CFE_ES_PoolCommit_Func_t CommitFunc); + +/** + * \brief Gets a block from the pool + * + * This may recycle a previously returned block or allocate + * a new block, depending on availability. + * + * \param[inout] PoolRecPtr Pointer to pool structure + * \param[out] BlockOffsetPtr Location to output new block offset + * \param[in] ReqSize Size of block requested + * + * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes + */ +int32 CFE_ES_GenPoolGetBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t *BlockOffsetPtr, + CFE_ES_MemOffset_t ReqSize); + +/** + * \brief Returns a block to the pool + * + * This marks the previously allocated block as deallocated, + * and allows it to be recycled on a future get request. + * + * \param[inout] PoolRecPtr Pointer to pool structure + * \param[out] BlockSizePtr Location to output original allocation size + * \param[in] BlockOffset Offset of data block + * + * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes + */ +int32 CFE_ES_GenPoolPutBlock(CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t *BlockSizePtr, + CFE_ES_MemOffset_t BlockOffset); + +/** + * \brief Rebuild list of free blocks in pool + * + * If pools are stored in a nonvolatile memory area, then it is + * possible to resume pool operation from a previously initialized + * pool. This function attempts to restore the state of the pool + * by scanning for allocated and deallocated block markers. + * + * Before using this function, one should call CFE_ES_GenPoolInitialize() + * to first configure the basic pool structure and block size list. + * + * This function will then attempt to recreate the internal free lists + * based on descriptors/signatures already existing in the memory area. + * + * \param[inout] PoolRecPtr Pointer to pool structure + * + * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes + */ +int32 CFE_ES_GenPoolRebuild(CFE_ES_GenPoolRecord_t *PoolRecPtr); + +/** + * \brief Get size of pool block + * + * Given a previously allocated block, look up its descriptor information + * and return the actual size. + * + * \param[inout] PoolRecPtr Pointer to pool structure + * \param[out] BlockSizePtr Location to output original allocation size + * \param[in] BlockOffset Offset of data block + * + * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes + */ +int32 CFE_ES_GenPoolGetBlockSize(CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t *BlockSizePtr, + CFE_ES_MemOffset_t BlockOffset); + +/** + * \brief Validate a pool structure + * + * Perform basic sanity checks on the pool internal data. + * + * \param[in] PoolRecPtr Pointer to pool structure + * + * \return #CFE_SUCCESS, or error code \ref CFEReturnCodes + */ +bool CFE_ES_GenPoolValidateState(const CFE_ES_GenPoolRecord_t *PoolRecPtr); + +/** + * \brief Query basic usage of the pool structure + * + * \param[in] PoolRecPtr Pointer to pool structure + * \param[out] FreeSizeBuf Buffer to store free size + * \param[out] TotalSizeBuf Buffer to store total size + */ +void CFE_ES_GenPoolGetUsage(CFE_ES_GenPoolRecord_t *PoolRecPtr, + CFE_ES_MemOffset_t *FreeSizeBuf, + CFE_ES_MemOffset_t *TotalSizeBuf); + +/** + * \brief Query counters associated with the pool structure + * + * \param[in] PoolRecPtr Pointer to pool structure + * \param[out] NumBucketsBuf Buffer to store bucket count + * \param[out] AllocCountBuf Buffer to store allocation count + * \param[out] ValidationErrorCountBuf Buffer to store validation error count + */ +void CFE_ES_GenPoolGetCounts(CFE_ES_GenPoolRecord_t *PoolRecPtr, + uint16 *NumBucketsBuf, + uint32 *AllocCountBuf, + uint32 *ValidationErrorCountBuf); + +/** + * \brief Query bucket-specific usage of the pool structure + * + * If the bucket number is not valid, this sets all output values to zero. + * + * \param[in] PoolRecPtr Pointer to pool structure + * \param[in] BucketId Bucket number (non-zero) + * \param[out] BlockStatsBuf Buffer to store block stats + */ +void CFE_ES_GenPoolGetBucketUsage(CFE_ES_GenPoolRecord_t *PoolRecPtr, uint16 BucketId, + CFE_ES_BlockStats_t *BlockStatsBuf); + +/** + * \brief Calculate the pool size required for the specified number of blocks + * + * Given a block size list, determine the amount of bytes required to allocate + * the requested number of minimally-sized blocks, including descriptor overhead. + * + * \note This is intended only as a sanity check on pool sizes, and does not + * guarantee the ability to actually allocate buffers in a real pool. In particular, + * alignment is not factored into the this size calculation, and this may require + * some additional overhead. + * + * \param[in] NumBlockSizes Number of entries in BlockSizeList + * \param[in] BlockSizeList Size of pool blocks + * \param[in] NumBlocks Number of blocks + * + * \return Minimum size required for requested number of blocks. + */ +CFE_ES_MemOffset_t CFE_ES_GenPoolCalcMinSize(uint16 NumBlockSizes, + const CFE_ES_MemOffset_t *BlockSizeList, + uint32 NumBlocks); + +#endif /* _cfe_es_generic_pool_ */ + diff --git a/fsw/cfe-core/src/es/cfe_es_global.h b/fsw/cfe-core/src/es/cfe_es_global.h index 86bc9aa8b..0f73f64ce 100644 --- a/fsw/cfe-core/src/es/cfe_es_global.h +++ b/fsw/cfe-core/src/es/cfe_es_global.h @@ -44,6 +44,8 @@ #include "cfe_es_apps.h" #include "cfe_es_cds.h" #include "cfe_es_perf.h" +#include "cfe_es_generic_pool.h" +#include "cfe_es_mempool.h" #include "cfe_time.h" #include "cfe_platform_cfg.h" #include "cfe_evs.h" @@ -162,6 +164,10 @@ typedef struct */ CFE_ES_BackgroundTaskState_t BackgroundTask; + /* + ** Memory Pools + */ + CFE_ES_MemPoolRecord_t MemPoolTable[CFE_PLATFORM_ES_MAX_MEMORY_POOLS]; } CFE_ES_Global_t; diff --git a/fsw/cfe-core/src/es/cfe_es_mempool.c b/fsw/cfe-core/src/es/cfe_es_mempool.c new file mode 100644 index 000000000..a4285a856 --- /dev/null +++ b/fsw/cfe-core/src/es/cfe_es_mempool.c @@ -0,0 +1,691 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/* +** File: +** cfe_es_mempool.c +** +** Purpose: +** Set of services for management of discrete sized memory pools. +** +** References: +** Flight Software Branch C Coding Standard Version 1.0a +** cFE Flight Software Application Developers Guide +** +*/ + +/* +** Includes +*/ +#include +#include +#include + +#include "private/cfe_private.h" +#include "cfe_es_generic_pool.h" +#include "cfe_es.h" +#include "cfe_es_task.h" +#include "cfe_es_log.h" + +/** + * Macro that determines the native alignment requirement of a specific type + * + * By getting the offset of the structure after following a single char, + * this effectively gets how much padding the compiler added, which in turn reveals its + * minimum alignment requirement. (C99 is lacking a standardized "alignof" operator, + * and this is intended to substitute). + */ +#define ALIGN_OF(type) ((cpuaddr)&((struct { char Byte; type Align; } *)0)->Align) + + +/*****************************************************************************/ +/* +** Type Definitions +*/ + +const CFE_ES_MemOffset_t CFE_ES_MemPoolDefSize[CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES] = +{ + CFE_PLATFORM_ES_MAX_BLOCK_SIZE, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_16, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_15, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_14, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_13, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_12, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_11, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_10, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_09, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_08, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_07, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_06, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_05, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_04, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_03, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_02, + CFE_PLATFORM_ES_MEM_BLOCK_SIZE_01 +}; + +/*****************************************************************************/ +/* +** Functions +*/ + +int32 CFE_ES_MemPoolDirectRetrieve(CFE_ES_GenPoolRecord_t *PoolRecPtr, CFE_ES_MemOffset_t Offset, + CFE_ES_GenPoolBD_t **BdPtr) +{ + cpuaddr DataAddress; + CFE_ES_MemPoolRecord_t *MemPoolRecPtr = (CFE_ES_MemPoolRecord_t *)PoolRecPtr; + + DataAddress = MemPoolRecPtr->BaseAddr + Offset; + *BdPtr = (CFE_ES_GenPoolBD_t *)DataAddress; + + return CFE_SUCCESS; +} + +int32 CFE_ES_MemPoolDirectCommit(CFE_ES_GenPoolRecord_t *PoolRecPtr, CFE_ES_MemOffset_t Offset, + const CFE_ES_GenPoolBD_t *BdPtr) +{ + return CFE_SUCCESS; +} + + +int32 CFE_ES_MemPoolID_ToIndex(CFE_ES_MemHandle_t PoolID, uint32 *Idx) +{ + return CFE_ES_ResourceID_ToIndex_Internal( + CFE_ES_ResourceID_ToInteger(PoolID) - CFE_ES_POOLID_BASE, + CFE_PLATFORM_ES_MAX_MEMORY_POOLS, + Idx); +} + +CFE_ES_MemPoolRecord_t* CFE_ES_LocateMemPoolRecordByID(CFE_ES_MemHandle_t PoolID) +{ + CFE_ES_MemPoolRecord_t *MemPoolRecPtr; + uint32 Idx; + + if (CFE_ES_MemPoolID_ToIndex(PoolID, &Idx) == CFE_SUCCESS) + { + MemPoolRecPtr = &CFE_ES_Global.MemPoolTable[Idx]; + } + else + { + MemPoolRecPtr = NULL; + } + + return MemPoolRecPtr; +} + +/* +** CFE_ES_PoolCreateNoSem will initialize a pre-allocated memory pool without using a mutex. +*/ +int32 CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *PoolID, + uint8 *MemPtr, + CFE_ES_MemOffset_t Size ) +{ + return CFE_ES_PoolCreateEx(PoolID, MemPtr, Size, CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES, + &CFE_ES_MemPoolDefSize[0],CFE_ES_NO_MUTEX); +} + +/* +** CFE_ES_PoolCreate will initialize a pre-allocated memory pool while using a mutex. +*/ +int32 CFE_ES_PoolCreate(CFE_ES_MemHandle_t *PoolID, + uint8 *MemPtr, + CFE_ES_MemOffset_t Size ) +{ + return CFE_ES_PoolCreateEx(PoolID, MemPtr, Size, CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES, + &CFE_ES_MemPoolDefSize[0],CFE_ES_USE_MUTEX); +} + + +int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *PoolID, + uint8 *MemPtr, + CFE_ES_MemOffset_t Size, + uint16 NumBlockSizes, + const CFE_ES_MemOffset_t *BlockSizes, + uint16 UseMutex ) +{ + int32 Status; + uint32 Index; + CFE_ES_MemHandle_t PendingID; + CFE_ES_MemPoolRecord_t *PoolRecPtr; + CFE_ES_MemOffset_t Alignment; + CFE_ES_MemOffset_t MinimumSize; + char MutexName[OS_MAX_API_NAME]; + + /* Sanity Check inputs */ + if (MemPtr == NULL || PoolID == NULL) + { + return CFE_ES_BAD_ARGUMENT; + } + + /* If too many sizes are specified, return an error */ + if (NumBlockSizes > CFE_PLATFORM_ES_POOL_MAX_BUCKETS) + { + CFE_ES_WriteToSysLog("CFE_ES:poolCreate Num Block Sizes (%d) greater than max (%d)\n", + (int)NumBlockSizes, CFE_PLATFORM_ES_POOL_MAX_BUCKETS); + return(CFE_ES_BAD_ARGUMENT); + } + + if ((UseMutex != CFE_ES_USE_MUTEX) && (UseMutex != CFE_ES_NO_MUTEX)) + { + CFE_ES_WriteToSysLog("CFE_ES:poolCreate Invalid Mutex Usage Option (%d), must be %d or %d\n", + UseMutex, CFE_ES_NO_MUTEX, CFE_ES_USE_MUTEX); + return(CFE_ES_BAD_ARGUMENT); + } + + /* + * Use default block sizes if not specified + */ + if (BlockSizes == NULL) + { + BlockSizes = CFE_ES_MemPoolDefSize; + if (NumBlockSizes == 0 || NumBlockSizes > CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES) + { + NumBlockSizes = CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES; + } + } + + /* + * Sanity check the pool size + */ + MinimumSize = CFE_ES_GenPoolCalcMinSize(NumBlockSizes, BlockSizes, 1); + if ( Size < MinimumSize ) + { + CFE_ES_WriteToSysLog("CFE_ES:poolCreate Pool size(%lu) too small, need >=%lu bytes\n", + (unsigned long)Size, + (unsigned long)MinimumSize); + return CFE_ES_BAD_ARGUMENT; + } + + + + /* + * Find an open slot in the Pool Table + */ + PendingID = CFE_ES_RESOURCEID_UNDEFINED; + PoolRecPtr = CFE_ES_Global.MemPoolTable; + CFE_ES_LockSharedData(__func__, __LINE__); + for (Index = 0; Index < CFE_PLATFORM_ES_MAX_MEMORY_POOLS; ++Index) + { + if (!CFE_ES_MemPoolRecordIsUsed(PoolRecPtr)) + { + /* reset/clear all contents */ + memset(PoolRecPtr, 0, sizeof(*PoolRecPtr)); + PendingID = CFE_ES_ResourceID_FromInteger(Index + CFE_ES_POOLID_BASE); + CFE_ES_MemPoolRecordSetUsed(PoolRecPtr, CFE_ES_RESOURCEID_RESERVED); + break; + } + ++PoolRecPtr; + } + CFE_ES_UnlockSharedData(__func__, __LINE__); + + /* + * If no open resource ID was found, return now. + * + * No more inline returns after this point; execution + * must continue to the end of this function where the ID is freed + * if not fully successful. + */ + if (!CFE_ES_ResourceID_IsDefined(PendingID)) + { + return CFE_ES_NO_RESOURCE_IDS_AVAILABLE; + } + + Alignment = ALIGN_OF(CFE_ES_PoolAlign_t); /* memory mapped pools should be aligned */ + if (Alignment < CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN) + { + Alignment = CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN; + } + + /* + * Most of the work is done by the generic pool implementation. + * This subsystem works in offsets, not pointers. + */ + Status = CFE_ES_GenPoolInitialize( + &PoolRecPtr->Pool, + 0, + Size, + Alignment, + NumBlockSizes, + BlockSizes, + CFE_ES_MemPoolDirectRetrieve, + CFE_ES_MemPoolDirectCommit); + + /* + * If successful, complete the process. + */ + if (Status == CFE_SUCCESS && UseMutex == CFE_ES_USE_MUTEX) + { + /* + ** Construct a name for the Mutex from the address + ** This is needed only because OS_MutSemCreate requires + ** a unique name for each semaphore created. + */ + snprintf(MutexName, OS_MAX_API_NAME, "Pool%08lX", CFE_ES_ResourceID_ToInteger(PendingID)); + + /* create a mutex to protect this memory pool */ + Status = OS_MutSemCreate(&PoolRecPtr->MutexId, MutexName, 0); + if (Status != OS_SUCCESS) + { + /* log error and rewrite to CFE status code */ + CFE_ES_WriteToSysLog("CFE_ES:poolCreate OSAL error %d while creating mutex\n", + (int)Status); + + Status = CFE_STATUS_EXTERNAL_RESOURCE_FAIL; + } + } + + if (Status == CFE_SUCCESS) + { + /* + * Store the base address. + * This is only relevant for memory-mapped pools which is why it is done here. + */ + PoolRecPtr->BaseAddr = (cpuaddr)MemPtr; + + /* + * Get the calling context. + * If this not a valid CFE context, then AppID will be undefined. + * We can still permit the creation of the pool but automatic cleanup + * if an exception or other event occurs will not be possible. + */ + CFE_ES_GetAppID(&PoolRecPtr->OwnerAppID); + + /* + * Store the actual/correct pool ID in the record. + */ + CFE_ES_MemPoolRecordSetUsed(PoolRecPtr,PendingID); + } + else + { + /* + * Free the entry that was reserved earlier + */ + CFE_ES_MemPoolRecordSetFree(PoolRecPtr); + PendingID = CFE_ES_RESOURCEID_UNDEFINED; + + if (Status == CFE_ES_POOL_BOUNDS_ERROR) + { + CFE_ES_WriteToSysLog("CFE_ES:poolCreate Pool size(%lu) too small\n", + (unsigned long)Size); + } + } + + /* + * Export pool ID to caller as handle + */ + *PoolID = PendingID; + + return(Status); +} + +int32 CFE_ES_PoolDelete(CFE_ES_MemHandle_t PoolID) +{ + CFE_ES_MemPoolRecord_t *PoolRecPtr; + osal_id_t MutexId; + int32 Status; + int32 MutDeleteStatus; + + PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(PoolID); + + CFE_ES_LockSharedData(__func__, __LINE__); + + /* basic sanity check */ + if (CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, PoolID)) + { + MutexId = PoolRecPtr->MutexId; /* snapshot mutex ID, will be freed later */ + CFE_ES_MemPoolRecordSetFree(PoolRecPtr); + Status = CFE_SUCCESS; + } + else + { + MutexId = OS_OBJECT_ID_UNDEFINED; + Status = CFE_ES_ERR_MEM_HANDLE; + } + + CFE_ES_UnlockSharedData(__func__, __LINE__); + + /* Release the mutex if it was configured. + * This is done after releasing the ES lock, to avoid + * potential conflict with holding two locks. */ + if (OS_ObjectIdDefined(MutexId)) + { + MutDeleteStatus = OS_MutSemDelete(MutexId); + if (MutDeleteStatus != OS_SUCCESS) + { + /* + * Report to syslog for informational purposes only. + * + * The MemPool entry has already been deleted, so this + * function should not return an error at this point. + */ + CFE_ES_WriteToSysLog("CFE_ES:poolDelete error %d deleting mutex\n", + (int)MutDeleteStatus); + } + } + + return Status; +} + +/* +** Function: +** CFE_ES_GetPoolBuf +** +** Purpose: +** CFE_ES_GetPoolBuf allocates a block from the memory pool. +*/ +int32 CFE_ES_GetPoolBuf(uint32 **BufPtr, + CFE_ES_MemHandle_t Handle, + CFE_ES_MemOffset_t Size ) +{ + int32 Status; + CFE_ES_MemHandle_t AppId; + CFE_ES_MemPoolRecord_t *PoolRecPtr; + CFE_ES_MemOffset_t DataOffset; + + PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(Handle); + + /* basic sanity check */ + if (!CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, Handle)) + { + CFE_ES_GetAppID(&AppId); + CFE_ES_WriteToSysLog("CFE_ES:getPoolBuf err:Bad handle(0x%08lX) AppId=%lu\n", + CFE_ES_ResourceID_ToInteger(Handle), + CFE_ES_ResourceID_ToInteger(AppId)); + return(CFE_ES_ERR_MEM_HANDLE); + } + + /* + * Real work begins here. + * If pool is mutex-protected, take the mutex now. + */ + if (OS_ObjectIdDefined(PoolRecPtr->MutexId)) + { + OS_MutSemTake(PoolRecPtr->MutexId); + } + + /* + * Fundamental work is done as a generic routine. + * + * If successful, this gets an offset, which can then + * be translated into a pointer to return to the caller. + */ + Status = CFE_ES_GenPoolGetBlock(&PoolRecPtr->Pool, &DataOffset, Size); + + /* + * Real work ends here. + * If pool is mutex-protected, release the mutex now. + */ + if (OS_ObjectIdDefined(PoolRecPtr->MutexId)) + { + OS_MutSemGive(PoolRecPtr->MutexId); + } + + /* If not successful, return error now */ + if (Status != CFE_SUCCESS) + { + return (Status); + } + + + /* Compute the actual buffer address. + * It is returned as uint32* for historical reasons. */ + *BufPtr = (uint32*)(PoolRecPtr->BaseAddr + DataOffset); + + return (int32)Size; +} + +/* +** CFE_ES_GetPoolBufInfo gets the size of the specified block (if it exists). +*/ +int32 CFE_ES_GetPoolBufInfo(CFE_ES_MemHandle_t Handle, + uint32 * BufPtr) +{ + int32 Status; + CFE_ES_MemPoolRecord_t *PoolRecPtr; + CFE_ES_MemOffset_t DataOffset; + CFE_ES_MemOffset_t DataSize; + + PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(Handle); + + /* basic sanity check */ + if (!CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, Handle)) + { + return(CFE_ES_ERR_MEM_HANDLE); + } + + /* + * Real work begins here. + * If pool is mutex-protected, take the mutex now. + */ + if (OS_ObjectIdDefined(PoolRecPtr->MutexId)) + { + OS_MutSemTake(PoolRecPtr->MutexId); + } + + DataOffset = (cpuaddr)BufPtr - PoolRecPtr->BaseAddr; + + Status = CFE_ES_GenPoolGetBlockSize(&PoolRecPtr->Pool, &DataSize, DataOffset); + + /* + * Real work ends here. + * If pool is mutex-protected, release the mutex now. + */ + if (OS_ObjectIdDefined(PoolRecPtr->MutexId)) + { + OS_MutSemGive(PoolRecPtr->MutexId); + } + + + if (Status == CFE_SUCCESS) + { + /* + * Historically this function returns the size of the buffer + * as an int32. This is not workable for large (64 bit) pools. + */ + Status = (int32)DataSize; + } + + return Status; +} + +/* +** CFE_ES_putPoolBuf returns a block back to the memory pool. +*/ +int32 CFE_ES_PutPoolBuf(CFE_ES_MemHandle_t Handle, + uint32 * BufPtr) +{ + CFE_ES_MemPoolRecord_t *PoolRecPtr; + CFE_ES_MemOffset_t DataSize; + CFE_ES_MemOffset_t DataOffset; + int32 Status; + + PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(Handle); + + /* basic sanity check */ + if (!CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, Handle)) + { + CFE_ES_WriteToSysLog("CFE_ES:putPoolBuf err:Invalid Memory Handle (0x%08lX).\n", + CFE_ES_ResourceID_ToInteger(Handle)); + + return(CFE_ES_ERR_MEM_HANDLE); + } + + /* + * Real work begins here. + * If pool is mutex-protected, take the mutex now. + */ + if (OS_ObjectIdDefined(PoolRecPtr->MutexId)) + { + OS_MutSemTake(PoolRecPtr->MutexId); + } + + DataOffset = (cpuaddr)BufPtr - PoolRecPtr->BaseAddr; + + /* + * Fundamental work is done as a generic routine. + * + * If successful, this gets an offset, which can then + * be translated into a pointer to return to the caller. + */ + Status = CFE_ES_GenPoolPutBlock(&PoolRecPtr->Pool, &DataSize, DataOffset); + + /* + * Real work ends here. + * If pool is mutex-protected, release the mutex now. + */ + if (OS_ObjectIdDefined(PoolRecPtr->MutexId)) + { + OS_MutSemGive(PoolRecPtr->MutexId); + } + + /* + * If successful then modify return code to be + * the size of the original buffer that was put (backward compatible) + * + * Otherwise if not successful, log the relevant detail + */ + if (Status == CFE_SUCCESS) + { + Status = (int32)DataSize; + } + else if (Status == CFE_ES_POOL_BLOCK_INVALID) + { + CFE_ES_WriteToSysLog("CFE_ES:putPoolBuf err:Deallocating invalid or corrupt memory block @ 0x%08lX\n", + (unsigned long)BufPtr); + } + else if (Status == CFE_ES_BUFFER_NOT_IN_POOL) + { + CFE_ES_WriteToSysLog("CFE_ES_GenPoolPutBlock err:Bad offset(%lu) outside pool boundary\n", + (unsigned long)DataOffset); + } + + return Status; +} + +/* +** Function: +** CFE_ES_GetMemPoolStats +** +** Purpose: +** +*/ +int32 CFE_ES_GetMemPoolStats(CFE_ES_MemPoolStats_t *BufPtr, + CFE_ES_MemHandle_t Handle) +{ + CFE_ES_MemHandle_t AppId; + CFE_ES_MemPoolRecord_t *PoolRecPtr; + uint16 NumBuckets; + uint16 Idx; + + PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(Handle); + + /* basic sanity check */ + if (!CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, Handle)) + { + CFE_ES_GetAppID(&AppId); + CFE_ES_WriteToSysLog("CFE_ES:getMemPoolStats err:Bad handle(0x%08lX) AppId=%lu\n", + CFE_ES_ResourceID_ToInteger(Handle), CFE_ES_ResourceID_ToInteger(AppId)); + return(CFE_ES_ERR_MEM_HANDLE); + } + + /* + * Real work begins here. + * If pool is mutex-protected, take the mutex now. + */ + if (OS_ObjectIdDefined(PoolRecPtr->MutexId)) + { + OS_MutSemTake(PoolRecPtr->MutexId); + } + + /* + * Obtain the free and total byte count + */ + CFE_ES_GenPoolGetUsage(&PoolRecPtr->Pool, + &BufPtr->NumFreeBytes, + &BufPtr->PoolSize); + + /* + * Obtain the allocation and validation error counts + */ + CFE_ES_GenPoolGetCounts(&PoolRecPtr->Pool, + &NumBuckets, + &BufPtr->NumBlocksRequested, + &BufPtr->CheckErrCtr); + + for (Idx = 0; Idx < CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES; ++Idx) + { + CFE_ES_GenPoolGetBucketUsage(&PoolRecPtr->Pool, NumBuckets, + &BufPtr->BlockStats[Idx]); + + if (NumBuckets > 0) + { + --NumBuckets; + } + } + + /* + * Real work ends here. + * If pool is mutex-protected, release the mutex now. + */ + if (OS_ObjectIdDefined(PoolRecPtr->MutexId)) + { + OS_MutSemGive(PoolRecPtr->MutexId); + } + + return CFE_SUCCESS; +} + + +/* +** Function: +** CFE_ES_ValidateHandle +** +** Purpose: +** Insures that the handle passed in meets all of the requirements of a valid handle. +*/ +bool CFE_ES_ValidateHandle(CFE_ES_MemHandle_t Handle) +{ + CFE_ES_MemPoolRecord_t *PoolRecPtr; + CFE_ES_MemOffset_t TotalSize; + + /* Test #1) Handle must be valid */ + PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(Handle); + if (!CFE_ES_MemPoolRecordIsMatch(PoolRecPtr, Handle)) + { + return false; + } + + /* Test #2) Check critical internal fields are within reason */ + if (!CFE_ES_GenPoolValidateState(&PoolRecPtr->Pool)) + { + return false; + } + + /* Test #3) Check memory address in PSP (allows both RAM and EEPROM) */ + CFE_ES_GenPoolGetUsage(&PoolRecPtr->Pool, NULL, &TotalSize); + if (CFE_PSP_MemValidateRange(PoolRecPtr->BaseAddr, + TotalSize, + CFE_PSP_MEM_ANY) != CFE_PSP_SUCCESS) + { + return false; + } + + return true; +} diff --git a/fsw/cfe-core/src/es/cfe_es_mempool.h b/fsw/cfe-core/src/es/cfe_es_mempool.h new file mode 100644 index 000000000..cd4347488 --- /dev/null +++ b/fsw/cfe-core/src/es/cfe_es_mempool.h @@ -0,0 +1,175 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/** + * \file cfe_es_mempool.h + * + * Contains data structure definitions used by the ES mempool implementation. + * + * The ES memory pools are now built on top of the generic memory pool implementation, + * with a layer on top to translate into memory mapped buffer addresses. + */ + +#ifndef _CFE_ES_MEMPOOL_H_ +#define _CFE_ES_MEMPOOL_H_ + +/* +** Include Files +*/ +#include "common_types.h" +#include "cfe_es_generic_pool.h" + +typedef struct +{ + /* + * The generic pool structure + * This must be the first entry in this structure. + */ + CFE_ES_GenPoolRecord_t Pool; + + /* + * The ID of this pool record + */ + CFE_ES_MemHandle_t PoolID; + + /** + * This indicates the start/base address + * of the memory block. + */ + cpuaddr BaseAddr; + + /** + * The "owner" field stores the AppID of the creator of the pool. + * If an exception or other event occurs that causes this app to exit, + * this allows ES to also release the memory pool entry. + * + * It is still possible for pools to be created outside the context of + * an ES app, but in that case the resource cannot be cleaned up if the + * app exits unexpectedly. + */ + CFE_ES_ResourceID_t OwnerAppID; + + /** + * Optional Mutex for serializing get/put operations + */ + osal_id_t MutexId; +} CFE_ES_MemPoolRecord_t; + + +/** + * @brief Obtain an index value correlating to an ES Memory Pool ID + * + * This calculates a zero based integer value that may be used for indexing + * into a local resource table/array. + * + * Index values are only guaranteed to be unique for resources of the same + * type. For instance, the indices corresponding to two [valid] Memory Pool + * IDs will never overlap, but the index of an Memory Pool and a library ID + * may be the same. Furthermore, indices may be reused if a resource is + * deleted and re-created. + * + * @note There is no inverse of this function - indices cannot be converted + * back to the original PoolID value. The caller should retain the original ID + * for future use. + * + * @param[in] PoolID Memory Pool ID to convert + * @param[out] Idx Buffer where the calculated index will be stored + * + * @return Execution status, see @ref CFEReturnCodes + * @retval #CFE_SUCCESS @copybrief CFE_SUCCESS + */ +int32 CFE_ES_MemPoolID_ToIndex(CFE_ES_MemHandle_t PoolID, uint32 *Idx); + +/** + * @brief Locate the Pool table entry correlating with a given Pool ID. + * + * This only returns a pointer to the table entry and does _not_ + * otherwise check/validate the entry. + * + * @param[in] PoolID the Pool ID to locate + * @return pointer to Pool Table entry for the given Pool ID + */ +CFE_ES_MemPoolRecord_t* CFE_ES_LocateMemPoolRecordByID(CFE_ES_MemHandle_t PoolID); + +/** + * @brief Check if a Memory Pool record is in use or free/empty + * + * This routine checks if the Pool table entry is in use or if it is free + * + * As this dereferences fields within the record, global data must be + * locked prior to invoking this function. + * + * @param[in] PoolRecPtr pointer to Pool table entry + * @returns true if the entry is in use/configured, or false if it is free/empty + */ +static inline bool CFE_ES_MemPoolRecordIsUsed(const CFE_ES_MemPoolRecord_t *PoolRecPtr) +{ + return CFE_ES_ResourceID_IsDefined(PoolRecPtr->PoolID); +} + +/** + * @brief Get the ID value from a Memory Pool table entry + * + * This routine converts the table entry back to an abstract ID. + * + * @param[in] PoolRecPtr pointer to Pool table entry + * @returns PoolID of entry + */ +static inline CFE_ES_MemHandle_t CFE_ES_MemPoolRecordGetID(const CFE_ES_MemPoolRecord_t *PoolRecPtr) +{ + return (PoolRecPtr->PoolID); +} + +/** + * @brief Marks a Memory Pool table entry as used (not free) + * + * This sets the internal field(s) within this entry, and marks + * it as being associated with the given Pool ID. + * + * @param[in] PoolRecPtr pointer to Pool table entry + * @param[in] PoolID the Pool ID of this entry + */ +static inline void CFE_ES_MemPoolRecordSetUsed(CFE_ES_MemPoolRecord_t *PoolRecPtr, CFE_ES_MemHandle_t PoolID) +{ + PoolRecPtr->PoolID = PoolID; +} + +/** + * @brief Set a Memory Pool record table entry free (not used) + * + * This clears the internal field(s) within this entry, and allows the + * memory to be re-used in the future. + * + * @param[in] PoolRecPtr pointer to Pool table entry + */ +static inline void CFE_ES_MemPoolRecordSetFree(CFE_ES_MemPoolRecord_t *PoolRecPtr) +{ + PoolRecPtr->PoolID = CFE_ES_RESOURCEID_UNDEFINED; +} + + +static inline bool CFE_ES_MemPoolRecordIsMatch(const CFE_ES_MemPoolRecord_t *PoolRecPtr, CFE_ES_MemHandle_t PoolID) +{ + return (PoolRecPtr != NULL && CFE_ES_ResourceID_Equal(PoolRecPtr->PoolID, PoolID)); +} + + + +#endif /* _CFE_ES_MEMPOOL_H_ */ diff --git a/fsw/cfe-core/src/es/cfe_es_task.c b/fsw/cfe-core/src/es/cfe_es_task.c index d229390ec..d00bb55c6 100644 --- a/fsw/cfe-core/src/es/cfe_es_task.c +++ b/fsw/cfe-core/src/es/cfe_es_task.c @@ -1746,7 +1746,7 @@ int32 CFE_ES_SendMemPoolStatsCmd(const CFE_ES_SendMemPoolStats_t *data) Cmd = &data->Payload; /* Verify the handle to make sure it is legit */ - MemHandle = CFE_SB_GET_MEMADDR(Cmd->PoolHandle); + MemHandle = Cmd->PoolHandle; ValidHandle = CFE_ES_ValidateHandle(MemHandle); if (ValidHandle) @@ -1755,7 +1755,7 @@ int32 CFE_ES_SendMemPoolStatsCmd(const CFE_ES_SendMemPoolStats_t *data) CFE_ES_GetMemPoolStats(&CFE_ES_TaskData.MemStatsPacket.Payload.PoolStats, MemHandle); /* Echo the specified pool handle in the telemetry packet */ - CFE_SB_SET_MEMADDR(CFE_ES_TaskData.MemStatsPacket.Payload.PoolHandle, MemHandle); + CFE_ES_TaskData.MemStatsPacket.Payload.PoolHandle = MemHandle; /* ** Send memory statistics telemetry packet. @@ -1765,14 +1765,15 @@ int32 CFE_ES_SendMemPoolStatsCmd(const CFE_ES_SendMemPoolStats_t *data) CFE_ES_TaskData.CommandCounter++; CFE_EVS_SendEvent(CFE_ES_TLM_POOL_STATS_INFO_EID, CFE_EVS_EventType_DEBUG, - "Successfully telemetered memory pool stats for 0x%08lX", (unsigned long)Cmd->PoolHandle); + "Successfully telemetered memory pool stats for 0x%08lX", + CFE_ES_ResourceID_ToInteger(Cmd->PoolHandle)); } else { CFE_ES_TaskData.CommandErrorCounter++; CFE_EVS_SendEvent(CFE_ES_INVALID_POOL_HANDLE_ERR_EID, CFE_EVS_EventType_ERROR, "Cannot telemeter memory pool stats. Illegal Handle (0x%08lX)", - (unsigned long)Cmd->PoolHandle); + CFE_ES_ResourceID_ToInteger(Cmd->PoolHandle)); } return CFE_SUCCESS; diff --git a/fsw/cfe-core/src/es/cfe_esmempool.c b/fsw/cfe-core/src/es/cfe_esmempool.c deleted file mode 100644 index de46d29aa..000000000 --- a/fsw/cfe-core/src/es/cfe_esmempool.c +++ /dev/null @@ -1,700 +0,0 @@ -/* -** GSC-18128-1, "Core Flight Executive Version 6.7" -** -** Copyright (c) 2006-2019 United States Government as represented by -** the Administrator of the National Aeronautics and Space Administration. -** All Rights Reserved. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/* -** File: -** cfe_esmempool.c -** -** Purpose: -** Set of services for management of discrete sized memory pools. -** -** References: -** Flight Software Branch C Coding Standard Version 1.0a -** cFE Flight Software Application Developers Guide -** -*/ - -/* -** Includes -*/ -#include "private/cfe_private.h" -#include "cfe_esmempool.h" -#include "cfe_es.h" -#include "cfe_es_task.h" -#include "cfe_es_log.h" -#include - -/** - * Macro that determines the native alignment requirement of a specific type - * - * By getting the offset of the structure after following a single char, - * this effectively gets how much padding the compiler added, which in turn reveals its - * minimum alignment requirement. (C99 is lacking a standardized "alignof" operator, - * and this is intended to substitute). - */ -#define ALIGN_OF(type) ((cpuaddr)&((struct { char Byte; type Align; } *)0)->Align) - -/** - * Union to assist/simplify the pointer manipulation when allocating buffers in a pool - * - * When allocating buffers, the memory is calculated using raw addresses (cpuaddr) and then - * used as either buffer descriptor pointer (BD_t*) or user buffer pointers (uint32*). - * - * This union assists with casting between the 3 types. It is still a cast, but at least - * it limits the casting to these intended data types so it is slightly safer in that regard. - */ -typedef union -{ - BD_t *BdPtr; /**< Use when interpreting pool memory as a descriptor */ - uint32 *UserPtr; /**< Use when interpreting pool memory as a user buffer */ - cpuaddr Addr; /**< Use when interpreting pool memory as a memory address */ -} MemPoolAddr_t; - -/*****************************************************************************/ -/* -** Local Macro Definitions -*/ -#define CFE_ES_CHECK_PATTERN 0x5a5a -#define CFE_ES_MEMORY_ALLOCATED 0xaaaa -#define CFE_ES_MEMORY_DEALLOCATED 0xdddd -/*****************************************************************************/ -/* -** Type Definitions -*/ - - -uint32 CFE_ES_MemPoolDefSize[CFE_ES_MAX_MEMPOOL_BLOCK_SIZES] = -{ - CFE_PLATFORM_ES_MAX_BLOCK_SIZE, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_16, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_15, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_14, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_13, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_12, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_11, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_10, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_09, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_08, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_07, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_06, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_05, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_04, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_03, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_02, - CFE_PLATFORM_ES_MEM_BLOCK_SIZE_01 -}; - -/*****************************************************************************/ -/* -** Local Function Prototypes -*/ -uint32 CFE_ES_GetBlockSize(Pool_t *PoolPtr, uint32 Size); - -/*****************************************************************************/ -/* -** Functions -*/ - -/* -** CFE_ES_PoolCreateNoSem will initialize a pre-allocated memory pool without using a mutex. -*/ -int32 CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *HandlePtr, - uint8 *MemPtr, - uint32 Size ) -{ - return CFE_ES_PoolCreateEx(HandlePtr, MemPtr, Size, CFE_ES_MAX_MEMPOOL_BLOCK_SIZES, - &CFE_ES_MemPoolDefSize[0],CFE_ES_NO_MUTEX); -} - -/* -** CFE_ES_PoolCreate will initialize a pre-allocated memory pool while using a mutex. -*/ -int32 CFE_ES_PoolCreate(CFE_ES_MemHandle_t *HandlePtr, - uint8 *MemPtr, - uint32 Size ) -{ - return CFE_ES_PoolCreateEx(HandlePtr, MemPtr, Size, CFE_ES_MAX_MEMPOOL_BLOCK_SIZES, - &CFE_ES_MemPoolDefSize[0],CFE_ES_USE_MUTEX); -} - - -int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *HandlePtr, - uint8 *MemPtr, - uint32 Size, - uint32 NumBlockSizes, - uint32 *BlockSizes, - uint16 UseMutex ) -{ - char MutexName[OS_MAX_API_NAME]; - cpuaddr MemAddr; - cpuaddr MemAlignSize; - Pool_t *PoolPtr; - uint32 i; - uint32 j; - uint32 k; - uint32 *BlockSizeArrayPtr; - uint32 BlockSizeArraySize; - uint32 MinBlockSize; - - /* - * Verify basic sanity checks early, before doing anything. - * - * Previously this code would fill the PoolPtr structure prior to even verifying - * if the size was at least sizeof(Pool_t) -- possibly overrunning memory. - * - * The absolute minimum memory required for a pool to be usable would be - * enough to store a Pool_t plus at least sizeof(BD_t) plus alignment - * - * Note that alignment adjustments (if enabled) or a larger minimum block size may make - * it so its not possible to obtain even a single buffer allocation, even if this criteria - * is met. But this will protect against overrunning memory which is the most important thing. - */ - MinBlockSize = sizeof(Pool_t) + sizeof(BD_t) + sizeof(CFE_ES_STATIC_POOL_TYPE(CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN)); - if ( Size < MinBlockSize ) - { /* must be able make Pool management structure and at least one of the smallest blocks */ - CFE_ES_WriteToSysLog("CFE_ES:poolCreate Pool size(%u) too small for management structure, need >=(%u)\n", - (unsigned int)Size, - (unsigned int)MinBlockSize); - return(CFE_ES_BAD_ARGUMENT); - } - - /* If too many sizes are specified, return an error */ - if (NumBlockSizes > CFE_ES_MAX_MEMPOOL_BLOCK_SIZES) - { - CFE_ES_WriteToSysLog("CFE_ES:poolCreate Num Block Sizes (%d) greater than max (%d)\n", - (int)NumBlockSizes, CFE_ES_MAX_MEMPOOL_BLOCK_SIZES); - return(CFE_ES_BAD_ARGUMENT); - } - - if ((UseMutex != CFE_ES_USE_MUTEX) && (UseMutex != CFE_ES_NO_MUTEX)) - { - CFE_ES_WriteToSysLog("CFE_ES:poolCreate Invalid Mutex Usage Option (%d), must be %d or %d\n", - UseMutex, CFE_ES_NO_MUTEX, CFE_ES_USE_MUTEX); - return(CFE_ES_BAD_ARGUMENT); - } - - /* - * First align for the pool itself. - * This only needs meet requirements to store a Pool_t - */ - MemAlignSize = ALIGN_OF(Pool_t) - 1; - MemAlignSize |= MemAlignSize >> 1; - MemAlignSize |= MemAlignSize >> 2; - MemAlignSize |= MemAlignSize >> 4; - MemAlignSize |= MemAlignSize >> 8; - MemAlignSize |= MemAlignSize >> 16; - MemAddr = ((cpuaddr)MemPtr + MemAlignSize) & ~MemAlignSize; - - /* - * Determine alignment requirements of pool buffers - * This needs to meet alignment requirements of CFE_ES_PoolAlign_t, or - * the user specified CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN, whichever is greater. - */ - MemAlignSize = ALIGN_OF(CFE_ES_PoolAlign_t) - 1; - MemAlignSize |= CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN - 1; - MemAlignSize |= MemAlignSize >> 1; - MemAlignSize |= MemAlignSize >> 2; - MemAlignSize |= MemAlignSize >> 4; - MemAlignSize |= MemAlignSize >> 8; - MemAlignSize |= MemAlignSize >> 16; - - /* Set the pointers after alignment adjustment (if enabled) */ - PoolPtr = (Pool_t *)MemAddr; - *HandlePtr = MemAddr; - - if (UseMutex == CFE_ES_USE_MUTEX) - { - /* - ** Construct a name for the Mutex from the address - ** This is needed only because OS_MutSemCreate requires - ** a unique name for each semaphore created. - */ - snprintf(MutexName, OS_MAX_API_NAME, "%08lX", (unsigned long)MemPtr); - - /* create a semphore to protect this memory pool */ - OS_MutSemCreate(&(PoolPtr->MutexId), MutexName, 0); - } - - PoolPtr->PoolHandle = MemAddr; - PoolPtr->End = (cpuaddr)MemPtr + Size; /* End is based off the _original_ baseaddr and size */ - PoolPtr->Size = PoolPtr->End - MemAddr; /* Adjusts for any size lost due to alignment */ - PoolPtr->AlignMask = MemAlignSize; - PoolPtr->CurrentAddr = MemAddr + sizeof(Pool_t); - PoolPtr->SizeDescPtr = NULL; - PoolPtr->CheckErrCntr = 0; - PoolPtr->RequestCntr = 0; - - PoolPtr->UseMutex = UseMutex; - - for (i=0; iSizeDesc[i].NumCreated = 0; - PoolPtr->SizeDesc[i].NumFree = 0; - PoolPtr->SizeDesc[i].MaxSize = 0; - PoolPtr->SizeDesc[i].Top = NULL; - } - - /* Use default block sizes if none or too many sizes are specified */ - if ((NumBlockSizes == 0) || (BlockSizes == NULL)) - { - BlockSizeArrayPtr = &CFE_ES_MemPoolDefSize[0]; - BlockSizeArraySize = CFE_ES_MAX_MEMPOOL_BLOCK_SIZES; - } - else - { - BlockSizeArrayPtr = BlockSizes; - BlockSizeArraySize = NumBlockSizes; - } - - /* Use specified block sizes but make sure they are ordered largest to smallest */ - MinBlockSize = 0xffffffff; - for (i=0; i PoolPtr->SizeDesc[j].MaxSize) - { - /* Make space for new size */ - for (k=i; k>j; k--) - { - PoolPtr->SizeDesc[k].MaxSize = PoolPtr->SizeDesc[k-1].MaxSize; - } - - /* Insert the size in the correct location */ - PoolPtr->SizeDesc[j].MaxSize = BlockSizeArrayPtr[i]; - j = CFE_ES_MAX_MEMPOOL_BLOCK_SIZES; - } - else - { - j++; - } - } - } - - return(CFE_SUCCESS); -} - -/* -** Function: -** CFE_ES_GetPoolBuf -** -** Purpose: -** CFE_ES_GetPoolBuf allocates a block from the memory pool. -*/ -int32 CFE_ES_GetPoolBuf(uint32 **BufPtr, - CFE_ES_MemHandle_t Handle, - uint32 Size ) -{ - Pool_t * PoolPtr = (Pool_t *)Handle; - uint32 BlockSize; - MemPoolAddr_t BlockAddr; - CFE_ES_ResourceID_t AppId; - - if (PoolPtr != NULL) - { - if (Handle != PoolPtr->PoolHandle) - { - CFE_ES_GetAppID(&AppId); - CFE_ES_WriteToSysLog("CFE_ES:getPoolBuf err:Bad handle(0x%08lX) AppId=%lu\n", - (unsigned long)Handle, CFE_ES_ResourceID_ToInteger(AppId)); - return(CFE_ES_ERR_MEM_HANDLE); - } - } - else - { - CFE_ES_GetAppID(&AppId); - CFE_ES_WriteToSysLog("CFE_ES:getPoolBuf err:Bad handle(0x%08lX) AppId=%lu\n", - (unsigned long)Handle, CFE_ES_ResourceID_ToInteger(AppId)); - return(CFE_ES_ERR_MEM_HANDLE); - } - - - if (PoolPtr->UseMutex == CFE_ES_USE_MUTEX) - { - OS_MutSemTake(PoolPtr->MutexId); - } - - *BufPtr = NULL; - - BlockSize = CFE_ES_GetBlockSize(PoolPtr, Size); - if (BlockSize > PoolPtr->SizeDesc[0].MaxSize) - { - /* save off the max size prior to release, for the log message */ - BlockSize = PoolPtr->SizeDesc[0].MaxSize; - if (PoolPtr->UseMutex == CFE_ES_USE_MUTEX) - { - OS_MutSemGive(PoolPtr->MutexId); - } - CFE_ES_WriteToSysLog("CFE_ES:getPoolBuf err:size(%u) > max(%u).\n", - (unsigned int)Size, - (unsigned int)BlockSize); - return(CFE_ES_ERR_MEM_BLOCK_SIZE); - } - - /* - ** Check if any of the requested size are available - */ - if (PoolPtr->SizeDescPtr->Top != NULL) /* Set by GetBlockSize call */ - { - /* - ** Get it off the top on the list - */ - BlockAddr.BdPtr = PoolPtr->SizeDescPtr->Top; - - PoolPtr->SizeDescPtr->Top = BlockAddr.BdPtr->Next; - PoolPtr->SizeDescPtr->NumFree--; - - BlockAddr.BdPtr->CheckBits = CFE_ES_CHECK_PATTERN; - BlockAddr.BdPtr->Allocated = CFE_ES_MEMORY_ALLOCATED; /* Flag memory block as allocated */ - BlockAddr.BdPtr->Size = BlockSize; - BlockAddr.BdPtr->Next = NULL; - - ++BlockAddr.BdPtr; - *BufPtr = BlockAddr.UserPtr; - } - else /* go make one */ - { - /* - * Determine the memory address of the new user block, - * which must be aligned according to the AlignMask member. - * - * Account for the space required for the buffer descriptor, which - * be placed before the user buffer in memory. - */ - BlockAddr.Addr = (PoolPtr->CurrentAddr + sizeof(BD_t) + PoolPtr->AlignMask) & - ~PoolPtr->AlignMask; - - /* - * Check if there is enough space remaining in the pool -- the - * proposed start address plus the block size must not exceed the pool end. - * Note it is checked this way in case the pool is at the end of memory, i.e. - * if the pool ends at 0xFFFFFFFF on a 32 bit machine, a comparison of simply - * (addr > end) will not work. - */ - if ( (PoolPtr->End - (BlockAddr.Addr + BlockSize)) >= PoolPtr->Size ){ /* can't fit in remaing mem */ - if (PoolPtr->UseMutex == CFE_ES_USE_MUTEX) - { - OS_MutSemGive(PoolPtr->MutexId); - } - CFE_ES_WriteToSysLog("CFE_ES:getPoolBuf err:Request won't fit in remaining memory\n"); - return(CFE_ES_ERR_MEM_BLOCK_SIZE); - } - - /* point to new memory block */ - *BufPtr = BlockAddr.UserPtr; - - /* - ** adjust pool current pointer and other recordkeeping in the Pool_t - */ - PoolPtr->CurrentAddr = BlockAddr.Addr + BlockSize; - PoolPtr->SizeDescPtr->NumCreated++; - PoolPtr->RequestCntr++; - - /* - ** create the buffer descriptor at the front of it - */ - --BlockAddr.BdPtr; - BlockAddr.BdPtr->CheckBits = CFE_ES_CHECK_PATTERN; - BlockAddr.BdPtr->Allocated = CFE_ES_MEMORY_ALLOCATED; /* Flag memory block as allocated */ - BlockAddr.BdPtr->Size = BlockSize; - BlockAddr.BdPtr->Next = NULL; - - } - - if (PoolPtr->UseMutex == CFE_ES_USE_MUTEX) - { - OS_MutSemGive(PoolPtr->MutexId); - } - return (int32)BlockSize; -} - -/* -** CFE_ES_GetPoolBufInfo gets the size of the specified block (if it exists). -*/ -int32 CFE_ES_GetPoolBufInfo(CFE_ES_MemHandle_t Handle, - uint32 * BufPtr) -{ - Pool_t *PoolPtr = (Pool_t *)Handle; - MemPoolAddr_t BlockAddr; - int32 Status; - - BlockAddr.UserPtr = BufPtr; - - if (PoolPtr == NULL || Handle != PoolPtr->PoolHandle) - { - /* bad handle */ - Status = CFE_ES_ERR_MEM_HANDLE; - } - else if ( (BlockAddr.Addr < (Handle + sizeof(Pool_t) + sizeof(BD_t))) || - (BlockAddr.Addr >= PoolPtr->End) ) - { - /* sanity check */ - Status = CFE_ES_BUFFER_NOT_IN_POOL; - } - else - { - /* - ** Move to the descriptor (immediately preceding the user buffer) - ** and perform simple sanity checks for descriptor. - ** This must be done while locked, if the USE_MUTEX flag is set. - */ - --BlockAddr.BdPtr; - - if (PoolPtr->UseMutex == CFE_ES_USE_MUTEX) - { - OS_MutSemTake(PoolPtr->MutexId); - } - - /* If a block is no longer allocated, report an error */ - if (BlockAddr.BdPtr->Allocated != CFE_ES_MEMORY_ALLOCATED || - BlockAddr.BdPtr->CheckBits != CFE_ES_CHECK_PATTERN) - { - Status = CFE_ES_ERR_MEM_HANDLE; - } - else - { - Status = BlockAddr.BdPtr->Size; - } - - if (PoolPtr->UseMutex == CFE_ES_USE_MUTEX) - { - OS_MutSemGive(PoolPtr->MutexId); - } - } - - return Status; -} - -/* -** CFE_ES_putPoolBuf returns a block back to the memory pool. -*/ -int32 CFE_ES_PutPoolBuf(CFE_ES_MemHandle_t Handle, - uint32 * BufPtr) -{ - Pool_t *PoolPtr = (Pool_t *)Handle; - MemPoolAddr_t BlockAddr; - uint32 BlockSize; - int32 Status; - char LogMessage[CFE_ES_MAX_SYSLOG_MSG_SIZE]; - - LogMessage[0] = 0; - BlockAddr.UserPtr = BufPtr; - - if (PoolPtr == NULL || Handle != PoolPtr->PoolHandle) - { - /* bad handle */ - CFE_ES_SysLog_snprintf(LogMessage, sizeof(LogMessage), - "CFE_ES:putPoolBuf err:Invalid Memory Handle (0x%08lX).\n", (unsigned long) Handle); - Status = CFE_ES_ERR_MEM_HANDLE; - } - else if ( (BlockAddr.Addr < (Handle + sizeof(Pool_t) + sizeof(BD_t))) || - (BlockAddr.Addr >= PoolPtr->End) ) - { - /* sanity check */ - CFE_ES_SysLog_snprintf(LogMessage, sizeof(LogMessage), - "CFE_ES:putPoolBuf err:Invalid Memory Handle (0x%08lX) or memory block (0x%08lX).\n", - (unsigned long) Handle, (unsigned long)BufPtr); - Status = CFE_ES_ERR_MEM_HANDLE; - } - else - { - /* - ** Move to the descriptor (immediately preceding the user buffer) - ** and perform simple sanity checks for descriptor. - ** This must be done while locked, if the USE_MUTEX flag is set. - */ - --BlockAddr.BdPtr; - - if (PoolPtr->UseMutex == CFE_ES_USE_MUTEX) - { - OS_MutSemTake(PoolPtr->MutexId); - } - - /* If a block is no longer allocated, report an error */ - if (BlockAddr.BdPtr->Allocated != CFE_ES_MEMORY_ALLOCATED) - { - PoolPtr->CheckErrCntr++; - CFE_ES_SysLog_snprintf(LogMessage, sizeof(LogMessage), - "CFE_ES:putPoolBuf err:Deallocating unallocated memory block @ 0x%08lX\n", - (unsigned long)BufPtr); - Status = CFE_ES_ERR_MEM_HANDLE; - } - else if (BlockAddr.BdPtr->CheckBits != CFE_ES_CHECK_PATTERN) - { - PoolPtr->CheckErrCntr++; - CFE_ES_SysLog_snprintf(LogMessage, sizeof(LogMessage), - "CFE_ES:putPoolBuf err:Invalid/Corrupted Memory descriptor @ 0x%08lX\n", - (unsigned long)BufPtr); - Status = CFE_ES_ERR_MEM_HANDLE; - } - else - { - BlockSize = CFE_ES_GetBlockSize(PoolPtr, BlockAddr.BdPtr->Size); - - if (BlockSize > PoolPtr->SizeDesc[0].MaxSize) - { - PoolPtr->CheckErrCntr++; - CFE_ES_SysLog_snprintf(LogMessage, sizeof(LogMessage), - "CFE_ES:putPoolBuf err:size(%d) > max(%d).\n", - (unsigned int)BlockAddr.BdPtr->Size,(unsigned int)PoolPtr->SizeDesc[0].MaxSize); - Status = CFE_ES_ERR_MEM_HANDLE; - } - else - { - BlockAddr.BdPtr->Allocated = CFE_ES_MEMORY_DEALLOCATED; - BlockAddr.BdPtr->Next = PoolPtr->SizeDescPtr->Top; /* Set by GetBlockSize call */ - PoolPtr->SizeDescPtr->Top = BlockAddr.BdPtr; - PoolPtr->SizeDescPtr->NumFree++; - Status = BlockSize; - } - } - - if (PoolPtr->UseMutex == CFE_ES_USE_MUTEX) - { - OS_MutSemGive(PoolPtr->MutexId); - } - } - - /* Output the message to syslog once the OTHER resource is unlocked */ - if (LogMessage[0] != 0) - { - CFE_ES_SYSLOG_APPEND(LogMessage); - } - - return Status; -} - -/* -** Function: -** ES_GetBlockSize -** -** Purpose: -** -*/ -uint32 CFE_ES_GetBlockSize(Pool_t *PoolPtr, uint32 Size) -{ - uint32 i=0; - - PoolPtr->SizeDescPtr = NULL; - - /* If caller is requesting a size larger than the largest allowed */ - /* then return an error code */ - if (Size > PoolPtr->SizeDesc[0].MaxSize) - { - return(0xFFFFFFFF); - } - - /* Locate the smallest size that holds the desired size */ - while ((i < (CFE_ES_MAX_MEMPOOL_BLOCK_SIZES-1)) && - (Size <= PoolPtr->SizeDesc[i+1].MaxSize)) - { - i++; - } - - PoolPtr->SizeDescPtr = &PoolPtr->SizeDesc[i]; - return(PoolPtr->SizeDesc[i].MaxSize); -} - - -/* -** Function: -** CFE_ES_GetMemPoolStats -** -** Purpose: -** -*/ -int32 CFE_ES_GetMemPoolStats(CFE_ES_MemPoolStats_t *BufPtr, - CFE_ES_MemHandle_t Handle) -{ - CFE_ES_ResourceID_t AppId; - Pool_t *PoolPtr; - uint32 i; - - PoolPtr = (Pool_t *)Handle; - - if (PoolPtr == NULL || Handle != PoolPtr->PoolHandle) - { - CFE_ES_GetAppID(&AppId); - CFE_ES_WriteToSysLog("CFE_ES:getMemPoolStats err:Bad handle(0x%08lX) AppId=%lu\n", - (unsigned long)Handle, CFE_ES_ResourceID_ToInteger(AppId)); - return(CFE_ES_ERR_MEM_HANDLE); - } - - BufPtr->PoolSize = PoolPtr->Size; - BufPtr->NumBlocksRequested = PoolPtr->RequestCntr; - BufPtr->CheckErrCtr = PoolPtr->CheckErrCntr; - BufPtr->NumFreeBytes = PoolPtr->End - PoolPtr->CurrentAddr; - - for (i=0; iBlockStats[i].BlockSize = PoolPtr->SizeDesc[i].MaxSize; - BufPtr->BlockStats[i].NumCreated = PoolPtr->SizeDesc[i].NumCreated; - BufPtr->BlockStats[i].NumFree = PoolPtr->SizeDesc[i].NumFree; - } - - return(CFE_SUCCESS); -} - - -/* -** Function: -** CFE_ES_ValidateHandle -** -** Purpose: -** Insures that the handle passed in meets all of the requirements of a valid handle. -*/ -bool CFE_ES_ValidateHandle(CFE_ES_MemHandle_t Handle) -{ - bool HandleValid = true; - Pool_t *PoolPtr; - - PoolPtr = (Pool_t *)Handle; - - /* There are several tests to make sure the memory pool handle is valid */ - - if ( PoolPtr == NULL ) - /* Test #1) Handle must not be a NULL pointer */ - { - HandleValid = false; - } - /* Test #2) Handle must be a valid memory address (allows both RAM and EEPROM) */ - else if (CFE_PSP_MemValidateRange(Handle, sizeof(Pool_t), CFE_PSP_MEM_ANY) != CFE_PSP_SUCCESS) - { - HandleValid = false; - } - /* Test #3) First field of pool structure must be start address of Pool */ - else if (Handle != PoolPtr->PoolHandle) - { - HandleValid = false; - } - /* Test #4) Pool structure must have End ptr equal to Start plus Size */ - else if ((PoolPtr->PoolHandle + PoolPtr->Size) != PoolPtr->End) - { - HandleValid = false; - } - - return(HandleValid); -} diff --git a/fsw/cfe-core/src/es/cfe_esmempool.h b/fsw/cfe-core/src/es/cfe_esmempool.h deleted file mode 100644 index b099258ef..000000000 --- a/fsw/cfe-core/src/es/cfe_esmempool.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -** GSC-18128-1, "Core Flight Executive Version 6.7" -** -** Copyright (c) 2006-2019 United States Government as represented by -** the Administrator of the National Aeronautics and Space Administration. -** All Rights Reserved. -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -/** - * \file cfe_esmempool.h - * - * Created on: Jan 21, 2015 - * Author: joseph.p.hickey@nasa.gov - * - * Contains data structure definitions used by the ES mempool implementation. - * These had previously been defined in cfe_esmempool.c. The definitions are - * moved into this header file so they can be shared with the unit test. - */ - -#ifndef _CFE_ES_MEMPOOL_H_ -#define _CFE_ES_MEMPOOL_H_ - -/* -** Include Files -*/ -#include "common_types.h" - -typedef struct BD BD_t; - -struct BD -{ - uint16 CheckBits; - uint16 Allocated; - uint32 Size; - BD_t *Next; -}; - -typedef struct -{ - BD_t *Top; - uint32 NumCreated; - uint32 NumFree; - uint32 MaxSize; -} BlockSizeDesc_t; - -/* -** Memory Pool Type -*/ -typedef struct -{ - cpuaddr PoolHandle; - cpuaddr Size; - cpuaddr End; - cpuaddr CurrentAddr; - cpuaddr AlignMask; - BlockSizeDesc_t *SizeDescPtr; - uint16 CheckErrCntr; - uint16 RequestCntr; - osal_id_t MutexId; - uint32 UseMutex; - BlockSizeDesc_t SizeDesc[CFE_ES_MAX_MEMPOOL_BLOCK_SIZES]; -} Pool_t; - - - -#endif /* _cfe_esmempool_ */ diff --git a/fsw/cfe-core/src/inc/cfe_error.h b/fsw/cfe-core/src/inc/cfe_error.h index aa5b06d89..30a7d56b1 100644 --- a/fsw/cfe-core/src/inc/cfe_error.h +++ b/fsw/cfe-core/src/inc/cfe_error.h @@ -154,6 +154,18 @@ */ #define CFE_STATUS_BAD_COMMAND_CODE ((int32)0xc8000004) +/** + * @brief External failure + * + * This error indicates that the operation failed for + * some reason outside the scope of CFE. The real failure may + * have been in OSAL, PSP, or another dependent library. + * + * Details of the original failure should be written to syslog + * and/or a system event before returning this error. + */ +#define CFE_STATUS_EXTERNAL_RESOURCE_FAIL ((int32)0xc8000005) + /** * @brief Not Implemented * @@ -653,6 +665,25 @@ */ #define CFE_ES_NO_RESOURCE_IDS_AVAILABLE ((int32)0xc400002B) +/** + * @brief Invalid pool block + * + * Software attempted to "put" a block back into a pool which + * does not appear to belong to that pool. This may mean the + * pool has become unusable due to memory corruption. + * + */ +#define CFE_ES_POOL_BLOCK_INVALID ((int32)0xc400002C) + +/** + * @brief Invalid pool size or buffer address + * + * A specified pool address or size is outside the acceptable + * bounds for that pool configuration. + * + */ +#define CFE_ES_POOL_BOUNDS_ERROR ((int32)0xc400002D) + /** * @brief Not Implemented diff --git a/fsw/cfe-core/src/inc/cfe_es.h b/fsw/cfe-core/src/inc/cfe_es.h index 368cd3c9e..eee9705e4 100644 --- a/fsw/cfe-core/src/inc/cfe_es.h +++ b/fsw/cfe-core/src/inc/cfe_es.h @@ -60,7 +60,8 @@ #define CFE_ES_DBIT(x) (1L << (x)) /* Places a one at bit positions 0 thru 31 */ #define CFE_ES_DTEST(i,x) (((i) & CFE_ES_DBIT(x)) != 0) /* true iff bit x of i is set */ #define CFE_ES_TEST_LONG_MASK(m,s) (CFE_ES_DTEST(m[(s)/32],(s)%32)) /* Test a bit within an array of 32-bit integers. */ -#define CFE_ES_MAX_MEMPOOL_BLOCK_SIZES 17 /**< Max number of size divisions allowed in a memory pool */ + +#define CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES 17 /**< Default number of size divisions in a memory pool */ /* ** Note about reset type and subtypes: @@ -99,14 +100,6 @@ ** Type Definitions */ -/** - * \brief Memory Handle type - * - * Data type used to hold Handles of Memory Pools - * created via CFE_ES_PoolCreate and CFE_ES_PoolCreateNoSem - */ -typedef cpuaddr CFE_ES_MemHandle_t; - /** * @brief A type that provides a common, abstract identifier for * all ES managed resources (e.g. apps, tasks, counters, etc). @@ -124,6 +117,28 @@ typedef cpuaddr CFE_ES_MemHandle_t; */ typedef uint32 CFE_ES_ResourceID_t; +/** + * \brief Memory Handle type + * + * Data type used to hold Handles of Memory Pools + * created via CFE_ES_PoolCreate and CFE_ES_PoolCreateNoSem + */ +typedef CFE_ES_ResourceID_t CFE_ES_MemHandle_t; + +/** + * Type used for memory pool offsets + * + * For backward compatibility with existing CFE code this can be uint32, + * but pools will be limited to 4GB in size as a result. + * + * On 64-bit platforms this can be a 64-bit value (e.g. size_t) which should + * allow larger pools. + * + * In either case this _must_ be an unsigned type. + */ +typedef uint32 CFE_ES_MemOffset_t; + + /** * @brief A resource ID value that represents an undefined/unused resource * @@ -367,7 +382,7 @@ typedef struct CFE_ES_TaskInfo */ typedef struct CFE_ES_BlockStats { - uint32 BlockSize; /**< \brief Number of bytes in each of these blocks */ + CFE_ES_MemOffset_t BlockSize; /**< \brief Number of bytes in each of these blocks */ uint32 NumCreated; /**< \brief Number of Memory Blocks of this size created */ uint32 NumFree; /**< \brief Number of Memory Blocks of this size that are free */ } CFE_ES_BlockStats_t; @@ -377,15 +392,15 @@ typedef struct CFE_ES_BlockStats */ typedef struct CFE_ES_MemPoolStats { - uint32 PoolSize; /**< \cfetlmmnemonic \ES_POOLSIZE + CFE_ES_MemOffset_t PoolSize; /**< \cfetlmmnemonic \ES_POOLSIZE \brief Size of Memory Pool (in bytes) */ uint32 NumBlocksRequested; /**< \cfetlmmnemonic \ES_BLKSREQ \brief Number of times a memory block has been allocated */ uint32 CheckErrCtr; /**< \cfetlmmnemonic \ES_BLKERRCTR \brief Number of errors detected when freeing a memory block */ - uint32 NumFreeBytes; /**< \cfetlmmnemonic \ES_FREEBYTES + CFE_ES_MemOffset_t NumFreeBytes; /**< \cfetlmmnemonic \ES_FREEBYTES \brief Number of bytes never allocated to a block */ - CFE_ES_BlockStats_t BlockStats[CFE_ES_MAX_MEMPOOL_BLOCK_SIZES]; /**< \cfetlmmnemonic \ES_BLKSTATS + CFE_ES_BlockStats_t BlockStats[CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES]; /**< \cfetlmmnemonic \ES_BLKSTATS \brief Contains stats on each block size */ } CFE_ES_MemPoolStats_t; @@ -1217,7 +1232,7 @@ int32 CFE_ES_RestoreFromCDS(void *RestoreToMemory, CFE_ES_CDSHandle_t Handle); ** -# The start address of the pool must be 32-bit aligned ** -# 168 bytes are used for internal bookkeeping, therefore, they will not be available for allocation. ** -** \param[in, out] HandlePtr A pointer to the variable the caller wishes to have the memory pool handle kept in. *HandlePtr is the memory pool handle. +** \param[in, out] PoolID A pointer to the variable the caller wishes to have the memory pool handle kept in. *PoolID is the memory pool handle. ** ** \param[in] MemPtr A Pointer to the pool of memory created by the calling application. This address must ** be on a 32-bit boundary. @@ -1231,7 +1246,7 @@ int32 CFE_ES_RestoreFromCDS(void *RestoreToMemory, CFE_ES_CDSHandle_t Handle); ** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateEx, #CFE_ES_GetPoolBuf, #CFE_ES_PutPoolBuf, #CFE_ES_GetMemPoolStats ** ******************************************************************************/ -int32 CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *HandlePtr, uint8 *MemPtr, uint32 Size); +int32 CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *PoolID, uint8 *MemPtr, CFE_ES_MemOffset_t Size); /*****************************************************************************/ /** @@ -1246,7 +1261,7 @@ int32 CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *HandlePtr, uint8 *MemPtr, uint3 ** -# The start address of the pool must be 32-bit aligned ** -# 168 bytes are used for internal bookkeeping, therefore, they will not be available for allocation. ** -** \param[in, out] HandlePtr A pointer to the variable the caller wishes to have the memory pool handle kept in. *HandlePtr is the memory pool handle. +** \param[in, out] PoolID A pointer to the variable the caller wishes to have the memory pool handle kept in. *PoolID is the memory pool handle. ** ** \param[in] MemPtr A Pointer to the pool of memory created by the calling application. This address must ** be on a 32-bit boundary. @@ -1260,7 +1275,7 @@ int32 CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *HandlePtr, uint8 *MemPtr, uint3 ** \sa #CFE_ES_PoolCreateNoSem, #CFE_ES_PoolCreateEx, #CFE_ES_GetPoolBuf, #CFE_ES_PutPoolBuf, #CFE_ES_GetMemPoolStats ** ******************************************************************************/ -int32 CFE_ES_PoolCreate(CFE_ES_MemHandle_t *HandlePtr, uint8 *MemPtr, uint32 Size); +int32 CFE_ES_PoolCreate(CFE_ES_MemHandle_t *PoolID, uint8 *MemPtr, CFE_ES_MemOffset_t Size); /*****************************************************************************/ /** @@ -1274,7 +1289,7 @@ int32 CFE_ES_PoolCreate(CFE_ES_MemHandle_t *HandlePtr, uint8 *MemPtr, uint32 Siz ** -# The start address of the pool must be 32-bit aligned ** -# 168 bytes are used for internal bookkeeping, therefore, they will not be available for allocation. ** -** \param[in, out] HandlePtr A pointer to the variable the caller wishes to have the memory pool handle kept in. *HandlePtr is the memory pool handle. +** \param[in, out] PoolID A pointer to the variable the caller wishes to have the memory pool handle kept in. *PoolID is the memory pool handle. ** ** \param[in] MemPtr A Pointer to the pool of memory created by the calling application. This address must ** be on a 32-bit boundary. @@ -1298,7 +1313,39 @@ int32 CFE_ES_PoolCreate(CFE_ES_MemHandle_t *HandlePtr, uint8 *MemPtr, uint32 Siz ** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateNoSem, #CFE_ES_GetPoolBuf, #CFE_ES_PutPoolBuf, #CFE_ES_GetMemPoolStats ** ******************************************************************************/ -int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *HandlePtr, uint8 *MemPtr, uint32 Size, uint32 NumBlockSizes, uint32 *BlockSizes, uint16 UseMutex); +int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *PoolID, + uint8 *MemPtr, + CFE_ES_MemOffset_t Size, + uint16 NumBlockSizes, + const CFE_ES_MemOffset_t *BlockSizes, + uint16 UseMutex ); + + +/*****************************************************************************/ +/** +** \brief Deletes a memory pool that was previously created +** +** \par Description +** This routine removes the pool ID and frees the global table +** entry for future re-use. +** +** \par Assumptions, External Events, and Notes: +** All buffers associated with the pool become invalid after this call. +** The application should ensure that buffers/references to the +** pool are returned before deleting the pool. +** +** \param[in] PoolID The ID of the pool to delete +** +** \return Execution status, see \ref CFEReturnCodes +** \retval #CFE_SUCCESS \copybrief CFE_SUCCESS +** \retval #CFE_ES_ERR_MEM_HANDLE \copybrief CFE_ES_ERR_MEM_HANDLE +** +** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateNoSem, #CFE_ES_GetPoolBuf, #CFE_ES_PutPoolBuf, #CFE_ES_GetMemPoolStats +** +******************************************************************************/ +int32 CFE_ES_PoolDelete(CFE_ES_MemHandle_t PoolID); + + /*****************************************************************************/ /** @@ -1312,7 +1359,7 @@ int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *HandlePtr, uint8 *MemPtr, uint32 S ** ** \param[in, out] BufPtr A pointer to the Application's pointer in which will be stored the address of the allocated memory buffer. *BufPtr is the address of the requested buffer. ** -** \param[in] HandlePtr The handle to the memory pool as returned by #CFE_ES_PoolCreate or #CFE_ES_PoolCreateNoSem. +** \param[in] PoolID The handle to the memory pool as returned by #CFE_ES_PoolCreate or #CFE_ES_PoolCreateNoSem. ** ** \param[in] Size The size of the buffer requested. NOTE: The size allocated may be larger. ** @@ -1323,7 +1370,7 @@ int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *HandlePtr, uint8 *MemPtr, uint32 S ** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateNoSem, #CFE_ES_PoolCreateEx, #CFE_ES_PutPoolBuf, #CFE_ES_GetMemPoolStats, #CFE_ES_GetPoolBufInfo ** ******************************************************************************/ -int32 CFE_ES_GetPoolBuf(uint32 **BufPtr, CFE_ES_MemHandle_t HandlePtr, uint32 Size); +int32 CFE_ES_GetPoolBuf(uint32 **BufPtr, CFE_ES_MemHandle_t PoolID, CFE_ES_MemOffset_t Size); /*****************************************************************************/ /** @@ -1335,7 +1382,7 @@ int32 CFE_ES_GetPoolBuf(uint32 **BufPtr, CFE_ES_MemHandle_t HandlePtr, uint32 Si ** \par Assumptions, External Events, and Notes: ** None ** -** \param[in] HandlePtr The handle to the memory pool as returned by #CFE_ES_PoolCreate or #CFE_ES_PoolCreateNoSem. +** \param[in] PoolID The handle to the memory pool as returned by #CFE_ES_PoolCreate or #CFE_ES_PoolCreateNoSem. ** ** \param[in] BufPtr A pointer to the memory buffer to provide status for. ** @@ -1347,7 +1394,7 @@ int32 CFE_ES_GetPoolBuf(uint32 **BufPtr, CFE_ES_MemHandle_t HandlePtr, uint32 Si ** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateNoSem, #CFE_ES_PoolCreateEx, #CFE_ES_GetPoolBuf, #CFE_ES_GetMemPoolStats, #CFE_ES_PutPoolBuf ** ******************************************************************************/ -int32 CFE_ES_GetPoolBufInfo(CFE_ES_MemHandle_t HandlePtr, uint32 *BufPtr); +int32 CFE_ES_GetPoolBufInfo(CFE_ES_MemHandle_t PoolID, uint32 *BufPtr); /*****************************************************************************/ /** @@ -1359,7 +1406,7 @@ int32 CFE_ES_GetPoolBufInfo(CFE_ES_MemHandle_t HandlePtr, uint32 *BufPtr); ** \par Assumptions, External Events, and Notes: ** None ** -** \param[in] HandlePtr The handle to the memory pool as returned by #CFE_ES_PoolCreate or #CFE_ES_PoolCreateNoSem. +** \param[in] PoolID The handle to the memory pool as returned by #CFE_ES_PoolCreate or #CFE_ES_PoolCreateNoSem. ** ** \param[in] BufPtr A pointer to the memory buffer to be released. ** @@ -1369,7 +1416,7 @@ int32 CFE_ES_GetPoolBufInfo(CFE_ES_MemHandle_t HandlePtr, uint32 *BufPtr); ** \sa #CFE_ES_PoolCreate, #CFE_ES_PoolCreateNoSem, #CFE_ES_PoolCreateEx, #CFE_ES_GetPoolBuf, #CFE_ES_GetMemPoolStats, #CFE_ES_GetPoolBufInfo ** ******************************************************************************/ -int32 CFE_ES_PutPoolBuf(CFE_ES_MemHandle_t HandlePtr, uint32 *BufPtr); +int32 CFE_ES_PutPoolBuf(CFE_ES_MemHandle_t PoolID, uint32 *BufPtr); /*****************************************************************************/ /** diff --git a/fsw/cfe-core/src/sb/cfe_sb_init.c b/fsw/cfe-core/src/sb/cfe_sb_init.c index 4154f0df9..3a831269a 100644 --- a/fsw/cfe-core/src/sb/cfe_sb_init.c +++ b/fsw/cfe-core/src/sb/cfe_sb_init.c @@ -47,7 +47,7 @@ ** External Declarations */ -uint32 CFE_SB_MemPoolDefSize[CFE_ES_MAX_MEMPOOL_BLOCK_SIZES] = +const CFE_ES_MemOffset_t CFE_SB_MemPoolDefSize[CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES] = { CFE_PLATFORM_SB_MAX_BLOCK_SIZE, CFE_PLATFORM_SB_MEM_BLOCK_SIZE_16, @@ -156,7 +156,7 @@ int32 CFE_SB_InitBuffers(void) { Stat = CFE_ES_PoolCreateEx(&CFE_SB.Mem.PoolHdl, CFE_SB.Mem.Partition.Data, CFE_PLATFORM_SB_BUF_MEMORY_BYTES, - CFE_ES_MAX_MEMPOOL_BLOCK_SIZES, + CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES, &CFE_SB_MemPoolDefSize[0], CFE_ES_NO_MUTEX); diff --git a/fsw/cfe-core/src/sb/cfe_sb_task.c b/fsw/cfe-core/src/sb/cfe_sb_task.c index cca69f46a..3ead76756 100644 --- a/fsw/cfe-core/src/sb/cfe_sb_task.c +++ b/fsw/cfe-core/src/sb/cfe_sb_task.c @@ -231,7 +231,7 @@ int32 CFE_SB_AppInit(void){ true); /* Populate the fixed fields in the HK Tlm Msg */ - CFE_SB_SET_MEMADDR(CFE_SB.HKTlmMsg.Payload.MemPoolHandle, CFE_SB.Mem.PoolHdl); + CFE_SB.HKTlmMsg.Payload.MemPoolHandle = CFE_SB.Mem.PoolHdl; /* Populate the fixed fields in the Stat Tlm Msg */ CFE_SB.StatTlmMsg.Payload.MaxMsgIdsAllowed = CFE_PLATFORM_SB_MAX_MSG_IDS; diff --git a/fsw/cfe-core/src/tbl/cfe_tbl_api.c b/fsw/cfe-core/src/tbl/cfe_tbl_api.c index ec0deba04..6448442af 100644 --- a/fsw/cfe-core/src/tbl/cfe_tbl_api.c +++ b/fsw/cfe-core/src/tbl/cfe_tbl_api.c @@ -261,7 +261,7 @@ int32 CFE_TBL_Register( CFE_TBL_Handle_t *TblHandlePtr, if(Status < 0) { CFE_ES_WriteToSysLog("CFE_TBL:Register-1st Buf Alloc GetPool fail Stat=0x%08X MemPoolHndl=0x%08lX\n", - (unsigned int)Status, (unsigned long)CFE_TBL_TaskData.Buf.PoolHdl); + (unsigned int)Status, CFE_ES_ResourceID_ToInteger(CFE_TBL_TaskData.Buf.PoolHdl)); } else { @@ -287,7 +287,7 @@ int32 CFE_TBL_Register( CFE_TBL_Handle_t *TblHandlePtr, if(Status < 0) { CFE_ES_WriteToSysLog("CFE_TBL:Register-2nd Buf Alloc GetPool fail Stat=0x%08X MemPoolHndl=0x%08lX\n", - (unsigned int)Status, (unsigned long)CFE_TBL_TaskData.Buf.PoolHdl); + (unsigned int)Status, CFE_ES_ResourceID_ToInteger(CFE_TBL_TaskData.Buf.PoolHdl)); } else { diff --git a/fsw/cfe-core/src/tbl/cfe_tbl_internal.c b/fsw/cfe-core/src/tbl/cfe_tbl_internal.c index d7df5c2e0..7da4f69fb 100644 --- a/fsw/cfe-core/src/tbl/cfe_tbl_internal.c +++ b/fsw/cfe-core/src/tbl/cfe_tbl_internal.c @@ -443,7 +443,7 @@ int32 CFE_TBL_RemoveAccessLink(CFE_TBL_Handle_t TblHandle) if (Status < 0) { CFE_ES_WriteToSysLog("CFE_TBL:RemoveAccessLink-PutPoolBuf[0] Fail Stat=0x%08X, Hndl=0x%08lX, Buf=0x%08lX\n", - (unsigned int)Status, (unsigned long)CFE_TBL_TaskData.Buf.PoolHdl, (unsigned long)RegRecPtr->Buffers[0].BufferPtr); + (unsigned int)Status, CFE_ES_ResourceID_ToInteger(CFE_TBL_TaskData.Buf.PoolHdl), (unsigned long)RegRecPtr->Buffers[0].BufferPtr); } /* If a double buffered table, then free the second buffer as well */ @@ -455,7 +455,7 @@ int32 CFE_TBL_RemoveAccessLink(CFE_TBL_Handle_t TblHandle) if (Status < 0) { CFE_ES_WriteToSysLog("CFE_TBL:RemoveAccessLink-PutPoolBuf[1] Fail Stat=0x%08X, Hndl=0x%08lX, Buf=0x%08lX\n", - (unsigned int)Status, (unsigned long)CFE_TBL_TaskData.Buf.PoolHdl, (unsigned long)RegRecPtr->Buffers[1].BufferPtr); + (unsigned int)Status, CFE_ES_ResourceID_ToInteger(CFE_TBL_TaskData.Buf.PoolHdl), (unsigned long)RegRecPtr->Buffers[1].BufferPtr); } } else diff --git a/fsw/cfe-core/src/tbl/cfe_tbl_task_cmds.c b/fsw/cfe-core/src/tbl/cfe_tbl_task_cmds.c index bebd56861..9010c4d67 100644 --- a/fsw/cfe-core/src/tbl/cfe_tbl_task_cmds.c +++ b/fsw/cfe-core/src/tbl/cfe_tbl_task_cmds.c @@ -166,7 +166,7 @@ void CFE_TBL_GetHkData(void) CFE_TBL_TaskData.HkPacket.Payload.CommandErrorCounter = CFE_TBL_TaskData.CommandErrorCounter; CFE_TBL_TaskData.HkPacket.Payload.FailedValCounter = CFE_TBL_TaskData.FailedValCounter; CFE_TBL_TaskData.HkPacket.Payload.NumLoadPending = 0; - CFE_SB_SET_MEMADDR(CFE_TBL_TaskData.HkPacket.Payload.MemPoolHandle, CFE_TBL_TaskData.Buf.PoolHdl); + CFE_TBL_TaskData.HkPacket.Payload.MemPoolHandle = CFE_TBL_TaskData.Buf.PoolHdl; /* Determine the number of tables currently registered and Number of Load Pending Tables */ Count = 0; diff --git a/fsw/cfe-core/unit-test/es_UT.c b/fsw/cfe-core/unit-test/es_UT.c index 16a51383f..3e6261544 100644 --- a/fsw/cfe-core/unit-test/es_UT.c +++ b/fsw/cfe-core/unit-test/es_UT.c @@ -51,11 +51,32 @@ extern int32 dummy_function(void); /* ** Global variables */ + +/* Buffers to support memory pool testing */ +typedef union +{ + CFE_ES_PoolAlign_t Align; /* make aligned */ + uint8 Data[300]; +} CFE_ES_GMP_DirectBuffer_t; + +typedef struct +{ + CFE_ES_GenPoolBD_t BD; + CFE_ES_PoolAlign_t Align; /* make aligned */ + uint8 Spare; /* make unaligned */ + uint8 Data[(sizeof(CFE_ES_GenPoolBD_t) * 4) + 157]; /* oddball size */ +} CFE_ES_GMP_IndirectBuffer_t; + + +CFE_ES_GMP_DirectBuffer_t UT_MemPoolDirectBuffer; +CFE_ES_GMP_IndirectBuffer_t UT_MemPoolIndirectBuffer; + /* Create a startup script buffer for a maximum of 5 lines * 80 chars/line */ char StartupScript[MAX_STARTUP_SCRIPT]; /* Number of apps instantiated */ uint32 ES_UT_NumApps; +uint32 ES_UT_NumPools; static const UT_TaskPipeDispatchId_t UT_TPID_CFE_ES_CMD_NOOP_CC = { @@ -216,6 +237,13 @@ CFE_ES_ResourceID_t ES_UT_MakeLibIdForIndex(uint32 ArrayIdx) return CFE_ES_ResourceID_FromInteger(ArrayIdx + CFE_ES_LIBID_BASE); } +CFE_ES_MemHandle_t ES_UT_MakePoolIdForIndex(uint32 ArrayIdx) +{ + /* UT hack - make up PoolID values in a manner similar to FSW. + * Real apps should never do this. */ + return CFE_ES_ResourceID_FromInteger(ArrayIdx + CFE_ES_POOLID_BASE); +} + /* * Helper function to setup a single app ID in the given state, along with * a main task ID. A pointer to the App and Task record is output so the @@ -310,6 +338,63 @@ void ES_UT_SetupChildTaskId(const CFE_ES_AppRecord_t *ParentApp, const char *Tas ++CFE_ES_Global.RegisteredTasks; } +int32 ES_UT_PoolDirectRetrieve(CFE_ES_GenPoolRecord_t *PoolRecPtr, CFE_ES_MemOffset_t Offset, + CFE_ES_GenPoolBD_t **BdPtr) +{ + *BdPtr = (CFE_ES_GenPoolBD_t*)((void*)&UT_MemPoolDirectBuffer.Data[Offset]); + return CFE_SUCCESS; +} + +int32 ES_UT_PoolDirectCommit(CFE_ES_GenPoolRecord_t *PoolRecPtr, CFE_ES_MemOffset_t Offset, + const CFE_ES_GenPoolBD_t *BdPtr) +{ + return CFE_SUCCESS; +} + +int32 ES_UT_PoolIndirectRetrieve(CFE_ES_GenPoolRecord_t *PoolRecPtr, CFE_ES_MemOffset_t Offset, + CFE_ES_GenPoolBD_t **BdPtr) +{ + memcpy(&UT_MemPoolIndirectBuffer.BD, &UT_MemPoolIndirectBuffer.Data[Offset], sizeof(CFE_ES_GenPoolBD_t)); + *BdPtr = &UT_MemPoolIndirectBuffer.BD; + return CFE_SUCCESS; +} + +int32 ES_UT_PoolIndirectCommit(CFE_ES_GenPoolRecord_t *PoolRecPtr, CFE_ES_MemOffset_t Offset, + const CFE_ES_GenPoolBD_t *BdPtr) +{ + memcpy(&UT_MemPoolIndirectBuffer.Data[Offset], BdPtr, sizeof(CFE_ES_GenPoolBD_t)); + return CFE_SUCCESS; +} + +void ES_UT_SetupMemPoolId(CFE_ES_MemPoolRecord_t **OutPoolRecPtr) +{ + CFE_ES_MemHandle_t UtPoolID; + CFE_ES_MemPoolRecord_t *LocalPoolRecPtr; + + UtPoolID = ES_UT_MakePoolIdForIndex(ES_UT_NumPools); + ++ES_UT_NumPools; + + LocalPoolRecPtr = CFE_ES_LocateMemPoolRecordByID(UtPoolID); + + /* in order to validate the size must be nonzero */ + LocalPoolRecPtr->Pool.PoolTotalSize = sizeof(UT_MemPoolDirectBuffer.Data); + LocalPoolRecPtr->Pool.PoolMaxOffset = sizeof(UT_MemPoolDirectBuffer.Data); + LocalPoolRecPtr->Pool.Buckets[0].BlockSize = 16; + LocalPoolRecPtr->Pool.NumBuckets = 1; + LocalPoolRecPtr->Pool.Retrieve = ES_UT_PoolDirectRetrieve; + LocalPoolRecPtr->Pool.Commit = ES_UT_PoolDirectCommit; + LocalPoolRecPtr->BaseAddr = (cpuaddr)UT_MemPoolDirectBuffer.Data; + OS_MutSemCreate(&LocalPoolRecPtr->MutexId, NULL, 0); + + CFE_ES_MemPoolRecordSetUsed(LocalPoolRecPtr, UtPoolID); + + if (OutPoolRecPtr) + { + *OutPoolRecPtr = LocalPoolRecPtr; + } + +} + void ES_UT_SetupSingleCDSRegistry(const char *CDSName, bool IsTable, CFE_ES_CDS_RegRec_t **OutRegRec) { @@ -335,6 +420,7 @@ void ES_UT_SetupSingleCDSRegistry(const char *CDSName, bool IsTable, } LocalRegRecPtr->Taken = true; LocalRegRecPtr->Table = IsTable; + LocalRegRecPtr->MemHandle = sizeof(CFE_ES_Global.CDSVars.ValidityField); @@ -431,6 +517,7 @@ void UtTest_Setup(void) UT_ADD_TEST(TestAPI); UT_ADD_TEST(TestGenericCounterAPI); UT_ADD_TEST(TestCDS); + UT_ADD_TEST(TestGenericPool); UT_ADD_TEST(TestCDSMempool); UT_ADD_TEST(TestESMempool); UT_ADD_TEST(TestSysLog); @@ -446,6 +533,7 @@ void ES_ResetUnitTest(void) memset(&CFE_ES_Global, 0, sizeof(CFE_ES_Global)); ES_UT_NumApps = 0; + ES_UT_NumPools = 0; } /* end ES_ResetUnitTest() */ void TestInit(void) @@ -2037,6 +2125,250 @@ void TestERLog(void) "No log entry rollover; no description; no context"); } + +void TestGenericPool(void) +{ + CFE_ES_GenPoolRecord_t Pool1; + CFE_ES_GenPoolRecord_t Pool2; + CFE_ES_MemOffset_t Offset1; + CFE_ES_MemOffset_t Offset2; + CFE_ES_MemOffset_t Offset3; + CFE_ES_MemOffset_t Offset4; + CFE_ES_MemOffset_t OffsetEnd; + CFE_ES_MemOffset_t BlockSize; + CFE_ES_MemOffset_t FreeSize; + CFE_ES_MemOffset_t TotalSize; + uint16 NumBlocks; + uint32 CountBuf; + uint32 ErrBuf; + CFE_ES_BlockStats_t BlockStats; + static const CFE_ES_MemOffset_t UT_POOL_BLOCK_SIZES[CFE_PLATFORM_ES_POOL_MAX_BUCKETS] = + { + /* + * These are intentionally in a mixed order + * so that the implementation will sort them. + */ + 16, 56, 60, 40, 44, 48, + 64, 128, 20, 24, 28, 12, + 52, 32, 4, 8, 36 + }; + uint16 i; + uint32 ExpectedCount; + + ES_ResetUnitTest(); + + /* Test successfully creating direct access pool, with alignment, no mutex */ + memset(&UT_MemPoolDirectBuffer, 0xee, sizeof(UT_MemPoolDirectBuffer)); + OffsetEnd = sizeof(UT_MemPoolDirectBuffer.Data); + UtAssert_INT32_EQ(CFE_ES_GenPoolInitialize(&Pool1, + 0, + OffsetEnd, + 32, + CFE_PLATFORM_ES_POOL_MAX_BUCKETS, + UT_POOL_BLOCK_SIZES, + ES_UT_PoolDirectRetrieve, + ES_UT_PoolDirectCommit), + CFE_SUCCESS); + + /* Allocate buffers until no space left */ + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, 44), CFE_SUCCESS); + UtAssert_True(Offset1 > 0 && Offset1 < OffsetEnd, "0 < Offset(%lu) < %lu", + (unsigned long)Offset1, (unsigned long)OffsetEnd); + UtAssert_True((Offset1 & 0x1F) == 0, "Offset(%lu) 32 byte alignment", + (unsigned long)Offset1); + + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset2, 72), CFE_SUCCESS); + UtAssert_True(Offset2 > Offset1 && Offset2 < OffsetEnd, "%lu < Offset(%lu) < %lu", + (unsigned long)Offset1, (unsigned long)Offset2, (unsigned long)OffsetEnd); + UtAssert_True((Offset2 & 0x1F) == 0, "Offset(%lu) 32 byte alignment", + (unsigned long)Offset2); + + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset3, 72), CFE_ES_ERR_MEM_BLOCK_SIZE); + + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset3, 6), CFE_SUCCESS); + UtAssert_True(Offset3 > Offset2 && Offset3 < OffsetEnd, "%lu < Offset(%lu) < %lu", + (unsigned long)Offset2, (unsigned long)Offset3, (unsigned long)OffsetEnd); + UtAssert_True((Offset3 & 0x1F) == 0, "Offset(%lu) 32 byte alignment", + (unsigned long)Offset3); + + /* Free a buffer and attempt to reallocate */ + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool1, &BlockSize, Offset2), CFE_SUCCESS); + UtAssert_UINT32_EQ(BlockSize, 72); + + /* Should not be able to free more than once */ + /* This should increment the validation error count */ + UtAssert_ZERO(Pool1.ValidationErrorCount); + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool1, &BlockSize, Offset2), CFE_ES_POOL_BLOCK_INVALID); + UtAssert_NONZERO(Pool1.ValidationErrorCount); + + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset4, 100), CFE_SUCCESS); + UtAssert_True(Offset4 == Offset2, "New Offset(%lu) == Old Offset(%lu)", + (unsigned long)Offset4, (unsigned long)Offset2); + + /* Attempt Bigger than the largest bucket */ + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, 1000), CFE_ES_ERR_MEM_BLOCK_SIZE); + + /* Call stats functions for coverage (no return code) */ + CFE_ES_GenPoolGetUsage(&Pool1, &FreeSize, &TotalSize); + CFE_ES_GenPoolGetCounts(&Pool1, &NumBlocks, &CountBuf, &ErrBuf); + CFE_ES_GenPoolGetBucketUsage(&Pool1, 1, &BlockStats); + + /* Check various outputs to ensure correctness */ + UtAssert_UINT32_EQ(TotalSize, OffsetEnd); + UtAssert_UINT32_EQ(CountBuf, 3); + UtAssert_True(FreeSize > 0, "FreeSize(%lu) > 0", (unsigned long)FreeSize); + + /* put blocks so the pool has a mixture of allocated an deallocated blocks */ + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool1, &BlockSize, Offset1), CFE_SUCCESS); + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool1, &BlockSize, Offset2), CFE_SUCCESS); + + /* Now wipe the pool management structure, and attempt to rebuild it. */ + UtAssert_INT32_EQ(CFE_ES_GenPoolInitialize(&Pool2, + 0, + OffsetEnd, + 32, + CFE_PLATFORM_ES_POOL_MAX_BUCKETS, + UT_POOL_BLOCK_SIZES, + ES_UT_PoolDirectRetrieve, + ES_UT_PoolDirectCommit), + CFE_SUCCESS); + + UtAssert_INT32_EQ(CFE_ES_GenPoolRebuild(&Pool2), + CFE_SUCCESS); + + /* After rebuilding, Pool2 should have similar state data to Pool1. */ + UtAssert_UINT32_EQ(Pool1.TailPosition, Pool2.TailPosition); + UtAssert_UINT32_EQ(Pool1.AllocationCount, Pool2.AllocationCount); + + for (i=0; i < Pool1.NumBuckets; ++i) + { + /* Allocation counts should match exactly */ + UtAssert_UINT32_EQ(Pool1.Buckets[i].AllocationCount, Pool2.Buckets[i].AllocationCount); + + /* + * The recovery is not aware of how many times the block was + * recycled, so this needs to be adjusted. + */ + ExpectedCount = Pool1.Buckets[i].ReleaseCount - Pool1.Buckets[i].RecycleCount; + UtAssert_UINT32_EQ(ExpectedCount, Pool2.Buckets[i].ReleaseCount); + } + + /* Get blocks again, from the recovered pool, to demonstrate that + * the pool is functional after recovery. */ + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset3, 44), CFE_SUCCESS); + UtAssert_UINT32_EQ(Offset3, Offset1); + + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset4, 72), CFE_SUCCESS); + UtAssert_UINT32_EQ(Offset4, Offset2); + + + + /* Test successfully creating indirect memory pool, no alignment, with mutex */ + memset(&UT_MemPoolIndirectBuffer, 0xee, sizeof(UT_MemPoolIndirectBuffer)); + OffsetEnd = sizeof(UT_MemPoolIndirectBuffer.Data); + UtAssert_INT32_EQ(CFE_ES_GenPoolInitialize(&Pool2, + 2, + OffsetEnd - 2, + 0, + CFE_PLATFORM_ES_POOL_MAX_BUCKETS, + UT_POOL_BLOCK_SIZES, + ES_UT_PoolIndirectRetrieve, + ES_UT_PoolIndirectCommit), + CFE_SUCCESS); + + /* Do Series of allocations - confirm that the implementation is + * properly adhering to the block sizes specified. */ + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset1, 1), CFE_SUCCESS); + + /* With no alignment adjustments, the result offset should be exactly matching */ + UtAssert_True(Offset1 == 2 + sizeof(CFE_ES_GenPoolBD_t), "Offset(%lu) match", + (unsigned long)Offset1); + + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset2, 55), CFE_SUCCESS); + /* the previous block should be 4 in size (smallest block) */ + UtAssert_True(Offset2 == Offset1 + 4 + sizeof(CFE_ES_GenPoolBD_t), "Offset(%lu) match", + (unsigned long)Offset2); + + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset3, 15), CFE_SUCCESS); + /* the previous block should be 56 in size */ + UtAssert_True(Offset3 == Offset2 + 56 + sizeof(CFE_ES_GenPoolBD_t), "Offset(%lu) match", + (unsigned long)Offset3); + + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset4, 54), CFE_SUCCESS); + /* the previous block should be 16 in size */ + UtAssert_True(Offset4 == Offset3 + 16 + sizeof(CFE_ES_GenPoolBD_t), "Offset(%lu) match", + (unsigned long)Offset4); + + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool2, &BlockSize, Offset1), CFE_SUCCESS); + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool2, &BlockSize, Offset2), CFE_SUCCESS); + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool2, &BlockSize, Offset3), CFE_SUCCESS); + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool2, &BlockSize, Offset4), CFE_SUCCESS); + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset1, 56), CFE_SUCCESS); + + /* should re-issue previous block */ + UtAssert_True(Offset4 == Offset1, "Offset(%lu) match", + (unsigned long)Offset1); + + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset3, 56), CFE_SUCCESS); + + /* should re-issue previous block */ + UtAssert_True(Offset3 == Offset2, "Offset(%lu) match", + (unsigned long)Offset3); + + /* Getting another will fail, despite being enough space, + * because its now fragmented. */ + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset2, 12), CFE_ES_ERR_MEM_BLOCK_SIZE); + + /* Put the buffer, then corrupt the memory and try to recycle */ + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool2, &BlockSize, Offset3), CFE_SUCCESS); + memset(UT_MemPoolIndirectBuffer.Data, 0xee, sizeof(UT_MemPoolIndirectBuffer.Data)); + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset3, 56), CFE_ES_ERR_MEM_BLOCK_SIZE); + + /* Test with just a single block size */ + ES_ResetUnitTest(); + memset(&UT_MemPoolDirectBuffer, 0xee, sizeof(UT_MemPoolDirectBuffer)); + /* Calculate exact (predicted) pool consumption per block */ + OffsetEnd = (sizeof(CFE_ES_GenPoolBD_t) + 31) & 0xFFF0; + OffsetEnd *= 2; /* make enough for 2 */ + UtAssert_INT32_EQ(CFE_ES_GenPoolInitialize(&Pool1, + 0, + OffsetEnd, + 16, + 1, + UT_POOL_BLOCK_SIZES, + ES_UT_PoolDirectRetrieve, + ES_UT_PoolDirectCommit), + CFE_SUCCESS); + + /* + * This should be exactly enough for 2 allocations. + * Allocation larger than 16 should fail. + */ + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, 32), CFE_ES_ERR_MEM_BLOCK_SIZE); + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset2, 1), CFE_SUCCESS); + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset3, 16), CFE_SUCCESS); + + /* Call stats functions for coverage (no return code) */ + CFE_ES_GenPoolGetUsage(&Pool1, &FreeSize, &TotalSize); + CFE_ES_GenPoolGetCounts(&Pool1, &NumBlocks, &CountBuf, &ErrBuf); + + /* Check various outputs to ensure correctness */ + UtAssert_UINT32_EQ(TotalSize, OffsetEnd); + UtAssert_UINT32_EQ(FreeSize, 0); + UtAssert_UINT32_EQ(CountBuf, 2); + + /* + * Check other validation + */ + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool1, &BlockSize, 0), CFE_ES_BUFFER_NOT_IN_POOL); + UtAssert_True(CFE_ES_GenPoolValidateState(&Pool1), "Nominal Handle validation"); + + Pool1.TailPosition = 0xFFFFFF; + UtAssert_True(!CFE_ES_GenPoolValidateState(&Pool1), "Validate Corrupt handle"); + +} + + void TestTask(void) { uint32 ResetType; @@ -2062,10 +2394,10 @@ void TestTask(void) CFE_ES_DumpCDSRegistry_t DumpCDSRegCmd; CFE_ES_QueryAllTasks_t QueryAllTasksCmd; } CmdBuf; - Pool_t UT_TestPool; CFE_ES_AppRecord_t *UtAppRecPtr; CFE_ES_TaskRecord_t *UtTaskRecPtr; CFE_ES_CDS_RegRec_t *UtCDSRegRecPtr; + CFE_ES_MemPoolRecord_t *UtPoolRecPtr; UtPrintf("Begin Test Task"); @@ -3080,11 +3412,6 @@ void TestTask(void) /* Test telemetry pool statistics retrieval with an invalid handle */ ES_ResetUnitTest(); memset(&CmdBuf, 0, sizeof(CmdBuf)); - memset(&UT_TestPool, 0, sizeof(UT_TestPool)); - CFE_SB_SET_MEMADDR(CmdBuf.TlmPoolStatsCmd.Payload.PoolHandle, &UT_TestPool); - UT_TestPool.PoolHandle = (cpuaddr)&UT_TestPool; - UT_TestPool.Size = 64; - UT_TestPool.End = UT_TestPool.PoolHandle; UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CFE_ES_SendMemPoolStats_t), UT_TPID_CFE_ES_CMD_SEND_MEM_POOL_STATS_CC); UT_Report(__FILE__, __LINE__, @@ -3094,10 +3421,8 @@ void TestTask(void) /* Test successful telemetry pool statistics retrieval */ ES_ResetUnitTest(); - memset(&UT_TestPool, 0, sizeof(UT_TestPool)); - UT_TestPool.PoolHandle = (cpuaddr)&UT_TestPool; - UT_TestPool.Size = 64; - UT_TestPool.End = UT_TestPool.PoolHandle + UT_TestPool.Size; + ES_UT_SetupMemPoolId(&UtPoolRecPtr); + CmdBuf.TlmPoolStatsCmd.Payload.PoolHandle = CFE_ES_MemPoolRecordGetID(UtPoolRecPtr); UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CFE_ES_SendMemPoolStats_t), UT_TPID_CFE_ES_CMD_SEND_MEM_POOL_STATS_CC); UT_Report(__FILE__, __LINE__, @@ -5585,133 +5910,129 @@ void TestCDSMempool(void) void TestESMempool(void) { - CFE_ES_MemHandle_t HandlePtr; - uint8 Buffer[CFE_PLATFORM_ES_MAX_BLOCK_SIZE]; - uint32 *address = NULL; - uint32 *address2 = NULL; - Pool_t *PoolPtr; + CFE_ES_MemHandle_t PoolID1; /* Poo1 1 handle, no mutex */ + CFE_ES_MemHandle_t PoolID2; /* Poo1 2 handle, with mutex */ + uint8 Buffer1[1024]; + uint8 Buffer2[1024]; + uint32 *addressp1 = NULL; /* Pool 1 buffer address */ + uint32 *addressp2 = NULL; /* Pool 2 buffer address */ + CFE_ES_MemPoolRecord_t *PoolPtr; CFE_ES_MemPoolStats_t Stats; - uint32 BlockSizes[4]; - BD_t *BdPtr; - CFE_ES_MemHandle_t HandlePtr2; - CFE_ES_MemHandle_t HandlePtrSave; + CFE_ES_MemOffset_t BlockSizes[CFE_PLATFORM_ES_POOL_MAX_BUCKETS+2]; + CFE_ES_GenPoolBD_t *BdPtr; uint32 i; UtPrintf("Begin Test ES memory pool"); + memset(BlockSizes, 0, sizeof(BlockSizes)); + /* Test creating memory pool without using a mutex with the pool size * too small */ ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreateNoSem(&HandlePtr, - Buffer, + CFE_ES_PoolCreateNoSem(&PoolID1, + Buffer1, 0) == CFE_ES_BAD_ARGUMENT, "CFE_ES_PoolCreateNoSem", "Pool size too small"); /* Test successfully creating memory pool without using a mutex */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreateNoSem(&HandlePtr, - Buffer, - CFE_PLATFORM_ES_MAX_BLOCK_SIZE) == CFE_SUCCESS, + CFE_ES_PoolCreateNoSem(&PoolID1, + Buffer1, + sizeof(Buffer1)) == CFE_SUCCESS, "CFE_ES_PoolCreateNoSem", "Memory pool create; successful"); /* Test creating memory pool using a mutex with the pool size too small */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreate(&HandlePtr, Buffer, 0) == CFE_ES_BAD_ARGUMENT, + CFE_ES_PoolCreate(&PoolID2, Buffer2, 0) == CFE_ES_BAD_ARGUMENT, "CFE_ES_PoolCreate", "Pool size too small"); /* Test successfully creating memory pool using a mutex */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreate(&HandlePtr, - Buffer, - CFE_PLATFORM_ES_MAX_BLOCK_SIZE) == CFE_SUCCESS, + CFE_ES_PoolCreate(&PoolID2, + Buffer2, + sizeof(Buffer2)) == CFE_SUCCESS, "CFE_ES_PoolCreate", "Create memory pool (using mutex) [1]; successful"); /* Test successfully allocating a pool buffer */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBuf((uint32 **) &address, HandlePtr, 256) > 0, + CFE_ES_GetPoolBuf((uint32 **) &addressp1, PoolID1, 256) > 0, "CFE_ES_GetPoolBuf", "Allocate pool buffer [1]; successful"); + UT_Report(__FILE__, __LINE__, + CFE_ES_GetPoolBuf((uint32 **) &addressp2, PoolID2, 256) > 0, + "CFE_ES_GetPoolBuf", + "Allocate pool buffer [2]; successful"); + /* Test successfully getting the size of an existing pool buffer */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBufInfo(HandlePtr, address) > 0, + CFE_ES_GetPoolBufInfo(PoolID2, addressp2) > 0, "CFE_ES_GetPoolBufInfo", "Get pool buffer size; successful"); /* Test successfully getting the size of an existing pool buffer. Use no * mutex in order to get branch path coverage */ - ES_ResetUnitTest(); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_NO_MUTEX; UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBufInfo(HandlePtr, address) > 0, + CFE_ES_GetPoolBufInfo(PoolID1, addressp1) > 0, "CFE_ES_GetPoolBufInfo", "Get pool buffer size; successful (no mutex)"); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_USE_MUTEX; /* Test successfully returning a pool buffer to the memory pool */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PutPoolBuf(HandlePtr, address) > 0, + CFE_ES_PutPoolBuf(PoolID1, addressp1) > 0, + "CFE_ES_PutPoolBuf", + "Return buffer to the memory pool; successful"); + + UT_Report(__FILE__, __LINE__, + CFE_ES_PutPoolBuf(PoolID2, addressp2) > 0, "CFE_ES_PutPoolBuf", "Return buffer to the memory pool; successful"); /* Test successfully allocating an additional pool buffer */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBuf(&address, HandlePtr, 256) > 0, + CFE_ES_GetPoolBuf(&addressp2, PoolID2, 256) > 0, "CFE_ES_GetPoolBuf", "Allocate pool buffer [2]; successful"); /* Test successfully returning a pool buffer to the second memory pool. * Use no mutex in order to get branch path coverage */ - ES_ResetUnitTest(); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_NO_MUTEX; UT_Report(__FILE__, __LINE__, - CFE_ES_PutPoolBuf(HandlePtr, address) > 0, + CFE_ES_PutPoolBuf(PoolID2, addressp2) > 0, "CFE_ES_PutPoolBuf", "Return buffer to the second memory pool; successful"); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_USE_MUTEX; /* Test handle validation using a handle with an invalid memory address */ - ES_ResetUnitTest(); - PoolPtr = (Pool_t *) &HandlePtr2; - PoolPtr->PoolHandle = (cpuaddr)&HandlePtrSave; - PoolPtr->Size = 64; UT_SetDeferredRetcode(UT_KEY(CFE_PSP_MemValidateRange), 1, -1); UT_Report(__FILE__, __LINE__, - CFE_ES_ValidateHandle(HandlePtr2) == false, + CFE_ES_ValidateHandle(PoolID2) == false, "CFE_ES_ValidateHandle", "Invalid handle; bad memory address"); /* Test handle validation using a handle where the first pool structure * field is not the pool start address */ - ES_ResetUnitTest(); + PoolPtr = CFE_ES_LocateMemPoolRecordByID(PoolID2); + PoolPtr->PoolID = CFE_ES_ResourceID_FromInteger( + CFE_ES_ResourceID_ToInteger(PoolPtr->PoolID) ^ 10); /* cause it to fail validation */ UT_Report(__FILE__, __LINE__, - CFE_ES_ValidateHandle(HandlePtr2) == false, + CFE_ES_ValidateHandle(PoolID2) == false, "CFE_ES_ValidateHandle", "Invalid handle; not pool start address"); /* Test allocating a pool buffer where the memory handle is not the pool * start address */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBuf(&address, - HandlePtr2, + CFE_ES_GetPoolBuf(&addressp2, + PoolID2, 256) == CFE_ES_ERR_MEM_HANDLE, "CFE_ES_GetPoolBuf", "Invalid handle; not pool start address"); @@ -5719,20 +6040,18 @@ void TestESMempool(void) /* Test getting memory pool statistics where the memory handle is not * the pool start address */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, CFE_ES_GetMemPoolStats(&Stats, - HandlePtr2) == CFE_ES_ERR_MEM_HANDLE, + CFE_ES_RESOURCEID_UNDEFINED) == CFE_ES_ERR_MEM_HANDLE, "CFE_ES_GetMemPoolStats", "Invalid handle; not pool start address"); /* Test allocating a pool buffer where the memory block doesn't fit within * the remaining memory */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBuf(&address, - HandlePtr, + CFE_ES_GetPoolBuf(&addressp1, + PoolID1, 75000) == CFE_ES_ERR_MEM_BLOCK_SIZE, "CFE_ES_GetPoolBuf", "Requested pool size too large"); @@ -5740,18 +6059,19 @@ void TestESMempool(void) /* Test getting the size of an existing pool buffer using an * invalid handle */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBufInfo(HandlePtr, address) == - CFE_ES_BUFFER_NOT_IN_POOL, + CFE_ES_GetPoolBufInfo(PoolID2, addressp2) == + CFE_ES_ERR_MEM_HANDLE, "CFE_ES_GetPoolBufInfo", "Invalid memory pool handle"); + PoolPtr->PoolID = CFE_ES_ResourceID_FromInteger( + CFE_ES_ResourceID_ToInteger(PoolPtr->PoolID) ^ 10); /* Repair Pool2 ID */ + /* Test returning a pool buffer using an invalid memory block */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PutPoolBuf(HandlePtr, - address) == CFE_ES_ERR_MEM_HANDLE, + CFE_ES_PutPoolBuf(PoolID2, + addressp2 - 10) == CFE_ES_BUFFER_NOT_IN_POOL, "CFE_ES_PutPoolBuf", "Invalid memory block"); @@ -5760,10 +6080,10 @@ void TestESMempool(void) */ ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreateEx(&HandlePtr, - Buffer, - sizeof(Buffer), - CFE_ES_MAX_MEMPOOL_BLOCK_SIZES + 2, + CFE_ES_PoolCreateEx(&PoolID1, + Buffer1, + sizeof(Buffer1), + CFE_PLATFORM_ES_POOL_MAX_BUCKETS + 2, BlockSizes, CFE_ES_USE_MUTEX) == CFE_ES_BAD_ARGUMENT, "CFE_ES_PoolCreateEx", @@ -5772,13 +6092,12 @@ void TestESMempool(void) /* Test initializing a pre-allocated pool specifying a pool size that * is too small and using the default block size */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreateEx(&HandlePtr, - Buffer, - sizeof(Pool_t) / 2, - CFE_ES_MAX_MEMPOOL_BLOCK_SIZES - 2, - NULL, + CFE_ES_PoolCreateEx(&PoolID1, + Buffer1, + sizeof(CFE_ES_GenPoolBD_t) / 2, + CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES - 2, + BlockSizes, CFE_ES_USE_MUTEX) == CFE_ES_BAD_ARGUMENT, "CFE_ES_PoolCreateEx", "Memory pool size too small (default block size)"); @@ -5787,11 +6106,10 @@ void TestESMempool(void) /* * Test to use default block sizes if none are given */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreateEx(&HandlePtr, - Buffer, - sizeof(Buffer), + CFE_ES_PoolCreateEx(&PoolID1, + Buffer1, + sizeof(Buffer1), 0, NULL, CFE_ES_USE_MUTEX) == CFE_SUCCESS, @@ -5799,20 +6117,18 @@ void TestESMempool(void) "Use default block sizes when none are given"); /* Test initializing a pre-allocated pool using an invalid mutex option */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreateEx(&HandlePtr, - Buffer, - sizeof(Buffer), - CFE_ES_MAX_MEMPOOL_BLOCK_SIZES - 2, + CFE_ES_PoolCreateEx(&PoolID1, + Buffer1, + sizeof(Buffer1), + CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES - 2, BlockSizes, 2) == CFE_ES_BAD_ARGUMENT, "CFE_ES_PoolCreateEx", "Invalid mutex option"); - /* Test initializing a pre-allocated pool specifying a pool size that - * is too small and specifying the block size with one block size set - * to zero + /* Test initializing a pre-allocated pool specifying + * the block size with one block size set to zero */ ES_ResetUnitTest(); BlockSizes[0] = 10; @@ -5820,22 +6136,21 @@ void TestESMempool(void) BlockSizes[2] = 100; BlockSizes[3] = 0; UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreateEx(&HandlePtr, - Buffer, - sizeof(Pool_t) + sizeof(BD_t), + CFE_ES_PoolCreateEx(&PoolID1, + Buffer1, + sizeof(Buffer1), 4, BlockSizes, - CFE_ES_USE_MUTEX) == CFE_ES_BAD_ARGUMENT, + CFE_ES_USE_MUTEX) == CFE_ES_ERR_MEM_BLOCK_SIZE, "CFE_ES_PoolCreateEx", - "Memory pool size too small (block size specified)"); + "Memory pool block size zero (block size specified)"); - ES_ResetUnitTest(); BlockSizes[0] = 10; BlockSizes[1] = 50; UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreateEx(&HandlePtr, - Buffer, - sizeof(Pool_t) + sizeof(BD_t) + sizeof(CFE_ES_STATIC_POOL_TYPE(CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN)), + CFE_ES_PoolCreateEx(&PoolID1, + Buffer1, + sizeof(Buffer1), 2, BlockSizes, CFE_ES_USE_MUTEX) == CFE_SUCCESS, @@ -5847,199 +6162,205 @@ void TestESMempool(void) */ ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreate(&HandlePtr, - Buffer, - CFE_PLATFORM_ES_MAX_BLOCK_SIZE) == CFE_SUCCESS, + CFE_ES_PoolCreate(&PoolID1, + Buffer1, + sizeof(Buffer1)) == CFE_SUCCESS, "CFE_ES_PoolCreate", "Create memory pool (using mutex) [2]; successful"); + UT_Report(__FILE__, __LINE__, + CFE_ES_PoolCreate(&PoolID2, + Buffer2, + sizeof(Buffer2)) == CFE_SUCCESS, + "CFE_ES_PoolCreate", + "Create memory pool (no mutex) [2]; successful"); /* Test successfully allocating an additional pool buffer for * subsequent tests */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBuf((uint32 **) &address, HandlePtr, 256) > 0, + CFE_ES_GetPoolBuf((uint32 **) &addressp1, PoolID1, 256) > 0, + "CFE_ES_GetPoolBuf", + "Allocate pool buffer [3]; successful"); + + UT_Report(__FILE__, __LINE__, + CFE_ES_GetPoolBuf((uint32 **) &addressp2, PoolID2, 256) > 0, "CFE_ES_GetPoolBuf", "Allocate pool buffer [3]; successful"); /* Test getting the size of an existing pool buffer using an * unallocated block */ - ES_ResetUnitTest(); - BdPtr = ((BD_t *)address) - 1; - BdPtr->Allocated = 717; + BdPtr = ((CFE_ES_GenPoolBD_t *)addressp1) - 1; + BdPtr->Allocated ^= 717; UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBufInfo(HandlePtr, - address) == - CFE_ES_ERR_MEM_HANDLE, + CFE_ES_GetPoolBufInfo(PoolID1, addressp1) == + CFE_ES_POOL_BLOCK_INVALID, "CFE_ES_GetPoolBufInfo", "Invalid memory pool handle; unallocated block"); + /* Test returning a pool buffer using an unallocated block */ + UT_Report(__FILE__, __LINE__, + CFE_ES_PutPoolBuf(PoolID1, addressp1) == CFE_ES_POOL_BLOCK_INVALID, + "CFE_ES_PutPoolBuf", + "Deallocate an unallocated block"); + + BdPtr->Allocated ^= 717; /* repair */ + /* Test getting the size of an existing pool buffer using an - * unallocated block. Use no mutex in order to get branch path coverage + * invalid check bit pattern */ - ES_ResetUnitTest(); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_NO_MUTEX; - BdPtr = ((BD_t *)address) - 1; - BdPtr->Allocated = 717; + BdPtr->Allocated = 0xaaaa; + BdPtr->CheckBits ^= 717; UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBufInfo(HandlePtr, address) == - CFE_ES_ERR_MEM_HANDLE, + CFE_ES_GetPoolBufInfo(PoolID1, addressp1) == + CFE_ES_POOL_BLOCK_INVALID, "CFE_ES_GetPoolBufInfo", - "Invalid memory pool handle; unallocated block (no mutex)"); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_USE_MUTEX; + "Invalid memory pool handle; check bit pattern"); - /* Test returning a pool buffer using an unallocated block */ - ES_ResetUnitTest(); + BdPtr->CheckBits ^= 717; /* repair */ + + /* Test returning a pool buffer using an invalid or corrupted + * memory descriptor + */ + BdPtr->ActualSize = 0xFFFFFFFF; UT_Report(__FILE__, __LINE__, - CFE_ES_PutPoolBuf(HandlePtr, address) == CFE_ES_ERR_MEM_HANDLE, + CFE_ES_PutPoolBuf(PoolID1, addressp1) == + CFE_ES_POOL_BLOCK_INVALID, "CFE_ES_PutPoolBuf", - "Deallocate an unallocated block"); + "Invalid/corrupted memory descriptor"); + + /* Test getting the size of an existing pool buffer using an + * unallocated block. Use no mutex in order to get branch path coverage + */ + BdPtr = ((CFE_ES_GenPoolBD_t *)addressp2) - 1; + BdPtr->Allocated ^= 717; + UT_Report(__FILE__, __LINE__, + CFE_ES_GetPoolBufInfo(PoolID2, addressp2) == + CFE_ES_POOL_BLOCK_INVALID, + "CFE_ES_GetPoolBufInfo", + "Invalid memory pool handle; unallocated block (no mutex)"); /* Test returning a pool buffer using an unallocated block. Use no mutex * in order to get branch path coverage */ - ES_ResetUnitTest(); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_NO_MUTEX; UT_Report(__FILE__, __LINE__, - CFE_ES_PutPoolBuf(HandlePtr, address) == CFE_ES_ERR_MEM_HANDLE, + CFE_ES_PutPoolBuf(PoolID2, addressp2) == CFE_ES_POOL_BLOCK_INVALID, "CFE_ES_PutPoolBuf", "Deallocate an unallocated block (no mutex)"); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_USE_MUTEX; - /* Test getting the size of an existing pool buffer using an - * invalid check bit pattern - */ - ES_ResetUnitTest(); - BdPtr->Allocated = 0xaaaa; - BdPtr->CheckBits = 717; - UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBufInfo(HandlePtr, address) == - CFE_ES_ERR_MEM_HANDLE, - "CFE_ES_GetPoolBufInfo", - "Invalid memory pool handle; check bit pattern"); + BdPtr->Allocated ^= 717; /* repair */ /* Test getting the size of an existing pool buffer using an * invalid check bit pattern. Use no mutex in order to get branch path * coverage */ - ES_ResetUnitTest(); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_NO_MUTEX; - BdPtr->Allocated = 0xaaaa; - BdPtr->CheckBits = 717; + BdPtr->CheckBits ^= 717; UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBufInfo(HandlePtr, address) == - CFE_ES_ERR_MEM_HANDLE, + CFE_ES_GetPoolBufInfo(PoolID2, addressp2) == + CFE_ES_POOL_BLOCK_INVALID, "CFE_ES_GetPoolBufInfo", "Invalid memory pool handle; check bit pattern (no mutex)"); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_USE_MUTEX; - /* Test returning a pool buffer using an invalid or corrupted - * memory descriptor - */ - ES_ResetUnitTest(); - UT_Report(__FILE__, __LINE__, - CFE_ES_PutPoolBuf(HandlePtr, address) == - CFE_ES_ERR_MEM_HANDLE, - "CFE_ES_PutPoolBuf", - "Invalid/corrupted memory descriptor"); + BdPtr->CheckBits ^= 717; /* repair */ /* Test returning a pool buffer using an invalid or corrupted * memory descriptor. Use no mutex in order to get branch path coverage */ - ES_ResetUnitTest(); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_NO_MUTEX; + BdPtr->ActualSize = 0xFFFFFFFF; UT_Report(__FILE__, __LINE__, - CFE_ES_PutPoolBuf(HandlePtr, address) == - CFE_ES_ERR_MEM_HANDLE, + CFE_ES_PutPoolBuf(PoolID2, addressp2) == + CFE_ES_POOL_BLOCK_INVALID, "CFE_ES_PutPoolBuf", "Invalid/corrupted memory descriptor (no mutex)"); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_USE_MUTEX; /* Test successfully creating memory pool using a mutex for * subsequent tests */ ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreate(&HandlePtr, - Buffer, - CFE_PLATFORM_ES_MAX_BLOCK_SIZE) == CFE_SUCCESS, + CFE_ES_PoolCreate(&PoolID1, + Buffer1, + sizeof(Buffer1)) == CFE_SUCCESS, "CFE_ES_PoolCreate", "Create memory pool (using mutex) [3]; successful"); /* Test successfully allocating an additional pool buffer for * subsequent tests. Use no mutex in order to get branch path coverage */ - ES_ResetUnitTest(); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_NO_MUTEX; UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBuf(&address, HandlePtr, 256) > 0, + CFE_ES_PoolCreate(&PoolID2, + Buffer2, + sizeof(Buffer2)) == CFE_SUCCESS, + "CFE_ES_PoolCreate", + "Create memory pool (using mutex) [3]; successful"); + + /* Test successfully allocating an additional pool buffer for + * subsequent tests + */ + UT_Report(__FILE__, __LINE__, + CFE_ES_GetPoolBuf((uint32 **) &addressp1, PoolID1, 256) > 0, "CFE_ES_GetPoolBuf", - "Allocate pool buffer [4]; successful"); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_USE_MUTEX; + "Allocate pool buffer [3]; successful"); + + UT_Report(__FILE__, __LINE__, + CFE_ES_GetPoolBuf((uint32 **) &addressp2, PoolID2, 256) > 0, + "CFE_ES_GetPoolBuf", + "Allocate pool buffer [3]; successful"); /* Test returning a pool buffer using a buffer size larger than * the maximum */ - ES_ResetUnitTest(); - BdPtr->CheckBits = 0x5a5a; - BdPtr->Size =CFE_PLATFORM_ES_MAX_BLOCK_SIZE +1; + BdPtr = ((CFE_ES_GenPoolBD_t *)addressp1) - 1; + BdPtr->ActualSize = CFE_PLATFORM_ES_MAX_BLOCK_SIZE +1; UT_Report(__FILE__, __LINE__, - CFE_ES_PutPoolBuf(HandlePtr, address) == CFE_ES_ERR_MEM_HANDLE, + CFE_ES_PutPoolBuf(PoolID1, addressp1) == CFE_ES_POOL_BLOCK_INVALID, "CFE_ES_PutPoolBuf", "Pool buffer size exceeds maximum"); /* Test returning a pool buffer using a buffer size larger than * the maximum. Use no mutex in order to get branch path coverage */ - ES_ResetUnitTest(); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_NO_MUTEX; - BdPtr->CheckBits = 0x5a5a; - BdPtr->Size =CFE_PLATFORM_ES_MAX_BLOCK_SIZE +1; + BdPtr = ((CFE_ES_GenPoolBD_t *)addressp2) - 1; + BdPtr->ActualSize =CFE_PLATFORM_ES_MAX_BLOCK_SIZE +1; UT_Report(__FILE__, __LINE__, - CFE_ES_PutPoolBuf(HandlePtr, address) == CFE_ES_ERR_MEM_HANDLE, + CFE_ES_PutPoolBuf(PoolID2, addressp2) == CFE_ES_POOL_BLOCK_INVALID, "CFE_ES_PutPoolBuf", "Pool buffer size exceeds maximum (no mutex)"); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_USE_MUTEX; /* Test allocating an additional pool buffer using a buffer size larger * than the maximum */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBuf(&address2, - HandlePtr, + CFE_ES_GetPoolBuf(&addressp2, + PoolID1, 99000) == CFE_ES_ERR_MEM_BLOCK_SIZE, "CFE_ES_GetPoolBuf", "Pool buffer size exceeds maximum"); /* Test handle validation using a null handle */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_ValidateHandle(0) == false, + CFE_ES_ValidateHandle(CFE_ES_RESOURCEID_UNDEFINED) == false, "CFE_ES_ValidateHandle", "NULL handle"); /* Test returning a pool buffer using a null handle */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PutPoolBuf(0, address) == CFE_ES_ERR_MEM_HANDLE, + CFE_ES_PutPoolBuf(CFE_ES_RESOURCEID_UNDEFINED, addressp2) == CFE_ES_ERR_MEM_HANDLE, "CFE_ES_PutPoolBuf", "NULL memory handle"); /* Test allocating a pool buffer using a null handle */ ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBuf(&address, - 0, + CFE_ES_GetPoolBuf(&addressp2, + CFE_ES_RESOURCEID_UNDEFINED, 256) == CFE_ES_ERR_MEM_HANDLE, "CFE_ES_GetPoolBuf", "NULL memory handle"); /* Test getting the size of an existing pool buffer using a null handle */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBufInfo(0, address) == + CFE_ES_GetPoolBufInfo(CFE_ES_RESOURCEID_UNDEFINED, addressp1) == CFE_ES_ERR_MEM_HANDLE, "CFE_ES_GetPoolBufInfo", "NULL memory handle"); @@ -6048,10 +6369,9 @@ void TestESMempool(void) ES_ResetUnitTest(); BlockSizes[0] = 16; UT_Report(__FILE__, __LINE__, - CFE_ES_PoolCreateEx(&HandlePtr, - Buffer, - sizeof(Pool_t) + sizeof(BD_t) + 16 + - sizeof(CFE_ES_STATIC_POOL_TYPE(CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN)), + CFE_ES_PoolCreateEx(&PoolID1, + Buffer1, + 128, 1, BlockSizes, CFE_ES_USE_MUTEX) == CFE_SUCCESS, @@ -6059,17 +6379,14 @@ void TestESMempool(void) "Allocate small memory pool"); /* Test allocating an additional pool buffer using a buffer size larger - * than the maximum. Use no mutex in order to get branch path coverage + * than the maximum. */ - ES_ResetUnitTest(); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_NO_MUTEX; UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBuf(&address2, - HandlePtr, + CFE_ES_GetPoolBuf(&addressp1, + PoolID1, 32) == CFE_ES_ERR_MEM_BLOCK_SIZE, "CFE_ES_GetPoolBuf", "Pool buffer size exceeds maximum (no mutex)"); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_USE_MUTEX; /* * Test allocating a pool buffer where the memory block doesn't fit within @@ -6085,37 +6402,32 @@ void TestESMempool(void) * successful ones is dependent on the CPU architecture and the setting of * CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN. Expect a failure within 20 allocations. */ - ES_ResetUnitTest(); - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_NO_MUTEX; for (i=0; i < 25; ++i) { - if (CFE_ES_GetPoolBuf(&address, HandlePtr, + if (CFE_ES_GetPoolBuf(&addressp1, PoolID1, 12) == CFE_ES_ERR_MEM_BLOCK_SIZE) { break; } } - ((Pool_t *) HandlePtr)->UseMutex = CFE_ES_USE_MUTEX; UT_Report(__FILE__, __LINE__, i >= 1 && i <= 20, "CFE_ES_GetPoolBuf", - "Pool fully allocated (no mutex)"); + "Pool fully allocated"); /* Test getting the size of a pool buffer that is not in the pool */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_GetPoolBufInfo(HandlePtr, - (uint32 *) HandlePtr + 1) == + CFE_ES_GetPoolBufInfo(PoolID1, + (uint32 *) addressp1 + 100) == CFE_ES_BUFFER_NOT_IN_POOL, "CFE_ES_GetPoolBufInfo", "Invalid pool buffer"); /* Test getting the size of a pool buffer with an invalid memory handle */ - ES_ResetUnitTest(); UT_Report(__FILE__, __LINE__, - CFE_ES_PutPoolBuf(HandlePtr, - (uint32 *) HandlePtr + 1) == + CFE_ES_PutPoolBuf(CFE_ES_RESOURCEID_UNDEFINED, + addressp1) == CFE_ES_ERR_MEM_HANDLE, "CFE_ES_PutPoolBuf", "Invalid memory handle"); diff --git a/fsw/cfe-core/unit-test/es_UT.h b/fsw/cfe-core/unit-test/es_UT.h index 3a2dd77a3..0d4a9c6e0 100644 --- a/fsw/cfe-core/unit-test/es_UT.h +++ b/fsw/cfe-core/unit-test/es_UT.h @@ -55,7 +55,7 @@ #include "cfe_es.h" #include "cfe_es_cds.h" #include "cfe_es_cds_mempool.h" -#include "cfe_esmempool.h" +#include "cfe_es_generic_pool.h" #include "cfe_es_global.h" #include "cfe_es_log.h" #include "cfe_es_perf.h" @@ -333,6 +333,7 @@ void TestESMempool(void); void TestSysLog(void); void TestGenericCounterAPI(void); +void TestGenericPool(void); void TestLibs(void); #endif /* _es_ut_h_ */ diff --git a/fsw/cfe-core/unit-test/ut_support.h b/fsw/cfe-core/unit-test/ut_support.h index c8c9d899c..60bfa2a1b 100644 --- a/fsw/cfe-core/unit-test/ut_support.h +++ b/fsw/cfe-core/unit-test/ut_support.h @@ -44,7 +44,7 @@ #include "cfe_evs_task.h" #include "cfe_es_global.h" #include "cfe_es_cds.h" -#include "cfe_esmempool.h" +#include "cfe_es_generic_pool.h" #include "cfe_time_utils.h" #include "utassert.h" diff --git a/fsw/cfe-core/ut-stubs/ut_es_stubs.c b/fsw/cfe-core/ut-stubs/ut_es_stubs.c index 35995042a..c63e70485 100644 --- a/fsw/cfe-core/ut-stubs/ut_es_stubs.c +++ b/fsw/cfe-core/ut-stubs/ut_es_stubs.c @@ -445,11 +445,11 @@ int32 CFE_ES_WriteToSysLog(const char *SpecStringPtr, ...) ** ******************************************************************************/ int32 CFE_ES_GetPoolBuf(uint32 **BufPtr, - CFE_ES_MemHandle_t HandlePtr, - uint32 Size) + CFE_ES_MemHandle_t PoolID, + CFE_ES_MemOffset_t Size) { UT_Stub_RegisterContext(UT_KEY(CFE_ES_GetPoolBuf), BufPtr); - UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_GetPoolBuf), HandlePtr); + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_GetPoolBuf), PoolID); UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_GetPoolBuf), Size); static union @@ -554,9 +554,9 @@ int32 CFE_ES_GetPoolBuf(uint32 **BufPtr, ** Returns either a user-defined status flag or OS_SUCCESS. ** ******************************************************************************/ -int32 CFE_ES_PoolCreate(cpuaddr *HandlePtr, uint8 *MemPtr, uint32 Size) +int32 CFE_ES_PoolCreate(CFE_ES_MemHandle_t *PoolID, uint8 *MemPtr, CFE_ES_MemOffset_t Size) { - UT_Stub_RegisterContext(UT_KEY(CFE_ES_PoolCreate), HandlePtr); + UT_Stub_RegisterContext(UT_KEY(CFE_ES_PoolCreate), PoolID); UT_Stub_RegisterContext(UT_KEY(CFE_ES_PoolCreate), MemPtr); UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_PoolCreate), Size); @@ -566,7 +566,7 @@ int32 CFE_ES_PoolCreate(cpuaddr *HandlePtr, uint8 *MemPtr, uint32 Size) if (status >= 0) { - UT_Stub_CopyToLocal(UT_KEY(CFE_ES_PoolCreate), (uint8*)HandlePtr, sizeof(*HandlePtr)); + UT_Stub_CopyToLocal(UT_KEY(CFE_ES_PoolCreate), (uint8*)PoolID, sizeof(*PoolID)); } return status; @@ -587,11 +587,11 @@ int32 CFE_ES_PoolCreate(cpuaddr *HandlePtr, uint8 *MemPtr, uint32 Size) ** Returns OS_SUCCESS. ** ******************************************************************************/ -int32 CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *HandlePtr, +int32 CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *PoolID, uint8 *MemPtr, - uint32 Size) + CFE_ES_MemOffset_t Size) { - UT_Stub_RegisterContext(UT_KEY(CFE_ES_PoolCreateNoSem), HandlePtr); + UT_Stub_RegisterContext(UT_KEY(CFE_ES_PoolCreateNoSem), PoolID); UT_Stub_RegisterContext(UT_KEY(CFE_ES_PoolCreateNoSem), MemPtr); UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_PoolCreateNoSem), Size); @@ -601,7 +601,7 @@ int32 CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *HandlePtr, if (status >= 0) { - UT_Stub_CopyToLocal(UT_KEY(CFE_ES_PoolCreateNoSem), (uint8*)HandlePtr, sizeof(*HandlePtr)); + UT_Stub_CopyToLocal(UT_KEY(CFE_ES_PoolCreateNoSem), (uint8*)PoolID, sizeof(*PoolID)); } return status; @@ -627,14 +627,14 @@ int32 CFE_ES_PoolCreateNoSem(CFE_ES_MemHandle_t *HandlePtr, ** Returns either a user-defined status flag or CFE_SUCCESS. ** ******************************************************************************/ -int32 CFE_ES_PoolCreateEx(cpuaddr *HandlePtr, - uint8 *MemPtr, - uint32 Size, - uint32 NumBlockSizes, - uint32 *BlockSizes, - uint16 UseMutex) +int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *PoolID, + uint8 *MemPtr, + CFE_ES_MemOffset_t Size, + uint16 NumBlockSizes, + const CFE_ES_MemOffset_t *BlockSizes, + uint16 UseMutex ) { - UT_Stub_RegisterContext(UT_KEY(CFE_ES_PoolCreateEx), HandlePtr); + UT_Stub_RegisterContext(UT_KEY(CFE_ES_PoolCreateEx), PoolID); UT_Stub_RegisterContext(UT_KEY(CFE_ES_PoolCreateEx), MemPtr); UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_PoolCreateEx), Size); UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_PoolCreateEx), NumBlockSizes); @@ -648,6 +648,22 @@ int32 CFE_ES_PoolCreateEx(cpuaddr *HandlePtr, return status; } +/*****************************************************************************/ +/** + * \brief CFE_ES_PoolDelete stub function + */ +int32 CFE_ES_PoolDelete(CFE_ES_MemHandle_t PoolID) +{ + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_PoolDelete), PoolID); + + int32 status = CFE_SUCCESS; + + status = UT_DEFAULT_IMPL(CFE_ES_PoolDelete); + + return status; +} + + /*****************************************************************************/ /** ** \brief CFE_ES_PutPoolBuf stub function @@ -671,9 +687,9 @@ int32 CFE_ES_PoolCreateEx(cpuaddr *HandlePtr, ** Returns either a user-defined status flag, 16, or -1. ** ******************************************************************************/ -int32 CFE_ES_PutPoolBuf(CFE_ES_MemHandle_t HandlePtr, uint32 *BufPtr) +int32 CFE_ES_PutPoolBuf(CFE_ES_MemHandle_t PoolID, uint32 *BufPtr) { - UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_PutPoolBuf), HandlePtr); + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_PutPoolBuf), PoolID); UT_Stub_RegisterContext(UT_KEY(CFE_ES_PutPoolBuf), BufPtr); int32 status; @@ -703,9 +719,9 @@ int32 CFE_ES_PutPoolBuf(CFE_ES_MemHandle_t HandlePtr, uint32 *BufPtr) ** Returns either a user-defined status flag or 16. ** ******************************************************************************/ -int32 CFE_ES_GetPoolBufInfo(CFE_ES_MemHandle_t HandlePtr, uint32 *BufPtr) +int32 CFE_ES_GetPoolBufInfo(CFE_ES_MemHandle_t PoolID, uint32 *BufPtr) { - UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_GetPoolBufInfo), HandlePtr); + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_GetPoolBufInfo), PoolID); UT_Stub_RegisterContext(UT_KEY(CFE_ES_GetPoolBufInfo), BufPtr); int32 status;