From c27f114d1021f6d1a871e9742c3efec964b13183 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Thu, 18 Apr 2024 10:52:32 -0400 Subject: [PATCH] Fix #2550, Use resource ID for dump control index Use a resourceID value for access into the dump control structure array. This allows for consistent lookup, matching, and free/in-use determination, as well as improved resilience to race conditions and stale data. --- .../fsw/inc/cfe_core_resourceid_basevalues.h | 2 + modules/tbl/fsw/src/cfe_tbl_api.c | 48 ++-- modules/tbl/fsw/src/cfe_tbl_internal.c | 17 +- modules/tbl/fsw/src/cfe_tbl_resource.c | 66 +++++ modules/tbl/fsw/src/cfe_tbl_resource.h | 183 +++++++++++++- modules/tbl/fsw/src/cfe_tbl_task.h | 45 ++-- modules/tbl/fsw/src/cfe_tbl_task_cmds.c | 82 +++--- modules/tbl/fsw/src/cfe_tbl_transaction.c | 2 +- modules/tbl/ut-coverage/tbl_UT.c | 235 ++++++++++++------ modules/tbl/ut-coverage/tbl_UT.h | 1 + 10 files changed, 496 insertions(+), 185 deletions(-) diff --git a/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h b/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h index 443136be6..a2011ba51 100644 --- a/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h +++ b/modules/resourceid/fsw/inc/cfe_core_resourceid_basevalues.h @@ -73,6 +73,7 @@ enum /* TBL managed resources */ CFE_RESOURCEID_TBL_VALRESULTID_BASE_OFFSET = OS_OBJECT_TYPE_USER + 8, + CFE_RESOURCEID_TBL_DUMPCTRLID_BASE_OFFSET = OS_OBJECT_TYPE_USER + 9, }; @@ -99,6 +100,7 @@ enum /* TBL managed resources */ CFE_TBL_VALRESULTID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_TBL_VALRESULTID_BASE_OFFSET), + CFE_TBL_DUMPCTRLID_BASE = CFE_RESOURCEID_MAKE_BASE(CFE_RESOURCEID_TBL_DUMPCTRLID_BASE_OFFSET), }; diff --git a/modules/tbl/fsw/src/cfe_tbl_api.c b/modules/tbl/fsw/src/cfe_tbl_api.c index e63252ef8..92dc8933c 100644 --- a/modules/tbl/fsw/src/cfe_tbl_api.c +++ b/modules/tbl/fsw/src/cfe_tbl_api.c @@ -1096,7 +1096,7 @@ CFE_Status_t CFE_TBL_DumpToBuffer(CFE_TBL_Handle_t TblHandle) int32 Status; CFE_TBL_RegistryRec_t *RegRecPtr = NULL; CFE_TBL_DumpControl_t *DumpCtrlPtr = NULL; - CFE_ES_AppId_t ThisAppId; + CFE_TBL_LoadBuff_t * ActiveBufPtr; Status = CFE_TBL_TxnStartFromHandle(&Txn, TblHandle, CFE_TBL_TxnContext_ACCESSOR_APP); @@ -1104,36 +1104,34 @@ CFE_Status_t CFE_TBL_DumpToBuffer(CFE_TBL_Handle_t TblHandle) { Status = CFE_TBL_TxnGetTableStatus(&Txn); - RegRecPtr = CFE_TBL_TxnRegRec(&Txn); - - CFE_TBL_TxnFinish(&Txn); - } - else - { - ThisAppId = CFE_TBL_TxnAppId(&Txn); - - CFE_ES_WriteToSysLog("%s: App(%lu) does not have access to Tbl Handle=%d\n", __func__, - CFE_RESOURCEID_TO_ULONG(ThisAppId), (int)TblHandle); - } + /* Make sure the table has been requested to be dumped */ + if (Status == CFE_TBL_INFO_DUMP_PENDING) + { + RegRecPtr = CFE_TBL_TxnRegRec(&Txn); + DumpCtrlPtr = CFE_TBL_LocateDumpCtrlByID(RegRecPtr->DumpControlId); + ActiveBufPtr = CFE_TBL_GetActiveBuffer(RegRecPtr); - /* Make sure the table has been requested to be dumped */ - if (Status == CFE_TBL_INFO_DUMP_PENDING) - { - DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[RegRecPtr->DumpControlIndex]; + /* Copy the contents of the active buffer to the assigned dump buffer */ + memcpy(DumpCtrlPtr->DumpBufferPtr->BufferPtr, ActiveBufPtr->BufferPtr, DumpCtrlPtr->Size); - /* Copy the contents of the active buffer to the assigned dump buffer */ - memcpy(DumpCtrlPtr->DumpBufferPtr->BufferPtr, RegRecPtr->Buffers[0].BufferPtr, DumpCtrlPtr->Size); + /* Save the current time so that the header in the dump file can have the correct time */ + DumpCtrlPtr->DumpBufferPtr->FileTime = CFE_TIME_GetTime(); - /* Save the current time so that the header in the dump file can have the correct time */ - DumpCtrlPtr->DumpBufferPtr->FileTime = CFE_TIME_GetTime(); + /* Disassociate the dump request from the table */ + RegRecPtr->DumpControlId = CFE_TBL_NO_DUMP_PENDING; - /* Disassociate the dump request from the table */ - RegRecPtr->DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; + /* Notify the Table Services Application that the dump buffer is ready to be written to a file */ + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; - /* Notify the Table Services Application that the dump buffer is ready to be written to a file */ - DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; + Status = CFE_SUCCESS; + } - Status = CFE_SUCCESS; + CFE_TBL_TxnFinish(&Txn); + } + else + { + CFE_ES_WriteToSysLog("%s: App(%lu) does not have access to Tbl Handle=%lu\n", __func__, + CFE_TBL_TxnAppIdAsULong(&Txn), CFE_TBL_TxnHandleAsULong(&Txn)); } return Status; diff --git a/modules/tbl/fsw/src/cfe_tbl_internal.c b/modules/tbl/fsw/src/cfe_tbl_internal.c index 76053e463..fe736b0df 100644 --- a/modules/tbl/fsw/src/cfe_tbl_internal.c +++ b/modules/tbl/fsw/src/cfe_tbl_internal.c @@ -92,8 +92,6 @@ int32 CFE_TBL_EarlyInit(void) /* Initialize the Dump-Only Table Dump Control Blocks nonzero values */ for (i = 0; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { - CFE_TBL_Global.DumpControlBlocks[i].State = CFE_TBL_DUMP_FREE; - /* Prevent Shared Buffers from being used until successfully allocated */ CFE_TBL_Global.LoadBuffs[i].Taken = true; } @@ -223,7 +221,7 @@ void CFE_TBL_InitRegistryRecord(CFE_TBL_RegistryRec_t *RegRecPtr) RegRecPtr->ValidateActiveId = CFE_TBL_NO_VALIDATION_PENDING; RegRecPtr->ValidateInactiveId = CFE_TBL_NO_VALIDATION_PENDING; RegRecPtr->CDSHandle = CFE_ES_CDS_BAD_HANDLE; - RegRecPtr->DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; + RegRecPtr->DumpControlId = CFE_TBL_NO_DUMP_PENDING; CFE_TBL_HandleLinkInit(&RegRecPtr->AccessList); } @@ -1021,19 +1019,22 @@ void CFE_TBL_ByteSwapUint32(uint32 *Uint32ToSwapPtr) *-----------------------------------------------------------------*/ int32 CFE_TBL_CleanUpApp(CFE_ES_AppId_t AppId) { - uint32 i; - CFE_TBL_TxnState_t Txn; + uint32 i; + CFE_TBL_TxnState_t Txn; + CFE_TBL_DumpControl_t *DumpCtrlPtr; /* Scan Dump Requests to determine if any of the tables that */ /* were to be dumped will be deleted */ for (i = 0; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { + DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[i]; + /* Check to see if the table to be dumped is owned by the App to be deleted */ - if ((CFE_TBL_Global.DumpControlBlocks[i].State != CFE_TBL_DUMP_FREE) && - CFE_RESOURCEID_TEST_EQUAL(CFE_TBL_Global.DumpControlBlocks[i].RegRecPtr->OwnerAppId, AppId)) + if (CFE_TBL_DumpCtrlBlockIsUsed(DumpCtrlPtr) && + CFE_RESOURCEID_TEST_EQUAL(DumpCtrlPtr->RegRecPtr->OwnerAppId, AppId)) { /* If so, then remove the dump request */ - CFE_TBL_Global.DumpControlBlocks[i].State = CFE_TBL_DUMP_FREE; + CFE_TBL_DumpCtrlBlockSetFree(DumpCtrlPtr); } } diff --git a/modules/tbl/fsw/src/cfe_tbl_resource.c b/modules/tbl/fsw/src/cfe_tbl_resource.c index 06e90b987..23275fa8e 100644 --- a/modules/tbl/fsw/src/cfe_tbl_resource.c +++ b/modules/tbl/fsw/src/cfe_tbl_resource.c @@ -52,6 +52,18 @@ CFE_Status_t CFE_TBL_Handle_ToIndex(CFE_TBL_Handle_t TblHandle, uint32 *Idx) return CFE_SUCCESS; } +/*---------------------------------------------------------------- + * + * Implemented per public API + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_Status_t CFE_TBL_DumpCtrlId_ToIndex(CFE_TBL_DumpCtrlId_t DumpCtrlId, uint32 *Idx) +{ + return CFE_ResourceId_ToIndex(CFE_RESOURCEID_UNWRAP(DumpCtrlId), CFE_TBL_DUMPCTRLID_BASE, + CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS, Idx); +} + /*---------------------------------------------------------------- * * Implemented per public API @@ -152,6 +164,60 @@ CFE_TBL_Handle_t CFE_TBL_AccessDescriptorGetHandle(const CFE_TBL_AccessDescripto return (AccessDescPtr - CFE_TBL_Global.Handles); } +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_TBL_DumpControl_t *CFE_TBL_LocateDumpCtrlByID(CFE_TBL_DumpCtrlId_t BlockId) +{ + CFE_TBL_DumpControl_t *BlockPtr; + uint32 Idx; + + if (CFE_TBL_DumpCtrlId_ToIndex(BlockId, &Idx) == CFE_SUCCESS) + { + BlockPtr = &CFE_TBL_Global.DumpControlBlocks[Idx]; + } + else + { + BlockPtr = NULL; + } + + return BlockPtr; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +bool CFE_TBL_CheckDumpCtrlSlotUsed(CFE_ResourceId_t CheckId) +{ + CFE_TBL_DumpControl_t *BlockPtr; + + /* + * Note - The pointer here should never be NULL because the ID should always be + * within the expected range, but if it ever is NULL, this should return true + * such that the caller will _not_ attempt to use the record. + */ + BlockPtr = CFE_TBL_LocateDumpCtrlByID(CFE_TBL_DUMPCTRLID_C(CheckId)); + return (BlockPtr == NULL || CFE_TBL_DumpCtrlBlockIsUsed(BlockPtr)); +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_ResourceId_t CFE_TBL_GetNextDumpCtrlBlock(void) +{ + return CFE_ResourceId_FindNext(CFE_TBL_Global.LastDumpCtrlBlockId, CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS, + CFE_TBL_CheckDumpCtrlSlotUsed); +} + /*---------------------------------------------------------------- * * Application-scope internal function diff --git a/modules/tbl/fsw/src/cfe_tbl_resource.h b/modules/tbl/fsw/src/cfe_tbl_resource.h index 5eba6922b..7217b1684 100644 --- a/modules/tbl/fsw/src/cfe_tbl_resource.h +++ b/modules/tbl/fsw/src/cfe_tbl_resource.h @@ -112,7 +112,7 @@ CFE_TBL_ValidationResult_t *CFE_TBL_LocateValidationResultByID(CFE_TBL_Validatio * Calculates the array position/index of the global array entry for * the given result ID. * - * @param[in] BlockID the ID/handle of the validation result block to retrieve + * @param[in] ValResultId the ID of the validation result entry to retrieve * @param[out] Idx Output buffer to store the index * @returns #CFE_SUCCESS if conversion successful. @copydoc CFE_SUCCESS * #CFE_ES_ERR_RESOURCEID_NOT_VALID if ID is outside valid range @@ -242,6 +242,187 @@ CFE_ResourceId_t CFE_TBL_GetNextValResultBlock(void); */ bool CFE_TBL_CheckValidationResultSlotUsed(CFE_ResourceId_t CheckId); +/* + * --------------------------------------------------------------------------------------- + * + * ~~~ DUMP CONTROL BLOCK ACCESSORS ~~~ + * + * These operate on CFE_TBL_DumpControl_t* and CFE_TBL_DumpCtrlId_t types + * + * --------------------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Get the array index correlating with a Dump Control Block ID + * + * Calculates the array position/index of the global array entry for + * the given block ID. + * + * @param[in] DumpCtrlId the ID/handle of the control block to retrieve + * @param[out] Idx Output buffer to store the index + * @returns #CFE_SUCCESS if conversion successful. @copydoc CFE_SUCCESS + * #CFE_ES_ERR_RESOURCEID_NOT_VALID if ID is outside valid range + */ +CFE_Status_t CFE_TBL_DumpCtrlId_ToIndex(CFE_TBL_DumpCtrlId_t DumpCtrlId, uint32 *Idx); + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Locate the registry table entry correlating with a given registry ID. + * + * This only returns a pointer to the table entry where the record + * should reside, but does _not_ actually check/validate the entry. + * + * If the passed-in ID parameter is not within the acceptable range of ID + * values for applications, such that it could never be valid under + * any circumstances, then NULL is returned. Otherwise, a pointer to the + * corresponding table entry is returned, indicating the location where + * that ID should reside, if it is currently in use. + * + * @note This only returns where the ID should reside, not that it actually + * resides there. If looking up an existing ID, then caller must additionally + * confirm that the returned record is a match to the expected ID before using + * or modifying the data within the returned record pointer. + * + * The CFE_TBL_DumpCtrlBlockIsMatch() function can be used to check/confirm + * if the returned table entry is a positive match for the given ID. + * + * @sa CFE_TBL_DumpCtrlBlockIsMatch() + * + * @param[in] BlockId the block ID to locate + * @return pointer to dump control block for the given ID, or NULL if out of range + */ +CFE_TBL_DumpControl_t *CFE_TBL_LocateDumpCtrlByID(CFE_TBL_DumpCtrlId_t BlockId); + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Check if a dump control block is a match for the given ID + * + * This routine confirms that the previously-located block pointer is valid + * and matches the expected block ID. + * + * As this dereferences fields within the record, global data must be + * locked prior to invoking this function. + * + * This function may be used in conjunction with CFE_TBL_LocateDumpCtrlByID() + * to confirm that the located record is a positive match to the expected ID. + * As such, the record pointer is also permitted to be NULL, to alleviate the + * need for the caller to handle this possibility explicitly. + * + * Once a record pointer has been successfully validated using this routine, + * it may be safely passed to all other internal functions. + * + * @sa CFE_TBL_LocateDumpCtrlByID + * + * @param[in] BlockPtr pointer to validation result table entry, or NULL + * @param[in] BlockId expected validation result ID + * @returns true if the entry matches the given ID + */ +static inline bool CFE_TBL_DumpCtrlBlockIsMatch(const CFE_TBL_DumpControl_t *BlockPtr, CFE_TBL_DumpCtrlId_t BlockId) +{ + return (BlockPtr != NULL && CFE_RESOURCEID_TEST_EQUAL(BlockPtr->BlockId, BlockId)); +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Check if a dump control block is in use or free/empty + * + * This routine checks if the block 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. + * + * @note This internal helper function must only be used on result pointers + * that are known to refer to an actual table location (i.e. non-null). + * + * @param[in] BlockPtr pointer to dump control block + * @returns true if the entry is in use/configured, or false if it is free/empty + */ +static inline bool CFE_TBL_DumpCtrlBlockIsUsed(const CFE_TBL_DumpControl_t *BlockPtr) +{ + return (CFE_RESOURCEID_TEST_DEFINED(BlockPtr->BlockId)); +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Marks a dump control block as in use (not avaliable) + * + * This sets the internal field(s) within this entry, and marks + * it as being associated with the given block ID. + * + * @note This internal helper function must only be used on record pointers + * that are known to refer to an actual table location (i.e. non-null). + * + * @param[in] BlockPtr pointer to dump control block + * @param[in] PendingId the ID of this entry that will be set + */ +static inline void CFE_TBL_DumpCtrlBlockSetUsed(CFE_TBL_DumpControl_t *BlockPtr, CFE_ResourceId_t PendingId) +{ + BlockPtr->BlockId = CFE_TBL_DUMPCTRLID_C(PendingId); +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Marks a dump control block as available (not in use) + * + * This clears the internal field(s) within this entry, and marks + * it as not being associated with any block ID. + * + * @note This internal helper function must only be used on record pointers + * that are known to refer to an actual table location (i.e. non-null). + * + * @param[in] BlockPtr pointer to dump control block + */ +static inline void CFE_TBL_DumpCtrlBlockSetFree(CFE_TBL_DumpControl_t *BlockPtr) +{ + BlockPtr->State = CFE_TBL_DUMP_FREE; + BlockPtr->BlockId = CFE_TBL_DUMPCTRLID_UNDEFINED; +} + +/*---------------------------------------------------------------------------------------*/ +/** + * @brief Get the ID value from a dump control block + * + * This routine converts the block pointer to its corresponding ID. + * + * @note This internal helper function must only be used on record pointers + * that are known to refer to an actual table location (i.e. non-null). + * + * @param[in] BlockPtr pointer to block + * @returns ID of entry + */ +static inline CFE_TBL_DumpCtrlId_t CFE_TBL_DumpCtrlBlockGetId(const CFE_TBL_DumpControl_t *BlockPtr) +{ + return BlockPtr->BlockId; +} + +/* + * Internal functions to perform name based resource lookups + * + * These functions do not lock, they must only be used internally by ES when + * the lock is already held. + */ + +/** + * @brief Determine the next ID to use for a dump control block + * + * Obtains an ID value that is usable for a new dump control block. If no blocks + * are available, then UNDEFINED is returned. + * + * @returns ID to use for next control block, or UNDEFINED if no slots available + */ +CFE_ResourceId_t CFE_TBL_GetNextDumpCtrlBlock(void); + +/** + * Test if a slot corresponding to a pending ID is used + * + * This is an internal helper function for CFE_ResourceId_FindNext(), and not + * typically called directly. It is prototyped here for unit testing. + * + * @returns True if used, False if available + */ +bool CFE_TBL_CheckDumpCtrlSlotUsed(CFE_ResourceId_t CheckId); + /* * --------------------------------------------------------------------------------------- * diff --git a/modules/tbl/fsw/src/cfe_tbl_task.h b/modules/tbl/fsw/src/cfe_tbl_task.h index 5176d0f3f..c510cd46b 100644 --- a/modules/tbl/fsw/src/cfe_tbl_task.h +++ b/modules/tbl/fsw/src/cfe_tbl_task.h @@ -64,16 +64,16 @@ /** \brief Value indicating when no Validation is Pending */ /** ** This macro is used to indicate no Validation is Pending by assigning it to -** #CFE_TBL_RegistryRec_t::ValidateActiveIndex or #CFE_TBL_RegistryRec_t::ValidateInactiveIndex +** #CFE_TBL_RegistryRec_t::ValidateActiveId or #CFE_TBL_RegistryRec_t::ValidateInactiveId */ #define CFE_TBL_NO_VALIDATION_PENDING CFE_TBL_VALRESULTID_UNDEFINED /** \brief Value indicating when no Dump is Pending on a Dump-Only Table */ /** ** This macro is used to indicate no Dump is Pending by assigning it to -** #CFE_TBL_RegistryRec_t::DumpControlIndex +** #CFE_TBL_RegistryRec_t::DumpControlId */ -#define CFE_TBL_NO_DUMP_PENDING (-1) +#define CFE_TBL_NO_DUMP_PENDING CFE_TBL_DUMPCTRLID_UNDEFINED /************************ Internal Structure Definitions *****************************/ @@ -87,6 +87,16 @@ typedef CFE_RESOURCEID_BASE_TYPE CFE_TBL_ValidationResultId_t; #define CFE_TBL_VALRESULTID_C(val) ((CFE_TBL_ValidationResultId_t)CFE_RESOURCEID_WRAP(val)) #define CFE_TBL_VALRESULTID_UNDEFINED CFE_TBL_VALRESULTID_C(CFE_RESOURCEID_UNDEFINED) +/** + * @brief A type for Dump Control Block IDs + * + * This is the type that is used for any API accepting or returning a dump control block + */ +typedef CFE_RESOURCEID_BASE_TYPE CFE_TBL_DumpCtrlId_t; + +#define CFE_TBL_DUMPCTRLID_C(val) ((CFE_TBL_DumpCtrlId_t)CFE_RESOURCEID_WRAP(val)) +#define CFE_TBL_DUMPCTRLID_UNDEFINED CFE_TBL_DUMPCTRLID_C(CFE_RESOURCEID_UNDEFINED) + /*******************************************************************************/ /** \brief Identifies the current state of a validation sequence. */ @@ -205,19 +215,19 @@ typedef struct CFE_TBL_ValidationResultId_t ValidateActiveId; /**< \brief Index to Validation Request on Active Table Result data */ CFE_TBL_ValidationResultId_t - ValidateInactiveId; /**< \brief Index to Validation Request on Inactive Table Result data */ - int32 DumpControlIndex; /**< \brief Index to Dump Control Block */ - CFE_ES_CDSHandle_t CDSHandle; /**< \brief Handle to Critical Data Store for Critical Tables */ - CFE_MSG_FcnCode_t NotificationCC; /**< \brief Command Code of an associated management notification message */ - bool CriticalTable; /**< \brief Flag indicating whether table is a Critical Table */ - bool TableLoadedOnce; /**< \brief Flag indicating whether table has been loaded once or not */ - bool LoadPending; /**< \brief Flag indicating an inactive buffer is ready to be copied */ - bool DumpOnly; /**< \brief Flag indicating Table is NOT to be loaded */ - bool DoubleBuffered; /**< \brief Flag indicating Table has a dedicated inactive buffer */ - bool UserDefAddr; /**< \brief Flag indicating Table address was defined by Owner Application */ - bool NotifyByMsg; /**< \brief Flag indicating Table Services should notify owning App via message - when table requires management */ - uint8 ActiveBufferIndex; /**< \brief Index identifying which buffer is the active buffer */ + ValidateInactiveId; /**< \brief Index to Validation Request on Inactive Table Result data */ + CFE_TBL_DumpCtrlId_t DumpControlId; /**< \brief Index to Dump Control Block */ + CFE_ES_CDSHandle_t CDSHandle; /**< \brief Handle to Critical Data Store for Critical Tables */ + CFE_MSG_FcnCode_t NotificationCC; /**< \brief Command Code of an associated management notification message */ + bool CriticalTable; /**< \brief Flag indicating whether table is a Critical Table */ + bool TableLoadedOnce; /**< \brief Flag indicating whether table has been loaded once or not */ + bool LoadPending; /**< \brief Flag indicating an inactive buffer is ready to be copied */ + bool DumpOnly; /**< \brief Flag indicating Table is NOT to be loaded */ + bool DoubleBuffered; /**< \brief Flag indicating Table has a dedicated inactive buffer */ + bool UserDefAddr; /**< \brief Flag indicating Table address was defined by Owner Application */ + bool NotifyByMsg; /**< \brief Flag indicating Table Services should notify owning App via message + when table requires management */ + uint8 ActiveBufferIndex; /**< \brief Index identifying which buffer is the active buffer */ char Name[CFE_TBL_MAX_FULL_NAME_LEN]; /**< \brief Processor specific table name */ char LastFileLoaded[OS_MAX_PATH_LEN]; /**< \brief Filename of last file loaded into table */ } CFE_TBL_RegistryRec_t; @@ -245,6 +255,8 @@ typedef struct */ typedef struct { + CFE_TBL_DumpCtrlId_t BlockId; + CFE_TBL_DumpState_t State; /**< \brief Current state of this block of data */ size_t Size; /**< \brief Number of bytes to be dumped */ CFE_TBL_LoadBuff_t * DumpBufferPtr; /**< \brief Address where dumped data is to be stored temporarily */ @@ -365,6 +377,7 @@ typedef struct CFE_TBL_RegDumpStateInfo_t RegDumpState; CFE_ResourceId_t LastValidationResultId; + CFE_ResourceId_t LastDumpCtrlBlockId; } CFE_TBL_Global_t; diff --git a/modules/tbl/fsw/src/cfe_tbl_task_cmds.c b/modules/tbl/fsw/src/cfe_tbl_task_cmds.c index 615676308..1033464d4 100644 --- a/modules/tbl/fsw/src/cfe_tbl_task_cmds.c +++ b/modules/tbl/fsw/src/cfe_tbl_task_cmds.c @@ -86,10 +86,11 @@ int32 CFE_TBL_SendHkCmd(const CFE_TBL_SendHkCmd_t *data) /* Check to see if there are any dump-only table dumps pending */ for (i = 0; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { - if (CFE_TBL_Global.DumpControlBlocks[i].State == CFE_TBL_DUMP_PERFORMED) + DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[i]; + + if (CFE_TBL_DumpCtrlBlockIsUsed(DumpCtrlPtr) && DumpCtrlPtr->State == CFE_TBL_DUMP_PERFORMED) { - DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[i]; - Status = CFE_TBL_DumpToFile(DumpCtrlPtr->DumpBufferPtr->DataSource, DumpCtrlPtr->TableName, + Status = CFE_TBL_DumpToFile(DumpCtrlPtr->DumpBufferPtr->DataSource, DumpCtrlPtr->TableName, DumpCtrlPtr->DumpBufferPtr->BufferPtr, DumpCtrlPtr->Size); /* If dump file was successfully written, update the file header so that the timestamp */ @@ -125,7 +126,7 @@ int32 CFE_TBL_SendHkCmd(const CFE_TBL_SendHkCmd_t *data) DumpCtrlPtr->RegRecPtr->LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; /* Free the Dump Control Block for later use */ - DumpCtrlPtr->State = CFE_TBL_DUMP_FREE; + CFE_TBL_DumpCtrlBlockSetFree(DumpCtrlPtr); } } @@ -536,17 +537,20 @@ int32 CFE_TBL_LoadCmd(const CFE_TBL_LoadCmd_t *data) int32 CFE_TBL_DumpCmd(const CFE_TBL_DumpCmd_t *data) { CFE_TBL_CmdProcRet_t ReturnCode = CFE_TBL_INC_ERR_CTR; /* Assume failure */ - int16 RegIndex; + CFE_TBL_TxnState_t Txn; const CFE_TBL_DumpCmd_Payload_t *CmdPtr = &data->Payload; char DumpFilename[OS_MAX_PATH_LEN]; char TableName[CFE_TBL_MAX_FULL_NAME_LEN]; CFE_TBL_RegistryRec_t * RegRecPtr; - void * DumpDataAddr = NULL; CFE_TBL_LoadBuff_t * WorkingBufferPtr; - int32 DumpIndex; - int32 Status; + CFE_TBL_LoadBuff_t * SelectedBufferPtr; + CFE_ResourceId_t PendingDumpId; + CFE_Status_t Status; CFE_TBL_DumpControl_t * DumpCtrlPtr; + SelectedBufferPtr = NULL; + WorkingBufferPtr = NULL; + /* Make sure all strings are null terminated before attempting to process them */ CFE_SB_MessageStringGet(DumpFilename, (char *)CmdPtr->DumpFilename, NULL, sizeof(DumpFilename), sizeof(CmdPtr->DumpFilename)); @@ -554,76 +558,47 @@ int32 CFE_TBL_DumpCmd(const CFE_TBL_DumpCmd_t *data) CFE_SB_MessageStringGet(TableName, (char *)CmdPtr->TableName, NULL, sizeof(TableName), sizeof(CmdPtr->TableName)); /* Before doing anything, lets make sure the table that is to be dumped exists */ - RegIndex = CFE_TBL_FindTableInRegistry(TableName); + Status = CFE_TBL_TxnStartFromName(&Txn, TableName, CFE_TBL_TxnContext_UNDEFINED); - if (RegIndex != CFE_TBL_NOT_FOUND) + if (Status == CFE_SUCCESS) { /* Obtain a pointer to registry information about specified table */ - RegRecPtr = &CFE_TBL_Global.Registry[RegIndex]; + RegRecPtr = CFE_TBL_TxnRegRec(&Txn); /* Determine what data is to be dumped */ - if (CmdPtr->ActiveTableFlag == CFE_TBL_BufferSelect_ACTIVE) - { - DumpDataAddr = RegRecPtr->Buffers[RegRecPtr->ActiveBufferIndex].BufferPtr; - } - else if (CmdPtr->ActiveTableFlag == CFE_TBL_BufferSelect_INACTIVE) /* Dumping Inactive Buffer */ - { - /* If this is a double buffered table, locating the inactive buffer is trivial */ - if (RegRecPtr->DoubleBuffered) - { - DumpDataAddr = RegRecPtr->Buffers[(1U - RegRecPtr->ActiveBufferIndex)].BufferPtr; - } - else - { - /* For single buffered tables, the index to the inactive buffer is kept in 'LoadInProgress' */ - /* Unless this is a table whose address was defined by the owning Application. */ - if ((RegRecPtr->LoadInProgress != CFE_TBL_NO_LOAD_IN_PROGRESS) && (!RegRecPtr->UserDefAddr)) - { - DumpDataAddr = CFE_TBL_Global.LoadBuffs[RegRecPtr->LoadInProgress].BufferPtr; - } - else - { - CFE_EVS_SendEvent(CFE_TBL_NO_INACTIVE_BUFFER_ERR_EID, CFE_EVS_EventType_ERROR, - "No Inactive Buffer for Table '%s' present", TableName); - } - } - } - else + SelectedBufferPtr = CFE_TBL_GetSelectedBuffer(RegRecPtr, CmdPtr->ActiveTableFlag); + + CFE_TBL_TxnFinish(&Txn); + + if (SelectedBufferPtr == NULL) { CFE_EVS_SendEvent(CFE_TBL_ILLEGAL_BUFF_PARAM_ERR_EID, CFE_EVS_EventType_ERROR, "Cmd for Table '%s' had illegal buffer parameter (0x%08X)", TableName, (unsigned int)CmdPtr->ActiveTableFlag); } - - /* If we have located the data to be dumped, then proceed with creating the file and dumping the data */ - if (DumpDataAddr != NULL) + else { + /* If we have located the data to be dumped, then proceed with creating the file and dumping the data */ /* If this is not a dump only table, then we can perform the dump immediately */ if (!RegRecPtr->DumpOnly) { - ReturnCode = CFE_TBL_DumpToFile(DumpFilename, TableName, DumpDataAddr, RegRecPtr->Size); + ReturnCode = CFE_TBL_DumpToFile(DumpFilename, TableName, SelectedBufferPtr->BufferPtr, RegRecPtr->Size); } else /* Dump Only tables need to synchronize their dumps with the owner's execution */ { /* Make sure a dump is not already in progress */ - if (RegRecPtr->DumpControlIndex == CFE_TBL_NO_DUMP_PENDING) + if (!CFE_RESOURCEID_TEST_DEFINED(RegRecPtr->DumpControlId)) { /* Find a free Dump Control Block */ - DumpIndex = 0; - while ((DumpIndex < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS) && - (CFE_TBL_Global.DumpControlBlocks[DumpIndex].State != CFE_TBL_DUMP_FREE)) - { - DumpIndex++; - } - - if (DumpIndex < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS) + PendingDumpId = CFE_TBL_GetNextDumpCtrlBlock(); + DumpCtrlPtr = CFE_TBL_LocateDumpCtrlByID(CFE_TBL_DUMPCTRLID_C(PendingDumpId)); + if (DumpCtrlPtr != NULL) { /* Allocate a shared memory buffer for storing the data to be dumped */ Status = CFE_TBL_GetWorkingBuffer(&WorkingBufferPtr, RegRecPtr, false); if (Status == CFE_SUCCESS) { - DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[DumpIndex]; DumpCtrlPtr->State = CFE_TBL_DUMP_PENDING; DumpCtrlPtr->RegRecPtr = RegRecPtr; @@ -634,7 +609,8 @@ int32 CFE_TBL_DumpCmd(const CFE_TBL_DumpCmd_t *data) DumpCtrlPtr->Size = RegRecPtr->Size; /* Notify the owning application that a dump is pending */ - RegRecPtr->DumpControlIndex = DumpIndex; + CFE_TBL_DumpCtrlBlockSetUsed(DumpCtrlPtr, PendingDumpId); + RegRecPtr->DumpControlId = CFE_TBL_DumpCtrlBlockGetId(DumpCtrlPtr); /* If application requested notification by message, then do so */ CFE_TBL_SendNotificationMsg(RegRecPtr); diff --git a/modules/tbl/fsw/src/cfe_tbl_transaction.c b/modules/tbl/fsw/src/cfe_tbl_transaction.c index 479ac1e27..63beb11a3 100644 --- a/modules/tbl/fsw/src/cfe_tbl_transaction.c +++ b/modules/tbl/fsw/src/cfe_tbl_transaction.c @@ -289,7 +289,7 @@ CFE_Status_t CFE_TBL_TxnGetTableStatus(CFE_TBL_TxnState_t *Txn) { Status = CFE_TBL_INFO_VALIDATION_PENDING; } - else if (RegRecPtr->DumpControlIndex != CFE_TBL_NO_DUMP_PENDING) + else if (CFE_RESOURCEID_TEST_DEFINED(RegRecPtr->DumpControlId)) { Status = CFE_TBL_INFO_DUMP_PENDING; } diff --git a/modules/tbl/ut-coverage/tbl_UT.c b/modules/tbl/ut-coverage/tbl_UT.c index 3affe155d..3d245b005 100644 --- a/modules/tbl/ut-coverage/tbl_UT.c +++ b/modules/tbl/ut-coverage/tbl_UT.c @@ -159,6 +159,46 @@ void UT_TBL_ResetValidationState(uint32 ArrayIndex) memset(ValResultPtr, 0, sizeof(*ValResultPtr)); } +void UT_TBL_SetupPendingDump(uint32 ArrayIndex, CFE_TBL_LoadBuff_t *DumpBufferPtr, CFE_TBL_RegistryRec_t *RegRecPtr, + CFE_TBL_DumpControl_t **DumpCtrlOut) +{ + CFE_TBL_DumpControl_t *DumpCtrlPtr; + CFE_ResourceId_t PendingId; + + DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[ArrayIndex]; + + PendingId = CFE_ResourceId_FromInteger(CFE_TBL_DUMPCTRLID_BASE + ArrayIndex); + + memset(DumpCtrlPtr, 0, sizeof(*DumpCtrlPtr)); + + DumpCtrlPtr->State = CFE_TBL_DUMP_PENDING; + DumpCtrlPtr->BlockId = CFE_TBL_DUMPCTRLID_C(PendingId); + DumpCtrlPtr->RegRecPtr = RegRecPtr; + DumpCtrlPtr->DumpBufferPtr = DumpBufferPtr; + DumpCtrlPtr->Size = 1; + + snprintf(DumpCtrlPtr->TableName, sizeof(DumpCtrlPtr->TableName), "ut_cfe_tbl.UT_Table%u", + (unsigned int)ArrayIndex + 1); + + if (RegRecPtr != NULL) + { + RegRecPtr->DumpControlId = DumpCtrlPtr->BlockId; + } + + if (DumpCtrlOut != NULL) + { + *DumpCtrlOut = DumpCtrlPtr; + } +} + +/* Resets the indicated dump control block to the free/unused state */ +void UT_TBL_ResetDumpCtrlState(uint32 ArrayIndex) +{ + CFE_TBL_DumpControl_t *DumpCtrlPtr; + DumpCtrlPtr = &CFE_TBL_Global.DumpControlBlocks[ArrayIndex]; + memset(DumpCtrlPtr, 0, sizeof(*DumpCtrlPtr)); +} + /* ** Functions */ @@ -181,6 +221,7 @@ void UtTest_Setup(void) UT_ADD_TEST(Test_CFE_TBL_ResourceID_ValidationResult); UT_ADD_TEST(Test_CFE_TBL_ResourceID_RegistryRecord); UT_ADD_TEST(Test_CFE_TBL_ResourceID_AccessDescriptor); + UT_ADD_TEST(Test_CFE_TBL_ResourceID_DumpControl); /* cfe_tbl_task_cmds.c functions */ /* This should be done first (it initializes working data structures) */ @@ -269,10 +310,7 @@ void UT_ResetTableRegistry(void) /* Initialize the dump-only table dump control blocks */ for (i = 0; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { - CFE_TBL_Global.DumpControlBlocks[i].State = CFE_TBL_DUMP_FREE; - CFE_TBL_Global.DumpControlBlocks[i].DumpBufferPtr = NULL; - CFE_TBL_Global.DumpControlBlocks[i].Size = 0; - CFE_TBL_Global.DumpControlBlocks[i].TableName[0] = '\0'; + UT_TBL_ResetDumpCtrlState(i); /* Free all shared buffers */ CFE_TBL_Global.LoadBuffs[i].Taken = false; @@ -1071,7 +1109,7 @@ void Test_CFE_TBL_DumpRegCmd(void) */ void Test_CFE_TBL_DumpCmd(void) { - int i, k, u; + int i, u; uint8 Buff; uint8 * BuffPtr = &Buff; CFE_TBL_LoadBuff_t Load = {0}; @@ -1107,9 +1145,9 @@ void Test_CFE_TBL_DumpCmd(void) CFE_TBL_Global.Registry[i].DumpOnly = true; } - CFE_TBL_Global.DumpControlBlocks[2].State = CFE_TBL_DUMP_PENDING; - CFE_TBL_Global.DumpControlBlocks[3].State = CFE_TBL_DUMP_FREE; - CFE_TBL_Global.Registry[2].DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; + UT_TBL_SetupPendingDump(2, NULL, NULL, NULL); + UT_TBL_ResetDumpCtrlState(3); + CFE_TBL_Global.Registry[2].DumpControlId = CFE_TBL_NO_DUMP_PENDING; CFE_TBL_Global.Registry[2].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; CFE_TBL_Global.Registry[2].DoubleBuffered = false; CFE_TBL_Global.LoadBuffs[CFE_TBL_Global.Registry[2].LoadInProgress] = Load; @@ -1123,11 +1161,11 @@ void Test_CFE_TBL_DumpCmd(void) * available */ UT_InitData(); - CFE_TBL_Global.DumpControlBlocks[2].State = CFE_TBL_DUMP_FREE; - CFE_TBL_Global.Registry[2].DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; - CFE_TBL_Global.Registry[2].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; - CFE_TBL_Global.Registry[2].TableLoadedOnce = true; - CFE_TBL_Global.Registry[2].DoubleBuffered = false; + UT_TBL_ResetDumpCtrlState(2); + CFE_TBL_Global.Registry[2].DumpControlId = CFE_TBL_NO_DUMP_PENDING; + CFE_TBL_Global.Registry[2].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; + CFE_TBL_Global.Registry[2].TableLoadedOnce = true; + CFE_TBL_Global.Registry[2].DoubleBuffered = false; for (u = 0; u < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; u++) { @@ -1142,14 +1180,9 @@ void Test_CFE_TBL_DumpCmd(void) * dump only table dumps have been requested */ UT_InitData(); - CFE_TBL_Global.Registry[2].DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; - - for (k = 0; k < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; k++) - { - CFE_TBL_Global.DumpControlBlocks[k].State = CFE_TBL_DUMP_PENDING; - } - - CFE_TBL_Global.Registry[2].NotifyByMsg = true; + CFE_TBL_Global.Registry[2].DumpControlId = CFE_TBL_NO_DUMP_PENDING; + CFE_TBL_Global.Registry[2].NotifyByMsg = true; + UT_SetDeferredRetcode(UT_KEY(CFE_ResourceId_FindNext), 1, 0); UtAssert_INT32_EQ(CFE_TBL_DumpCmd(&DumpCmd), CFE_TBL_INC_ERR_CTR); /* Test with an inactive buffer, double-buffered, dump already in progress; @@ -1159,7 +1192,7 @@ void Test_CFE_TBL_DumpCmd(void) DumpCmd.Payload.ActiveTableFlag = CFE_TBL_BufferSelect_INACTIVE; CFE_TBL_Global.Registry[2].DoubleBuffered = true; CFE_TBL_Global.Registry[2].Buffers[(1 - CFE_TBL_Global.Registry[2].ActiveBufferIndex)].BufferPtr = BuffPtr; - CFE_TBL_Global.Registry[2].DumpControlIndex = CFE_TBL_NO_DUMP_PENDING + 1; + CFE_TBL_Global.Registry[2].DumpControlId = CFE_TBL_DUMPCTRLID_C(CFE_ResourceId_FromInteger(1)); UtAssert_INT32_EQ(CFE_TBL_DumpCmd(&DumpCmd), CFE_TBL_INC_ERR_CTR); /* Test with an inactive buffer, single-buffered, pointer created, is a @@ -1368,13 +1401,14 @@ void Test_CFE_TBL_LoadCmd(void) */ void Test_CFE_TBL_SendHkCmd(void) { - int i; - CFE_TBL_LoadBuff_t DumpBuff; - CFE_TBL_LoadBuff_t * DumpBuffPtr = &DumpBuff; - CFE_TBL_RegistryRec_t RegRecPtr; - uint8 Buff; - void * BuffPtr = &Buff; - int32 LoadInProg = 0; + int i; + CFE_TBL_LoadBuff_t DumpBuff; + CFE_TBL_LoadBuff_t * DumpBuffPtr = &DumpBuff; + CFE_TBL_RegistryRec_t *RegRecPtr; + uint8 Buff; + void * BuffPtr = &Buff; + int32 LoadInProg = 0; + CFE_TBL_DumpControl_t *DumpCtrlPtr; UtPrintf("Begin Test Housekeeping Command"); @@ -1382,25 +1416,21 @@ void Test_CFE_TBL_SendHkCmd(void) * to send Hk packet */ UT_InitData(); - strncpy(CFE_TBL_Global.DumpControlBlocks[0].TableName, "housekeepingtest", - sizeof(CFE_TBL_Global.DumpControlBlocks[0].TableName) - 1); - CFE_TBL_Global.DumpControlBlocks[0].TableName[sizeof(CFE_TBL_Global.DumpControlBlocks[0].TableName) - 1] = '\0'; - CFE_TBL_Global.DumpControlBlocks[0].Size = 10; - LoadInProg = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; - RegRecPtr.LoadInProgress = LoadInProg; - CFE_TBL_Global.DumpControlBlocks[0].RegRecPtr = &RegRecPtr; - DumpBuffPtr->Taken = true; - DumpBuffPtr->Validated = true; - DumpBuffPtr->BufferPtr = BuffPtr; - DumpBuffPtr->FileTime = CFE_TIME_ZERO_VALUE; + RegRecPtr = &CFE_TBL_Global.Registry[0]; + UT_TBL_SetupPendingDump(0, DumpBuffPtr, RegRecPtr, &DumpCtrlPtr); + LoadInProg = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; + RegRecPtr->LoadInProgress = LoadInProg; + DumpBuffPtr->Taken = true; + DumpBuffPtr->Validated = true; + DumpBuffPtr->BufferPtr = BuffPtr; + DumpBuffPtr->FileTime = CFE_TIME_ZERO_VALUE; strncpy(DumpBuffPtr->DataSource, "hkSource", sizeof(DumpBuffPtr->DataSource) - 1); DumpBuffPtr->DataSource[sizeof(DumpBuffPtr->DataSource) - 1] = '\0'; - CFE_TBL_Global.DumpControlBlocks[0].DumpBufferPtr = DumpBuffPtr; - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PERFORMED; + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; for (i = 1; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { - CFE_TBL_Global.DumpControlBlocks[i].State = CFE_TBL_DUMP_PENDING; + UT_TBL_SetupPendingDump(i, NULL, NULL, NULL); } UT_SetDeferredRetcode(UT_KEY(CFE_SB_TransmitMsg), 1, CFE_SUCCESS - 1); @@ -1409,35 +1439,38 @@ void Test_CFE_TBL_SendHkCmd(void) for (i = 1; i < CFE_PLATFORM_TBL_MAX_SIMULTANEOUS_LOADS; i++) { - CFE_TBL_Global.DumpControlBlocks[i].State = CFE_TBL_DUMP_PENDING; + UT_TBL_SetupPendingDump(i, NULL, NULL, NULL); } - RegRecPtr.LoadInProgress = LoadInProg; - CFE_TBL_Global.DumpControlBlocks[0].RegRecPtr = &RegRecPtr; + RegRecPtr->LoadInProgress = LoadInProg; /* Test response to inability to open dump file */ UT_InitData(); - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PERFORMED; - CFE_TBL_Global.HkTlmTblRegIndex = CFE_TBL_NOT_FOUND + 1; + UT_TBL_SetupPendingDump(0, DumpBuffPtr, RegRecPtr, &DumpCtrlPtr); + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; + CFE_TBL_Global.HkTlmTblRegIndex = CFE_TBL_NOT_FOUND + 1; UT_SetDefaultReturnValue(UT_KEY(OS_OpenCreate), OS_ERROR); UtAssert_INT32_EQ(CFE_TBL_SendHkCmd(NULL), CFE_TBL_DONT_INC_CTR); /* Test response to an invalid table and a dump file create failure */ UT_InitData(); - CFE_TBL_Global.HkTlmTblRegIndex = CFE_TBL_NOT_FOUND; - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PERFORMED; + UT_TBL_SetupPendingDump(0, DumpBuffPtr, RegRecPtr, &DumpCtrlPtr); + CFE_TBL_Global.HkTlmTblRegIndex = CFE_TBL_NOT_FOUND; + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; UT_SetDefaultReturnValue(UT_KEY(OS_OpenCreate), OS_ERROR); UtAssert_INT32_EQ(CFE_TBL_SendHkCmd(NULL), CFE_TBL_DONT_INC_CTR); /* Test response to a file time stamp failure */ UT_InitData(); - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PERFORMED; + UT_TBL_SetupPendingDump(0, DumpBuffPtr, RegRecPtr, &DumpCtrlPtr); + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; UT_SetDeferredRetcode(UT_KEY(CFE_FS_SetTimestamp), 1, OS_SUCCESS - 1); UtAssert_INT32_EQ(CFE_TBL_SendHkCmd(NULL), CFE_TBL_DONT_INC_CTR); /* Test response to OS_OpenCreate failure */ UT_InitData(); - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PERFORMED; + UT_TBL_SetupPendingDump(0, DumpBuffPtr, RegRecPtr, &DumpCtrlPtr); + DumpCtrlPtr->State = CFE_TBL_DUMP_PERFORMED; UT_SetDeferredRetcode(UT_KEY(OS_OpenCreate), 3, -1); UtAssert_INT32_EQ(CFE_TBL_SendHkCmd(NULL), CFE_TBL_DONT_INC_CTR); } @@ -2620,6 +2653,7 @@ void Test_CFE_TBL_Manage(void) CFE_TBL_AccessDescriptor_t *AccessDescPtr; CFE_TBL_Handle_t AccessIterator; CFE_TBL_ValidationResult_t *ValResultPtr; + CFE_TBL_DumpControl_t * DumpCtrlPtr; memset(&TestTable1, 0, sizeof(TestTable1)); @@ -2882,22 +2916,13 @@ void Test_CFE_TBL_Manage(void) /* Test successfully processing a table dump request */ UT_InitData(); CFE_UtAssert_SUCCESS(CFE_TBL_GetWorkingBuffer(&WorkingBufferPtr, RegRecPtr, false)); - CFE_TBL_Global.DumpControlBlocks[0].State = CFE_TBL_DUMP_PENDING; - CFE_TBL_Global.DumpControlBlocks[0].RegRecPtr = RegRecPtr; + UT_TBL_SetupPendingDump(0, WorkingBufferPtr, RegRecPtr, &DumpCtrlPtr); /* Save the name of the desired dump filename, table name, and size for * later */ - CFE_TBL_Global.DumpControlBlocks[0].DumpBufferPtr = WorkingBufferPtr; - strncpy(CFE_TBL_Global.DumpControlBlocks[0].DumpBufferPtr->DataSource, "MyDumpFilename", - sizeof(CFE_TBL_Global.DumpControlBlocks[0].DumpBufferPtr->DataSource) - 1); - CFE_TBL_Global.DumpControlBlocks[0] - .DumpBufferPtr->DataSource[sizeof(CFE_TBL_Global.DumpControlBlocks[0].DumpBufferPtr->DataSource) - 1] = 0; - strncpy(CFE_TBL_Global.DumpControlBlocks[0].TableName, "ut_cfe_tbl.UT_Table2", - sizeof(CFE_TBL_Global.DumpControlBlocks[0].TableName) - 1); - CFE_TBL_Global.DumpControlBlocks[0].TableName[sizeof(CFE_TBL_Global.DumpControlBlocks[0].TableName) - 1] = 0; - CFE_TBL_Global.DumpControlBlocks[0].Size = RegRecPtr->Size; - RegRecPtr->DumpControlIndex = 0; + strncpy(WorkingBufferPtr->DataSource, "MyDumpFilename", sizeof(WorkingBufferPtr->DataSource) - 1); + WorkingBufferPtr->DataSource[sizeof(WorkingBufferPtr->DataSource) - 1] = 0; CFE_UtAssert_SUCCESS(CFE_TBL_Manage(App1TblHandle2)); CFE_UtAssert_EVENTCOUNT(0); } @@ -3225,6 +3250,7 @@ void Test_CFE_TBL_Internal(void) CFE_TBL_LoadBuff_t * WorkingBufferPtr; CFE_TBL_RegistryRec_t * RegRecPtr; CFE_TBL_AccessDescriptor_t *AccessDescPtr; + CFE_TBL_DumpControl_t * DumpCtrlPtr; char FilenameLong[OS_MAX_PATH_LEN + 10]; char Filename[OS_MAX_PATH_LEN]; int32 i; @@ -3762,16 +3788,18 @@ void Test_CFE_TBL_Internal(void) UT_InitData(); UT_SetAppID(UT_TBL_APPID_1); UT_SetDefaultReturnValue(UT_KEY(CFE_ES_PutPoolBuf), -1); - AccessDescPtr = &CFE_TBL_Global.Handles[App1TblHandle1]; - RegRecPtr = &CFE_TBL_Global.Registry[AccessDescPtr->RegIndex]; - CFE_TBL_Global.DumpControlBlocks[3].State = CFE_TBL_DUMP_PENDING; - CFE_TBL_Global.DumpControlBlocks[3].RegRecPtr = RegRecPtr; - RegRecPtr->LoadInProgress = 1; - CFE_TBL_Global.LoadBuffs[1].Taken = true; + AccessDescPtr = &CFE_TBL_Global.Handles[App1TblHandle1]; + RegRecPtr = &CFE_TBL_Global.Registry[AccessDescPtr->RegIndex]; + WorkingBufferPtr = &CFE_TBL_Global.LoadBuffs[1]; + + UT_TBL_SetupPendingDump(3, WorkingBufferPtr, RegRecPtr, &DumpCtrlPtr); + + RegRecPtr->LoadInProgress = 1; + WorkingBufferPtr->Taken = true; CFE_UtAssert_SUCCESS(CFE_TBL_CleanUpApp(UT_TBL_APPID_1)); - UtAssert_INT32_EQ(CFE_TBL_Global.DumpControlBlocks[3].State, CFE_TBL_DUMP_FREE); + UtAssert_INT32_EQ(DumpCtrlPtr->State, CFE_TBL_DUMP_FREE); CFE_UtAssert_RESOURCEID_EQ(RegRecPtr->OwnerAppId, CFE_TBL_NOT_OWNED); - UtAssert_BOOL_FALSE(CFE_TBL_Global.LoadBuffs[RegRecPtr->LoadInProgress].Taken); + UtAssert_BOOL_FALSE(WorkingBufferPtr->Taken); UtAssert_INT32_EQ(RegRecPtr->LoadInProgress, CFE_TBL_NO_LOAD_IN_PROGRESS); /* Test response to an attempt to use an invalid table handle */ @@ -3900,16 +3928,18 @@ void Test_CFE_TBL_Internal(void) UT_InitData(); UT_SetAppID(UT_TBL_APPID_1); UT_SetDefaultReturnValue(UT_KEY(CFE_ES_PutPoolBuf), -1); - CFE_TBL_Global.Handles[0].AppId = UT_TBL_APPID_1; - CFE_TBL_Global.Handles[0].UsedFlag = true; - CFE_TBL_Global.Handles[0].RegIndex = 0; - CFE_TBL_Global.Registry[0].OwnerAppId = UT_TBL_APPID_2; - CFE_TBL_Global.DumpControlBlocks[3].State = CFE_TBL_DUMP_PENDING; - CFE_TBL_Global.DumpControlBlocks[3].RegRecPtr = &CFE_TBL_Global.Registry[0]; - CFE_TBL_Global.Handles[1].AppId = UT_TBL_APPID_1; - CFE_TBL_Global.Handles[1].UsedFlag = false; + RegRecPtr = &CFE_TBL_Global.Registry[0]; + UT_TBL_SetupPendingDump(3, NULL, RegRecPtr, &DumpCtrlPtr); + + CFE_TBL_Global.Handles[0].AppId = UT_TBL_APPID_1; + CFE_TBL_Global.Handles[0].UsedFlag = true; + CFE_TBL_Global.Handles[0].RegIndex = 0; + RegRecPtr->OwnerAppId = UT_TBL_APPID_2; + CFE_TBL_Global.Handles[1].AppId = UT_TBL_APPID_1; + CFE_TBL_Global.Handles[1].UsedFlag = false; + CFE_UtAssert_SUCCESS(CFE_TBL_CleanUpApp(UT_TBL_APPID_1)); - UtAssert_INT32_EQ(CFE_TBL_Global.DumpControlBlocks[3].State, CFE_TBL_DUMP_PENDING); + UtAssert_INT32_EQ(DumpCtrlPtr->State, CFE_TBL_DUMP_PENDING); CFE_UtAssert_RESOURCEID_EQ(RegRecPtr->OwnerAppId, UT_TBL_APPID_2); #if (CFE_PLATFORM_TBL_VALID_SCID_COUNT > 0) @@ -4103,6 +4133,49 @@ void Test_CFE_TBL_ResourceID_AccessDescriptor(void) UtAssert_UINT32_EQ(Idx, 1); } +/* + * Tests the resource accessors for Dump Control Blocks + */ +void Test_CFE_TBL_ResourceID_DumpControl(void) +{ + uint32 Idx; + CFE_TBL_DumpCtrlId_t InvalidBlockId; + CFE_TBL_DumpCtrlId_t ValidBlockId; + CFE_ResourceId_t PendingId; + + UT_InitData(); + + InvalidBlockId = CFE_TBL_DUMPCTRLID_UNDEFINED; + UT_SetDefaultReturnValue(UT_KEY(CFE_ResourceId_ToIndex), CFE_ES_ERR_RESOURCEID_NOT_VALID); + UtAssert_INT32_EQ(CFE_TBL_DumpCtrlId_ToIndex(InvalidBlockId, &Idx), CFE_ES_ERR_RESOURCEID_NOT_VALID); + + /* by definition, looking up the undefined value should always be NULL */ + UtAssert_NULL(CFE_TBL_LocateDumpCtrlByID(InvalidBlockId)); + UT_ResetState(UT_KEY(CFE_ResourceId_ToIndex)); + + ValidBlockId = CFE_TBL_DUMPCTRLID_C(CFE_ResourceId_FromInteger(CFE_TBL_DUMPCTRLID_BASE + 1)); + UtAssert_INT32_EQ(CFE_TBL_DumpCtrlId_ToIndex(ValidBlockId, &Idx), CFE_SUCCESS); + + UtAssert_VOIDCALL(PendingId = CFE_TBL_GetNextDumpCtrlBlock()); + UtAssert_BOOL_TRUE(CFE_ResourceId_IsDefined(PendingId)); + + /* The slot should be available right now */ + UtAssert_BOOL_FALSE(CFE_TBL_CheckDumpCtrlSlotUsed(PendingId)); + + /* Make it used and confirm it is reported as not available */ + CFE_TBL_DumpCtrlBlockSetUsed(CFE_TBL_LocateDumpCtrlByID(CFE_TBL_DUMPCTRLID_C(PendingId)), PendingId); + UtAssert_BOOL_TRUE(CFE_TBL_CheckDumpCtrlSlotUsed(PendingId)); + + /* Test case where no ID is available */ + UT_SetDefaultReturnValue(UT_KEY(CFE_ResourceId_FindNext), 0); + UtAssert_VOIDCALL(PendingId = CFE_TBL_GetNextDumpCtrlBlock()); + UtAssert_BOOL_FALSE(CFE_ResourceId_IsDefined(PendingId)); + + /* A nonexistent slot is always "unavailable" */ + UtAssert_BOOL_TRUE(CFE_TBL_CheckDumpCtrlSlotUsed(PendingId)); + UT_ResetState(UT_KEY(CFE_ResourceId_FindNext)); +} + /* ** Test function executed when the contents of a table need to be validated */ diff --git a/modules/tbl/ut-coverage/tbl_UT.h b/modules/tbl/ut-coverage/tbl_UT.h index 95fd0d97b..b4b5fd8db 100644 --- a/modules/tbl/ut-coverage/tbl_UT.h +++ b/modules/tbl/ut-coverage/tbl_UT.h @@ -684,5 +684,6 @@ int32 Test_CFE_TBL_ValidationFunc(void *TblPtr); void Test_CFE_TBL_ResourceID_ValidationResult(void); void Test_CFE_TBL_ResourceID_RegistryRecord(void); void Test_CFE_TBL_ResourceID_AccessDescriptor(void); +void Test_CFE_TBL_ResourceID_DumpControl(void); #endif /* TBL_UT_H */