From 6b5f77a67eff0e756346df49db14472a5144406d Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Tue, 12 Jan 2021 16:01:40 -0500 Subject: [PATCH] Fix #985, globalize "resource ID" definitions Move certain definitions related to the CFE_ES_ResourceID_t type into the global CFE include files. This introduces two new headers: cfe_resourceid.h (public) cfe_resourceid_internal.h (private to CFE core apps) This allows other CFE core apps, such as SB, to use the CFE_ES_ResourceID_t using the same manipulators. --- fsw/cfe-core/src/es/cfe_es_api.c | 16 +- fsw/cfe-core/src/es/cfe_es_apps.c | 5 +- fsw/cfe-core/src/es/cfe_es_cds.c | 16 +- fsw/cfe-core/src/es/cfe_es_cds.h | 14 ++ fsw/cfe-core/src/es/cfe_es_mempool.c | 16 +- fsw/cfe-core/src/es/cfe_es_mempool.h | 28 ++- fsw/cfe-core/src/es/cfe_es_resource.c | 67 +++++--- fsw/cfe-core/src/es/cfe_es_resource.h | 122 +------------ fsw/cfe-core/src/es/cfe_es_start.c | 2 +- fsw/cfe-core/src/inc/cfe_es.h | 103 +---------- fsw/cfe-core/src/inc/cfe_resourceid.h | 150 ++++++++++++++++ .../src/inc/private/cfe_resourceid_internal.h | 160 ++++++++++++++++++ fsw/cfe-core/unit-test/es_UT.c | 14 +- fsw/cfe-core/ut-stubs/ut_es_stubs.c | 46 +++++ 14 files changed, 500 insertions(+), 259 deletions(-) create mode 100644 fsw/cfe-core/src/inc/cfe_resourceid.h create mode 100644 fsw/cfe-core/src/inc/private/cfe_resourceid_internal.h diff --git a/fsw/cfe-core/src/es/cfe_es_api.c b/fsw/cfe-core/src/es/cfe_es_api.c index d4d639de1..d15d5348d 100644 --- a/fsw/cfe-core/src/es/cfe_es_api.c +++ b/fsw/cfe-core/src/es/cfe_es_api.c @@ -1877,9 +1877,11 @@ int32 CFE_ES_RestoreFromCDS(void *RestoreToMemory, CFE_ES_CDSHandle_t Handle) return CFE_ES_CDSBlockRead(RestoreToMemory, Handle); } /* End of CFE_ES_RestoreFromCDS() */ -/* end of file */ - - +/* +** Function: CFE_ES_RegisterGenCounter +** +** Purpose: Allocates a generic counter resource and assigns ID +*/ int32 CFE_ES_RegisterGenCounter(CFE_ES_ResourceID_t *CounterIdPtr, const char *CounterName) { CFE_ES_GenCounterRecord_t *CountRecPtr; @@ -1912,7 +1914,7 @@ int32 CFE_ES_RegisterGenCounter(CFE_ES_ResourceID_t *CounterIdPtr, const char *C else { /* scan for a free slot */ - PendingCounterId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastCounterId, CFE_PLATFORM_ES_MAX_GEN_COUNTERS); + PendingCounterId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastCounterId, CFE_PLATFORM_ES_MAX_GEN_COUNTERS, CFE_ES_CheckCounterIdSlotUsed); CountRecPtr = CFE_ES_LocateCounterRecordByID(PendingCounterId); if (CountRecPtr == NULL) @@ -2108,7 +2110,7 @@ CFE_Status_t CFE_ES_GetGenCounterName(char *CounterName, CFE_ES_ResourceID_t Cou */ int32 CFE_ES_AppID_ToIndex(CFE_ES_ResourceID_t AppID, uint32 *Idx) { - return CFE_ES_ResourceID_ToIndex_Internal( + return CFE_ES_ResourceID_ToIndex( CFE_ES_ResourceID_ToInteger(AppID) - CFE_ES_APPID_BASE, CFE_PLATFORM_ES_MAX_APPLICATIONS, Idx); @@ -2120,7 +2122,7 @@ int32 CFE_ES_AppID_ToIndex(CFE_ES_ResourceID_t AppID, uint32 *Idx) */ int32 CFE_ES_LibID_ToIndex(CFE_ES_ResourceID_t LibId, uint32 *Idx) { - return CFE_ES_ResourceID_ToIndex_Internal( + return CFE_ES_ResourceID_ToIndex( CFE_ES_ResourceID_ToInteger(LibId) - CFE_ES_LIBID_BASE, CFE_PLATFORM_ES_MAX_LIBRARIES, Idx); @@ -2160,7 +2162,7 @@ int32 CFE_ES_TaskID_ToIndex(CFE_ES_ResourceID_t TaskID, uint32 *Idx) */ int32 CFE_ES_CounterID_ToIndex(CFE_ES_ResourceID_t CounterId, uint32 *Idx) { - return CFE_ES_ResourceID_ToIndex_Internal( + return CFE_ES_ResourceID_ToIndex( CFE_ES_ResourceID_ToInteger(CounterId) - CFE_ES_COUNTID_BASE, CFE_PLATFORM_ES_MAX_GEN_COUNTERS, Idx); diff --git a/fsw/cfe-core/src/es/cfe_es_apps.c b/fsw/cfe-core/src/es/cfe_es_apps.c index c38ee545f..66c430c49 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.c +++ b/fsw/cfe-core/src/es/cfe_es_apps.c @@ -688,7 +688,7 @@ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, else { /* scan for a free slot */ - PendingAppId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastAppId, CFE_PLATFORM_ES_MAX_APPLICATIONS); + PendingAppId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastAppId, CFE_PLATFORM_ES_MAX_APPLICATIONS, CFE_ES_CheckAppIdSlotUsed); AppRecPtr = CFE_ES_LocateAppRecordByID(PendingAppId); if (AppRecPtr == NULL) @@ -795,6 +795,7 @@ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, return Status; } /* End Function */ + /* **--------------------------------------------------------------------------------------- ** Name: CFE_ES_LoadLibrary @@ -864,7 +865,7 @@ int32 CFE_ES_LoadLibrary(CFE_ES_ResourceID_t *LibraryIdPtr, else { /* scan for a free slot */ - PendingLibId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastLibId, CFE_PLATFORM_ES_MAX_LIBRARIES); + PendingLibId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastLibId, CFE_PLATFORM_ES_MAX_LIBRARIES, CFE_ES_CheckLibIdSlotUsed); LibSlotPtr = CFE_ES_LocateLibRecordByID(PendingLibId); if (LibSlotPtr == NULL) diff --git a/fsw/cfe-core/src/es/cfe_es_cds.c b/fsw/cfe-core/src/es/cfe_es_cds.c index 6d1485f81..2c6ff0248 100644 --- a/fsw/cfe-core/src/es/cfe_es_cds.c +++ b/fsw/cfe-core/src/es/cfe_es_cds.c @@ -163,12 +163,24 @@ int32 CFE_ES_CDS_EarlyInit(void) /*******************************************************************/ int32 CFE_ES_CDSBlockID_ToIndex(CFE_ES_ResourceID_t BlockID, uint32 *Idx) { - return CFE_ES_ResourceID_ToIndex_Internal( + return CFE_ES_ResourceID_ToIndex( CFE_ES_ResourceID_ToInteger(BlockID) - CFE_ES_CDSBLOCKID_BASE, CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES, Idx); } +/*--------------------------------------------------------------------------------------- + * Function: CFE_ES_CheckCDSBlockIdSlotUsed + * + * Purpose: Helper function, Aids in allocating a new ID by checking if + * a given ID is available. Must be called while locked. + *--------------------------------------------------------------------------------------- + */ +bool CFE_ES_CheckCDSBlockIdSlotUsed(CFE_ES_ResourceID_t CheckId) +{ + return CFE_ES_CDSBlockRecordIsUsed(CFE_ES_LocateCDSBlockRecordByID(CheckId)); +} + /*******************************************************************/ /* * CFE_ES_LocateCDSBlockRecordByID @@ -347,7 +359,7 @@ int32 CFE_ES_RegisterCDSEx(CFE_ES_CDSHandle_t *HandlePtr, size_t UserBlockSize, else { /* scan for a free slot */ - PendingBlockId = CFE_ES_FindNextAvailableId(CDS->LastCDSBlockId, CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES); + PendingBlockId = CFE_ES_FindNextAvailableId(CDS->LastCDSBlockId, CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES, CFE_ES_CheckCDSBlockIdSlotUsed); RegRecPtr = CFE_ES_LocateCDSBlockRecordByID(PendingBlockId); if (RegRecPtr != NULL) diff --git a/fsw/cfe-core/src/es/cfe_es_cds.h b/fsw/cfe-core/src/es/cfe_es_cds.h index 5b6ff3132..e0564a4be 100644 --- a/fsw/cfe-core/src/es/cfe_es_cds.h +++ b/fsw/cfe-core/src/es/cfe_es_cds.h @@ -391,6 +391,20 @@ static inline size_t CFE_ES_CDSBlockRecordGetUserSize(const CFE_ES_CDS_RegRec_t return (CDSBlockRecPtr->BlockSize - sizeof(CFE_ES_CDS_BlockHeader_t)); } +/** + * @brief Check if a CDS Block ID table slot is used + * + * Checks if a table slot is available for a potential new ID + * This is a helper function intended to be used with + * CFE_ES_FindNextAvailableID() for allocating new IDs + * + * As this dereferences fields within the record, global data must be + * locked prior to invoking this function. + * + * @param[in] CheckId pending/candidate Block ID to check + * @returns true if the table slot for the ID is occupied, false if available + */ +bool CFE_ES_CheckCDSBlockIdSlotUsed(CFE_ES_ResourceID_t CheckId); /*****************************************************************************/ /** diff --git a/fsw/cfe-core/src/es/cfe_es_mempool.c b/fsw/cfe-core/src/es/cfe_es_mempool.c index 1f32588dd..6e994aabc 100644 --- a/fsw/cfe-core/src/es/cfe_es_mempool.c +++ b/fsw/cfe-core/src/es/cfe_es_mempool.c @@ -108,12 +108,24 @@ int32 CFE_ES_MemPoolDirectCommit(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t Offs int32 CFE_ES_MemPoolID_ToIndex(CFE_ES_MemHandle_t PoolID, uint32 *Idx) { - return CFE_ES_ResourceID_ToIndex_Internal( + return CFE_ES_ResourceID_ToIndex( CFE_ES_ResourceID_ToInteger(PoolID) - CFE_ES_POOLID_BASE, CFE_PLATFORM_ES_MAX_MEMORY_POOLS, Idx); } +/*--------------------------------------------------------------------------------------- + * Function: CFE_ES_CheckMemPoolSlotUsed + * + * Purpose: Helper function, Aids in allocating a new ID by checking if + * a given table slot is available. Must be called while locked. + *--------------------------------------------------------------------------------------- + */ +bool CFE_ES_CheckMemPoolSlotUsed(CFE_ES_ResourceID_t CheckId) +{ + return CFE_ES_MemPoolRecordIsUsed(CFE_ES_LocateMemPoolRecordByID(CheckId)); +} + CFE_ES_MemPoolRecord_t* CFE_ES_LocateMemPoolRecordByID(CFE_ES_MemHandle_t PoolID) { CFE_ES_MemPoolRecord_t *MemPoolRecPtr; @@ -211,7 +223,7 @@ int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *PoolID, CFE_ES_LockSharedData(__func__,__LINE__); /* scan for a free slot */ - PendingID = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastMemPoolId, CFE_PLATFORM_ES_MAX_MEMORY_POOLS); + PendingID = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastMemPoolId, CFE_PLATFORM_ES_MAX_MEMORY_POOLS, CFE_ES_CheckMemPoolSlotUsed); PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(PendingID); if (PoolRecPtr == NULL) diff --git a/fsw/cfe-core/src/es/cfe_es_mempool.h b/fsw/cfe-core/src/es/cfe_es_mempool.h index cd4347488..247d65110 100644 --- a/fsw/cfe-core/src/es/cfe_es_mempool.h +++ b/fsw/cfe-core/src/es/cfe_es_mempool.h @@ -164,12 +164,38 @@ static inline void CFE_ES_MemPoolRecordSetFree(CFE_ES_MemPoolRecord_t *PoolRecPt PoolRecPtr->PoolID = CFE_ES_RESOURCEID_UNDEFINED; } - +/** + * @brief Check if an Mem Pool record is a match for the given Pool ID + * + * This routine confirms that the previously-located record is valid + * and matches the expected Pool ID. + * + * 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 + * @param[in] PoolID expected Pool ID + * @returns true if the entry matches the given pool ID + */ 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)); } +/** + * @brief Check if a Pool ID table slot is used + * + * Checks if a table slot is available for a potential new ID + * This is a helper function intended to be used with + * CFE_ES_FindNextAvailableID() for allocating new IDs + * + * As this dereferences fields within the record, global data must be + * locked prior to invoking this function. + * + * @param[in] CheckId pending/candidate Pool ID to check + * @returns true if the table slot for the ID is occupied, false if available + */ +bool CFE_ES_CheckMemPoolSlotUsed(CFE_ES_ResourceID_t CheckId); #endif /* _CFE_ES_MEMPOOL_H_ */ diff --git a/fsw/cfe-core/src/es/cfe_es_resource.c b/fsw/cfe-core/src/es/cfe_es_resource.c index e51867277..4035697dd 100644 --- a/fsw/cfe-core/src/es/cfe_es_resource.c +++ b/fsw/cfe-core/src/es/cfe_es_resource.c @@ -43,11 +43,11 @@ /*********************************************************************/ /* - * CFE_ES_ResourceID_ToIndex_Internal + * CFE_ES_ResourceID_ToIndex * * For complete API information, see prototype in header */ -int32 CFE_ES_ResourceID_ToIndex_Internal(uint32 Serial, uint32 TableSize, uint32 *Idx) +int32 CFE_ES_ResourceID_ToIndex(uint32 Serial, uint32 TableSize, uint32 *Idx) { if (Idx == NULL) { @@ -94,7 +94,7 @@ CFE_ES_ResourceID_t CFE_ES_ResourceID_FromOSAL(osal_id_t id) * * For complete API information, see prototype in header */ -CFE_ES_ResourceID_t CFE_ES_FindNextAvailableId(CFE_ES_ResourceID_t StartId, uint32 TableSize) +CFE_ES_ResourceID_t CFE_ES_FindNextAvailableId(CFE_ES_ResourceID_t StartId, uint32 TableSize, bool (*CheckFunc)(CFE_ES_ResourceID_t)) { uint32 Serial; uint32 Count; @@ -124,27 +124,7 @@ CFE_ES_ResourceID_t CFE_ES_FindNextAvailableId(CFE_ES_ResourceID_t StartId, uint } CheckId = CFE_ES_ResourceID_FromInteger(ResourceType + Serial); - switch (ResourceType) - { - case CFE_ES_APPID_BASE: - IsTaken = CFE_ES_AppRecordIsUsed(CFE_ES_LocateAppRecordByID(CheckId)); - break; - case CFE_ES_LIBID_BASE: - IsTaken = CFE_ES_LibRecordIsUsed(CFE_ES_LocateLibRecordByID(CheckId)); - break; - case CFE_ES_COUNTID_BASE: - IsTaken = CFE_ES_CounterRecordIsUsed(CFE_ES_LocateCounterRecordByID(CheckId)); - break; - case CFE_ES_POOLID_BASE: - IsTaken = CFE_ES_MemPoolRecordIsUsed(CFE_ES_LocateMemPoolRecordByID(CheckId)); - break; - case CFE_ES_CDSBLOCKID_BASE: - IsTaken = CFE_ES_CDSBlockRecordIsUsed(CFE_ES_LocateCDSBlockRecordByID(CheckId)); - break; - default: - /* do nothing, should never happen */ - break; - } + IsTaken = CheckFunc(CheckId); } while (IsTaken); @@ -430,4 +410,43 @@ CFE_ES_AppRecord_t *CFE_ES_GetAppRecordByContext(void) return AppRecPtr; } +/* + * --------------------------------------------------------------------------------------- + * Function: CFE_ES_CheckCounterIdSlotUsed + * + * Purpose: Helper function, Aids in allocating a new ID by checking if + * a given ID is available. Must be called while locked. + * --------------------------------------------------------------------------------------- + */ +bool CFE_ES_CheckCounterIdSlotUsed(CFE_ES_ResourceID_t CheckId) +{ + return CFE_ES_CounterRecordIsUsed(CFE_ES_LocateCounterRecordByID(CheckId)); +} + +/* + *--------------------------------------------------------------------------------------- + * Function: CFE_ES_CheckAppIdSlotUsed + * + * Purpose: Helper function, Aids in allocating a new ID by checking if + * a given ID is available. Must be called while locked. + *--------------------------------------------------------------------------------------- + */ +bool CFE_ES_CheckAppIdSlotUsed(CFE_ES_ResourceID_t CheckId) +{ + return CFE_ES_AppRecordIsUsed(CFE_ES_LocateAppRecordByID(CheckId)); +} + +/* + * --------------------------------------------------------------------------------------- + * Function: CFE_ES_CheckLibIdSlotUsed + * + * Purpose: Helper function, Aids in allocating a new ID by checking if + * a given ID is available. Must be called while locked. + * --------------------------------------------------------------------------------------- + */ +bool CFE_ES_CheckLibIdSlotUsed(CFE_ES_ResourceID_t CheckId) +{ + return CFE_ES_LibRecordIsUsed(CFE_ES_LocateLibRecordByID(CheckId)); +} + diff --git a/fsw/cfe-core/src/es/cfe_es_resource.h b/fsw/cfe-core/src/es/cfe_es_resource.h index 07af0c0cc..91f2ddeca 100644 --- a/fsw/cfe-core/src/es/cfe_es_resource.h +++ b/fsw/cfe-core/src/es/cfe_es_resource.h @@ -34,73 +34,10 @@ /* ** Include Files */ +#include "cfe_resourceid.h" +#include "private/cfe_resourceid_internal.h" #include "cfe_es_global.h" -/* -** Defines -*/ - -/* - * Limits/definitions related to CFE_ES_ResourceID_t values. - * - * Defining based on OSAL ID values makes this object a superset of - * the OSAL ID type, such that OSAL IDs can be represented as ES resource IDs - * and not conflict with/alias each other. - * - * NOTE: This reflects a bit if "inside knowledge" about how OSAL IDs are - * constructed. The overlap between OSAL IDs and ES IDs may not always be - * consistent, and they can diverge in a future version. - */ -#define CFE_ES_RESOURCEID_SHIFT OS_OBJECT_TYPE_SHIFT -#define CFE_ES_RESOURCEID_MAX ((1 << CFE_ES_RESOURCEID_SHIFT)-1) -#define CFE_ES_RESOURCEID_MARK (0x02000000) - -/** - * @defgroup CFEESResourceIDBase ES Resource ID base values - * @{ - */ -#define CFE_ES_APPID_BASE (CFE_ES_RESOURCEID_MARK | ((OS_OBJECT_TYPE_USER+1) << CFE_ES_RESOURCEID_SHIFT)) -#define CFE_ES_LIBID_BASE (CFE_ES_RESOURCEID_MARK | ((OS_OBJECT_TYPE_USER+2) << CFE_ES_RESOURCEID_SHIFT)) -#define CFE_ES_COUNTID_BASE (CFE_ES_RESOURCEID_MARK | ((OS_OBJECT_TYPE_USER+3) << CFE_ES_RESOURCEID_SHIFT)) -#define CFE_ES_POOLID_BASE (CFE_ES_RESOURCEID_MARK | ((OS_OBJECT_TYPE_USER+4) << CFE_ES_RESOURCEID_SHIFT)) -#define CFE_ES_CDSBLOCKID_BASE (CFE_ES_RESOURCEID_MARK | ((OS_OBJECT_TYPE_USER+5) << CFE_ES_RESOURCEID_SHIFT)) -/** @} */ - -/** - * @brief Get the Base value (type/category) from a resource ID value - * - * This masks out the ID serial number to obtain the base value, which is different - * for each resource type. - * - * @note The value is NOT shifted or otherwise adjusted. It should match one of the - * defined base values in @ref CFEESResourceIDBase. - * - * @param[in] ResourceId the resource ID to decode - * @returns The base value associated with that ID - */ -static inline uint32 CFE_ES_ResourceID_GetBase(CFE_ES_ResourceID_t ResourceId) -{ - uint32 ResourceType = CFE_ES_ResourceID_ToInteger(ResourceId); - return (ResourceType - (ResourceType & CFE_ES_RESOURCEID_MAX)); -} - -/** - * @brief Locate the next resource ID which does not map to an in-use table entry - * - * This begins searching from StartId which should be the most recently issued ID - * for the resource category. This will then search for the next ID which does - * _not_ map to a table entry that is in use. That is, it does not alias any - * valid ID when converted to an array index. - * - * returns an undefined ID value if no open slots are available - * - * @param[in] StartId the last issued ID for the resource category (app, lib, etc). - * @returns Next ID value which does not map to a valid entry - * @retval #CFE_ES_RESOURCEID_UNDEFINED if no open slots. - * - */ -CFE_ES_ResourceID_t CFE_ES_FindNextAvailableId(CFE_ES_ResourceID_t StartId, uint32 TableSize); - /** * @brief Locate the app table entry correlating with a given app ID. @@ -550,56 +487,6 @@ extern CFE_ES_AppRecord_t* CFE_ES_GetAppRecordByContext(void); */ extern CFE_ES_TaskRecord_t* CFE_ES_GetTaskRecordByContext(void); -/** - * @brief Convert an ES Task ID to an OSAL task ID - * - * Task IDs created via CFE ES are also OSAL task IDs, but technically - * do refer to a different scope and therefore have a different type - * to represent them. - * - * This function facilitates converting between the types. - * - * @note Currently the numeric values are the same and can be interchanged - * for backward compatibility, however they may diverge in a future version. - * New code should not assume equivalence between OSAL and ES task IDs. - * - * @sa CFE_ES_ResourceID_FromOSAL - * - * @param[in] id The ES task ID - * @returns The OSAL task ID - */ -osal_id_t CFE_ES_ResourceID_ToOSAL(CFE_ES_ResourceID_t id); - -/** - * @brief Convert an ES Task ID to an OSAL task ID - * - * Task IDs created via CFE ES are also OSAL task IDs, but technically - * do refer to a different scope and therefore have a different type - * to represent them. - * - * This function facilitates converting between the types. - * - * @note Currently the numeric values are the same and can be interchanged - * for backward compatibility, however they may diverge in a future version. - * New code should not assume equivalence between OSAL and ES task IDs. - * - * @sa CFE_ES_ResourceID_ToOSAL - * - * @param[in] id The OSAL task ID - * @returns The ES task ID - */ -CFE_ES_ResourceID_t CFE_ES_ResourceID_FromOSAL(osal_id_t id); - -/** - * @brief Internal routine to aid in converting an ES resource ID to an array index - - * @param[in] Serial The resource serial number (type info masked out) - * @param[in] TableSize The size of the internal table (MAX value) - * @param[out] Idx The output index - * @returns Status code, CFE_SUCCESS if successful. - */ -int32 CFE_ES_ResourceID_ToIndex_Internal(uint32 Serial, uint32 TableSize, uint32 *Idx); - /* * Internal functions to perform name based resource lookups * @@ -611,5 +498,10 @@ CFE_ES_LibRecord_t *CFE_ES_LocateLibRecordByName(const char *Name); CFE_ES_TaskRecord_t *CFE_ES_LocateTaskRecordByName(const char *Name); CFE_ES_GenCounterRecord_t *CFE_ES_LocateCounterRecordByName(const char *Name); +/* Availability check functions used in conjunction with CFE_ES_FindNextAvailableId() */ +bool CFE_ES_CheckAppIdSlotUsed(CFE_ES_ResourceID_t CheckId); +bool CFE_ES_CheckLibIdSlotUsed(CFE_ES_ResourceID_t CheckId); +bool CFE_ES_CheckCounterIdSlotUsed(CFE_ES_ResourceID_t CheckId); + #endif /* CFE_ES_RESOURCE_H */ diff --git a/fsw/cfe-core/src/es/cfe_es_start.c b/fsw/cfe-core/src/es/cfe_es_start.c index 560fc259d..43689cb6a 100644 --- a/fsw/cfe-core/src/es/cfe_es_start.c +++ b/fsw/cfe-core/src/es/cfe_es_start.c @@ -759,7 +759,7 @@ void CFE_ES_CreateObjects(void) */ CFE_ES_LockSharedData(__func__,__LINE__); - PendingAppId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastAppId, CFE_PLATFORM_ES_MAX_APPLICATIONS); + PendingAppId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastAppId, CFE_PLATFORM_ES_MAX_APPLICATIONS, CFE_ES_CheckAppIdSlotUsed); AppRecPtr = CFE_ES_LocateAppRecordByID(PendingAppId); if (AppRecPtr != NULL) { diff --git a/fsw/cfe-core/src/inc/cfe_es.h b/fsw/cfe-core/src/inc/cfe_es.h index 244a76510..b42457ac6 100644 --- a/fsw/cfe-core/src/inc/cfe_es.h +++ b/fsw/cfe-core/src/inc/cfe_es.h @@ -43,6 +43,7 @@ #include "cfe_mission_cfg.h" #include "cfe_perfids.h" #include "cfe_error.h" +#include "cfe_resourceid.h" /*****************************************************************************/ @@ -64,32 +65,6 @@ #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. */ -/** \name Resource ID predefined values */ -/** \{ */ - -/** - * @brief A resource ID value that represents an undefined/unused resource - * - * This constant may be used to initialize local variables of the - * CFE_ES_ResourceID_t type to a safe value that will not alias a valid ID. - * - * By design, this value is also the result of zeroing a CFE_ES_ResourceID_t - * type via standard functions like memset(), such that objects initialized - * using this method will also be set to safe values. - */ -#define CFE_ES_RESOURCEID_UNDEFINED ((CFE_ES_ResourceID_t)0) - -/** - * @brief A resource ID value that represents a reserved entry - * - * This is not a valid value for any resource type, but is used to mark - * table entries that are not available for use. For instance, this may - * be used while setting up an entry initially. - */ -#define CFE_ES_RESOURCEID_RESERVED ((CFE_ES_ResourceID_t)0xFFFFFFFF) - -/** \} */ - /* ** Note about reset type and subtypes: ** @@ -214,82 +189,6 @@ typedef void* CFE_ES_MemPoolBuf_t; * @{ */ -/** - * @brief Convert a resource ID to an integer. - * - * This is primarily intended for logging purposes, such was writing - * to debug console, event messages, or log files, using printf-like APIs. - * - * For compatibility with C library APIs, this returns an "unsigned long" - * type and should be used with the "%lx" format specifier in a printf - * format string. - * - * @note No assumptions should be made about the actual integer value, - * such as its base/range. It may be printed, but should not be modified - * or tested/compared using other arithmetic ops, and should never be used - * as the index to an array or table. See the related function - * CFE_ES_ResourceID_ToIndex() for cases where a zero-based array/table index - * is needed. - * - * @sa CFE_ES_ResourceID_FromInteger() - * - * @param[in] id Resource ID to convert - * @returns Integer value corresponding to ID - */ -static inline unsigned long CFE_ES_ResourceID_ToInteger(CFE_ES_ResourceID_t id) -{ - return ((unsigned long)id); -} - -/** - * @brief Convert an integer to a resource ID. - * - * This is the inverse of CFE_ES_ResourceID_ToInteger(), and reconstitutes - * the original CFE_ES_ResourceID_t value from the integer representation. - * - * This may be used, for instance, where an ID value is parsed from a text - * file or message using C library APIs such as scanf() or strtoul(). - * - * @sa CFE_ES_ResourceID_ToInteger() - * - * @param[in] Value Integer value to convert - * @returns ID value corresponding to integer - */ -static inline CFE_ES_ResourceID_t CFE_ES_ResourceID_FromInteger(unsigned long Value) -{ - return ((CFE_ES_ResourceID_t)Value); -} - -/** - * @brief Compare two Resource ID values for equality - * - * @param[in] id1 Resource ID to check - * @param[in] id2 Resource ID to check - * @returns true if id1 and id2 are equal, false otherwise. - */ -static inline bool CFE_ES_ResourceID_Equal(CFE_ES_ResourceID_t id1, CFE_ES_ResourceID_t id2) -{ - return (id1 == id2); -} - -/** - * @brief Check if a resource ID value is defined - * - * The constant #CFE_ES_RESOURCEID_UNDEFINED represents an undefined ID value, - * such that the expression: - * - * CFE_ES_ResourceID_IsDefined(CFE_ES_RESOURCEID_UNDEFINED) - * - * Always returns false. - * - * @param[in] id Resource ID to check - * @returns True if the ID may refer to a defined entity, false if invalid/undefined. - */ -static inline bool CFE_ES_ResourceID_IsDefined(CFE_ES_ResourceID_t id) -{ - return (id != 0); -} - /** * @brief Obtain an index value correlating to an ES Application ID * diff --git a/fsw/cfe-core/src/inc/cfe_resourceid.h b/fsw/cfe-core/src/inc/cfe_resourceid.h new file mode 100644 index 000000000..199554539 --- /dev/null +++ b/fsw/cfe-core/src/inc/cfe_resourceid.h @@ -0,0 +1,150 @@ +/* +** 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_resourceid.h + * + * Contains global prototypes and definitions related to resource + * management and related CFE resource IDs. + * + * A CFE ES Resource ID is a common way to identify CFE-managed resources such + * as apps, tasks, counters, memory pools, CDS blocks, and other entities. + */ + +#ifndef CFE_RESOURCEID_H +#define CFE_RESOURCEID_H + +/* +** Include Files +** +** The actual CFE_ES_ResourceID_t type is part of the ES global/extern typedefs, +** as the concept originated in ES and has been extended across all of CFE. +*/ +#include "cfe_es_extern_typedefs.h" + +/* +** Defines +*/ + +/** \name Resource ID predefined values */ +/** \{ */ + +/** + * @brief A resource ID value that represents an undefined/unused resource + * + * This constant may be used to initialize local variables of the + * CFE_ES_ResourceID_t type to a safe value that will not alias a valid ID. + * + * By design, this value is also the result of zeroing a CFE_ES_ResourceID_t + * type via standard functions like memset(), such that objects initialized + * using this method will also be set to safe values. + */ +#define CFE_ES_RESOURCEID_UNDEFINED ((CFE_ES_ResourceID_t){0}) + +/** + * @brief A resource ID value that represents a reserved entry + * + * This is not a valid value for any resource type, but is used to mark + * table entries that are not available for use. For instance, this may + * be used while setting up an entry initially. + */ +#define CFE_ES_RESOURCEID_RESERVED ((CFE_ES_ResourceID_t){0xFFFFFFFF}) + +/** \} */ + + +/** + * @brief Convert a resource ID to an integer. + * + * This is primarily intended for logging purposes, such was writing + * to debug console, event messages, or log files, using printf-like APIs. + * + * For compatibility with C library APIs, this returns an "unsigned long" + * type and should be used with the "%lx" format specifier in a printf + * format string. + * + * @note No assumptions should be made about the actual integer value, + * such as its base/range. It may be printed, but should not be modified + * or tested/compared using other arithmetic ops, and should never be used + * as the index to an array or table. See the related function + * CFE_ES_ResourceID_ToIndex() for cases where a zero-based array/table index + * is needed. + * + * @sa CFE_ES_ResourceID_FromInteger() + * + * @param[in] id Resource ID to convert + * @returns Integer value corresponding to ID + */ +static inline unsigned long CFE_ES_ResourceID_ToInteger(CFE_ES_ResourceID_t id) +{ + return ((unsigned long)id); +} + +/** + * @brief Convert an integer to a resource ID. + * + * This is the inverse of CFE_ES_ResourceID_ToInteger(), and reconstitutes + * the original CFE_ES_ResourceID_t value from the integer representation. + * + * This may be used, for instance, where an ID value is parsed from a text + * file or message using C library APIs such as scanf() or strtoul(). + * + * @sa CFE_ES_ResourceID_ToInteger() + * + * @param[in] Value Integer value to convert + * @returns ID value corresponding to integer + */ +static inline CFE_ES_ResourceID_t CFE_ES_ResourceID_FromInteger(unsigned long Value) +{ + return ((CFE_ES_ResourceID_t)Value); +} + +/** + * @brief Compare two Resource ID values for equality + * + * @param[in] id1 Resource ID to check + * @param[in] id2 Resource ID to check + * @returns true if id1 and id2 are equal, false otherwise. + */ +static inline bool CFE_ES_ResourceID_Equal(CFE_ES_ResourceID_t id1, CFE_ES_ResourceID_t id2) +{ + return (id1 == id2); +} + +/** + * @brief Check if a resource ID value is defined + * + * The constant #CFE_ES_RESOURCEID_UNDEFINED represents an undefined ID value, + * such that the expression: + * + * CFE_ES_ResourceID_IsDefined(CFE_ES_RESOURCEID_UNDEFINED) + * + * Always returns false. + * + * @param[in] id Resource ID to check + * @returns True if the ID may refer to a defined entity, false if invalid/undefined. + */ +static inline bool CFE_ES_ResourceID_IsDefined(CFE_ES_ResourceID_t id) +{ + return (id != 0); +} + + +#endif /* CFE_RESOURCEID_H */ diff --git a/fsw/cfe-core/src/inc/private/cfe_resourceid_internal.h b/fsw/cfe-core/src/inc/private/cfe_resourceid_internal.h new file mode 100644 index 000000000..614bbe76f --- /dev/null +++ b/fsw/cfe-core/src/inc/private/cfe_resourceid_internal.h @@ -0,0 +1,160 @@ +/* +** 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_resourceid_internal.h + * + * Contains CFE internal prototypes and definitions related to resource + * management and related CFE resource IDs. + * + * A CFE ES Resource ID is a common way to identify CFE-managed resources such + * as apps, tasks, counters, memory pools, CDS blocks, and other entities. + */ + +#ifndef CFE_RESOURCEID_INTERNAL_H +#define CFE_RESOURCEID_INTERNAL_H + +/* +** Include Files +*/ +#include "cfe_resourceid.h" +#include "osapi-idmap.h" + +/* +** Defines +*/ + +/* + * Limits/definitions related to CFE_ES_ResourceID_t values. + * + * Defining based on OSAL ID values makes this object a superset of + * the OSAL ID type, such that OSAL IDs can be represented as ES resource IDs + * and not conflict with/alias each other. + * + * NOTE: This reflects a bit if "inside knowledge" about how OSAL IDs are + * constructed. The overlap between OSAL IDs and ES IDs may not always be + * consistent, and they can diverge in a future version. + */ +#define CFE_ES_RESOURCEID_SHIFT OS_OBJECT_TYPE_SHIFT +#define CFE_ES_RESOURCEID_MAX ((1 << CFE_ES_RESOURCEID_SHIFT)-1) +#define CFE_ES_RESOURCEID_MARK (0x02000000) + +/** + * @defgroup CFEResourceIDBase Resource ID base values + * @{ + */ +#define CFE_ES_APPID_BASE (CFE_ES_RESOURCEID_MARK | ((OS_OBJECT_TYPE_USER+1) << CFE_ES_RESOURCEID_SHIFT)) +#define CFE_ES_LIBID_BASE (CFE_ES_RESOURCEID_MARK | ((OS_OBJECT_TYPE_USER+2) << CFE_ES_RESOURCEID_SHIFT)) +#define CFE_ES_COUNTID_BASE (CFE_ES_RESOURCEID_MARK | ((OS_OBJECT_TYPE_USER+3) << CFE_ES_RESOURCEID_SHIFT)) +#define CFE_ES_POOLID_BASE (CFE_ES_RESOURCEID_MARK | ((OS_OBJECT_TYPE_USER+4) << CFE_ES_RESOURCEID_SHIFT)) +#define CFE_ES_CDSBLOCKID_BASE (CFE_ES_RESOURCEID_MARK | ((OS_OBJECT_TYPE_USER+5) << CFE_ES_RESOURCEID_SHIFT)) + +/** @} */ + + +/** + * @brief Get the Base value (type/category) from a resource ID value + * + * This masks out the ID serial number to obtain the base value, which is different + * for each resource type. + * + * @note The value is NOT shifted or otherwise adjusted. It should match one of the + * defined base values in @ref CFEESResourceIDBase. + * + * @param[in] ResourceId the resource ID to decode + * @returns The base value associated with that ID + */ +static inline uint32 CFE_ES_ResourceID_GetBase(CFE_ES_ResourceID_t ResourceId) +{ + uint32 ResourceType = CFE_ES_ResourceID_ToInteger(ResourceId); + return (ResourceType - (ResourceType & CFE_ES_RESOURCEID_MAX)); +} + +/** + * @brief Locate the next resource ID which does not map to an in-use table entry + * + * This begins searching from StartId which should be the most recently issued ID + * for the resource category. This will then search for the next ID which does + * _not_ map to a table entry that is in use. That is, it does not alias any + * valid ID when converted to an array index. + * + * returns an undefined ID value if no open slots are available + * + * @param[in] StartId the last issued ID for the resource category (app, lib, etc). + * @param[in] TableSize the maximum size of the target table + * @param[in] CheckFunc a function to check if the given ID is available + * @returns Next ID value which does not map to a valid entry + * @retval #CFE_ES_RESOURCEID_UNDEFINED if no open slots. + * + */ +CFE_ES_ResourceID_t CFE_ES_FindNextAvailableId(CFE_ES_ResourceID_t StartId, uint32 TableSize, bool (*CheckFunc)(CFE_ES_ResourceID_t) ); + +/** + * @brief Convert an ES Task ID to an OSAL task ID + * + * Task IDs created via CFE ES are also OSAL task IDs, but technically + * do refer to a different scope and therefore have a different type + * to represent them. + * + * This function facilitates converting between the types. + * + * @note Currently the numeric values are the same and can be interchanged + * for backward compatibility, however they may diverge in a future version. + * New code should not assume equivalence between OSAL and ES task IDs. + * + * @sa CFE_ES_ResourceID_FromOSAL + * + * @param[in] id The ES task ID + * @returns The OSAL task ID + */ +osal_id_t CFE_ES_ResourceID_ToOSAL(CFE_ES_ResourceID_t id); + +/** + * @brief Convert an ES Task ID to an OSAL task ID + * + * Task IDs created via CFE ES are also OSAL task IDs, but technically + * do refer to a different scope and therefore have a different type + * to represent them. + * + * This function facilitates converting between the types. + * + * @note Currently the numeric values are the same and can be interchanged + * for backward compatibility, however they may diverge in a future version. + * New code should not assume equivalence between OSAL and ES task IDs. + * + * @sa CFE_ES_ResourceID_ToOSAL + * + * @param[in] id The OSAL task ID + * @returns The ES task ID + */ +CFE_ES_ResourceID_t CFE_ES_ResourceID_FromOSAL(osal_id_t id); + +/** + * @brief Internal routine to aid in converting an ES resource ID to an array index + + * @param[in] Serial The resource serial number (type info masked out) + * @param[in] TableSize The size of the internal table (MAX value) + * @param[out] Idx The output index + * @returns Status code, CFE_SUCCESS if successful. + */ +int32 CFE_ES_ResourceID_ToIndex(uint32 Serial, uint32 TableSize, uint32 *Idx); + + +#endif /* CFE_RESOURCEID_H */ diff --git a/fsw/cfe-core/unit-test/es_UT.c b/fsw/cfe-core/unit-test/es_UT.c index bff84dc8b..cda38c3f2 100644 --- a/fsw/cfe-core/unit-test/es_UT.c +++ b/fsw/cfe-core/unit-test/es_UT.c @@ -2139,6 +2139,12 @@ void TestApps(void) } +static bool ES_UT_CheckIdSlotUsed(CFE_ES_ResourceID_t Id) +{ + return UT_DEFAULT_IMPL(ES_UT_CheckIdSlotUsed) != 0; +} + + void TestResourceID(void) { /* @@ -2151,15 +2157,17 @@ void TestResourceID(void) /* Call CFE_ES_FindNextAvailableId() using an invalid resource type */ ES_ResetUnitTest(); - Id = CFE_ES_FindNextAvailableId(CFE_ES_RESOURCEID_UNDEFINED, 5); + UT_SetDefaultReturnValue(UT_KEY(ES_UT_CheckIdSlotUsed), 1); + Id = CFE_ES_FindNextAvailableId(CFE_ES_RESOURCEID_UNDEFINED, 5, ES_UT_CheckIdSlotUsed); UtAssert_True(!CFE_ES_ResourceID_IsDefined(Id), "CFE_ES_FindNextAvailableId() on undefined resource type"); /* Verify that CFE_ES_FindNextAvailableId() does not repeat until CFE_ES_RESOURCEID_MAX is reached */ + UT_SetDefaultReturnValue(UT_KEY(ES_UT_CheckIdSlotUsed), 0); LastId = CFE_ES_Global.LastAppId; Count = CFE_ES_RESOURCEID_MAX-1; while (Count > 0) { - Id = CFE_ES_FindNextAvailableId(LastId, CFE_PLATFORM_ES_MAX_APPLICATIONS); + Id = CFE_ES_FindNextAvailableId(LastId, CFE_PLATFORM_ES_MAX_APPLICATIONS, ES_UT_CheckIdSlotUsed); if (CFE_ES_ResourceID_ToInteger(Id) - CFE_ES_ResourceID_ToInteger(LastId) != 1) { /* Numbers should be incrementing by 1 each time, never decreasing */ @@ -2172,7 +2180,7 @@ void TestResourceID(void) UtAssert_True(Count == 0, "CFE_ES_FindNextAvailableId() allocate all resource ID space"); /* Now verify that CFE_ES_FindNextAvailableId() recycles the first item again */ - Id = CFE_ES_FindNextAvailableId(LastId, CFE_PLATFORM_ES_MAX_APPLICATIONS); + Id = CFE_ES_FindNextAvailableId(LastId, CFE_PLATFORM_ES_MAX_APPLICATIONS, ES_UT_CheckIdSlotUsed); UtAssert_True(CFE_ES_ResourceID_IsDefined(Id), "CFE_ES_FindNextAvailableId() after wrap"); UtAssert_True(CFE_ES_ResourceID_ToInteger(Id) < (CFE_ES_APPID_BASE + CFE_PLATFORM_ES_MAX_APPLICATIONS), "CFE_ES_FindNextAvailableId() wrap ID"); } diff --git a/fsw/cfe-core/ut-stubs/ut_es_stubs.c b/fsw/cfe-core/ut-stubs/ut_es_stubs.c index 6f7ad94e7..e6dabf5b6 100644 --- a/fsw/cfe-core/ut-stubs/ut_es_stubs.c +++ b/fsw/cfe-core/ut-stubs/ut_es_stubs.c @@ -1320,3 +1320,49 @@ int32 CFE_ES_TaskID_ToIndex(CFE_ES_ResourceID_t TaskID, uint32 *Idx) return return_code; } + +CFE_ES_ResourceID_t CFE_ES_FindNextAvailableId(CFE_ES_ResourceID_t StartId, uint32 TableSize, bool (*CheckFunc)(CFE_ES_ResourceID_t)) +{ + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_FindNextAvailableId), StartId); + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_FindNextAvailableId), TableSize); + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_FindNextAvailableId), CheckFunc); + + int32 return_code; + + /* Using "1" by default here produces a sequential result when called multiple times */ + return_code = UT_DEFAULT_IMPL_RC(CFE_ES_FindNextAvailableId, 1); + + if (return_code < 0) + { + return CFE_ES_RESOURCEID_UNDEFINED; + } + + /* + * The test case may set the return code to indicate the offset from the start ID + */ + return CFE_ES_ResourceID_FromInteger(CFE_ES_ResourceID_ToInteger(StartId) + return_code); +} + +int32 CFE_ES_ResourceID_ToIndex(uint32 Serial, uint32 TableSize, uint32 *Idx) +{ + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_ResourceID_ToIndex), Serial); + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_ResourceID_ToIndex), TableSize); + UT_Stub_RegisterContextGenericArg(UT_KEY(CFE_ES_ResourceID_ToIndex), Idx); + + int32 return_code; + + return_code = UT_DEFAULT_IMPL(CFE_ES_ResourceID_ToIndex); + + if (return_code < 0) + { + /* fill with a very bad value that should cause a problem if used */ + *Idx = 0xDEADBEEF; + } + else if (UT_Stub_CopyToLocal(UT_KEY(CFE_ES_ResourceID_ToIndex), Idx, sizeof(*Idx)) < sizeof(*Idx)) + { + /* fill with default value if unspecified by test case */ + *Idx = Serial % TableSize; + } + + return return_code; +}