diff --git a/modules/tbl/fsw/src/cfe_tbl_api.c b/modules/tbl/fsw/src/cfe_tbl_api.c index 0d90f3c8c..36e08f068 100644 --- a/modules/tbl/fsw/src/cfe_tbl_api.c +++ b/modules/tbl/fsw/src/cfe_tbl_api.c @@ -251,14 +251,8 @@ CFE_Status_t CFE_TBL_Share(CFE_TBL_Handle_t *TblHandlePtr, const char *TblName) AccessDescPtr->RegIndex = CFE_TBL_TxnRegId(&Txn); AccessDescPtr->UsedFlag = true; - AccessDescPtr->PrevLink = CFE_TBL_END_OF_LIST; /* We are the new head of the list */ - AccessDescPtr->NextLink = RegRecPtr->HeadOfAccessList; - - /* Make sure the old head of the list now sees this as the head */ - CFE_TBL_Global.Handles[RegRecPtr->HeadOfAccessList].PrevLink = CFE_TBL_TxnHandle(&Txn); - - /* Make sure the Registry Record see this as the head of the list */ - RegRecPtr->HeadOfAccessList = CFE_TBL_TxnHandle(&Txn); + CFE_TBL_HandleLinkInit(&AccessDescPtr->Link); + CFE_TBL_HandleListInsertLink(RegRecPtr, AccessDescPtr); } CFE_TBL_TxnFinish(&Txn); @@ -647,7 +641,7 @@ CFE_Status_t CFE_TBL_Update(CFE_TBL_Handle_t TblHandle) /* * Note that (Status < 0) specifically matches ERROR, not WARNING codes. The CFE_TBL_UpdateInternal() function * currently only produces two possible codes (aside from CFE_SUCCESS) and both of these are defined as - * warnings, not errors. Therefore, its impossible to reach this code with RegRegPtr != NULL. + * warnings, not errors. Therefore, its impossible to reach this code with RegRecPtr != NULL. */ CFE_EVS_SendEventWithAppID(CFE_TBL_UPDATE_ERR_EID, CFE_EVS_EventType_ERROR, CFE_TBL_Global.TableTaskAppId, "%s Failed to update table, Status=0x%08X", AppName, (unsigned int)Status); @@ -1088,7 +1082,6 @@ CFE_Status_t CFE_TBL_GetInfo(CFE_TBL_Info_t *TblInfoPtr, const char *TblName) int32 Status = CFE_SUCCESS; int32 NumAccessDescriptors = 0; CFE_TBL_RegistryRec_t *RegRecPtr; - CFE_TBL_Handle_t HandleIterator; if (TblInfoPtr == NULL || TblName == NULL) { @@ -1117,13 +1110,7 @@ CFE_Status_t CFE_TBL_GetInfo(CFE_TBL_Info_t *TblInfoPtr, const char *TblName) strncpy(TblInfoPtr->LastFileLoaded, RegRecPtr->LastFileLoaded, sizeof(TblInfoPtr->LastFileLoaded) - 1); TblInfoPtr->LastFileLoaded[sizeof(TblInfoPtr->LastFileLoaded) - 1] = 0; - /* Count the number of Access Descriptors to determine the number of users */ - HandleIterator = RegRecPtr->HeadOfAccessList; - while (HandleIterator != CFE_TBL_END_OF_LIST) - { - NumAccessDescriptors++; - HandleIterator = CFE_TBL_Global.Handles[HandleIterator].NextLink; - } + CFE_TBL_ForeachAccessDescriptor(RegRecPtr, CFE_TBL_CountAccessDescHelper, &NumAccessDescriptors); TblInfoPtr->NumUsers = NumAccessDescriptors; @@ -1190,6 +1177,23 @@ CFE_Status_t CFE_TBL_DumpToBuffer(CFE_TBL_Handle_t TblHandle) return Status; } +/*---------------------------------------------------------------- + * + * Local helper function, not invoked outside this unit + * Intended to be used with CFE_TBL_ForeachAccessDescriptor() + * + *-----------------------------------------------------------------*/ +static void CFE_TBL_NotifyOtherAppHelper(CFE_TBL_AccessDescriptor_t *AccessDescPtr, void *Arg) +{ + CFE_TBL_TxnState_t *Txn = Arg; + + /* Only notify *OTHER* applications that the contents have changed */ + if (!CFE_RESOURCEID_TEST_EQUAL(AccessDescPtr->AppId, CFE_TBL_TxnAppId(Txn))) + { + AccessDescPtr->Updated = true; + } +} + /*---------------------------------------------------------------- * * Implemented per public API @@ -1201,7 +1205,6 @@ CFE_Status_t CFE_TBL_Modified(CFE_TBL_Handle_t TblHandle) CFE_TBL_TxnState_t Txn; int32 Status; CFE_TBL_RegistryRec_t *RegRecPtr = NULL; - CFE_TBL_Handle_t AccessIterator; CFE_ES_AppId_t ThisAppId; size_t FilenameLen; @@ -1241,17 +1244,8 @@ CFE_Status_t CFE_TBL_Modified(CFE_TBL_Handle_t TblHandle) strncpy(&RegRecPtr->LastFileLoaded[sizeof(RegRecPtr->LastFileLoaded) - 4], "(*)", 4); } - AccessIterator = RegRecPtr->HeadOfAccessList; - while (AccessIterator != CFE_TBL_END_OF_LIST) - { - /* Only notify *OTHER* applications that the contents have changed */ - if (!CFE_RESOURCEID_TEST_EQUAL(CFE_TBL_Global.Handles[AccessIterator].AppId, ThisAppId)) - { - CFE_TBL_Global.Handles[AccessIterator].Updated = true; - } - - AccessIterator = CFE_TBL_Global.Handles[AccessIterator].NextLink; - } + /* Only notify *OTHER* applications that the contents have changed */ + CFE_TBL_ForeachAccessDescriptor(RegRecPtr, CFE_TBL_NotifyOtherAppHelper, &Txn); } else { diff --git a/modules/tbl/fsw/src/cfe_tbl_internal.c b/modules/tbl/fsw/src/cfe_tbl_internal.c index 0c6cdc147..4ab8ef482 100644 --- a/modules/tbl/fsw/src/cfe_tbl_internal.c +++ b/modules/tbl/fsw/src/cfe_tbl_internal.c @@ -35,6 +35,31 @@ #include #include +/** + * Local/private structure used in conjunction with CFE_TBL_CheckInactiveBufferHelper + */ +typedef struct CFE_TBL_CheckInactiveBuffer +{ + int32 BufferIndex; + CFE_ES_AppId_t LockingAppId; +} CFE_TBL_CheckInactiveBuffer_t; + +/*---------------------------------------------------------------- + * + * Local helper function, not invoked outside this unit + * Intended to be used with CFE_TBL_ForeachAccessDescriptor() + * + *-----------------------------------------------------------------*/ +static void CFE_TBL_CheckInactiveBufferHelper(CFE_TBL_AccessDescriptor_t *AccDescPtr, void *Arg) +{ + CFE_TBL_CheckInactiveBuffer_t *StatPtr = Arg; + + if (AccDescPtr->BufferIndex == StatPtr->BufferIndex && AccDescPtr->LockFlag) + { + StatPtr->LockingAppId = AccDescPtr->AppId; + } +} + /*---------------------------------------------------------------- * * Implemented per public API @@ -60,9 +85,8 @@ int32 CFE_TBL_EarlyInit(void) /* Initialize the Table Access Descriptors nonzero values */ for (i = 0; i < CFE_PLATFORM_TBL_MAX_NUM_HANDLES; i++) { - CFE_TBL_Global.Handles[i].AppId = CFE_TBL_NOT_OWNED; - CFE_TBL_Global.Handles[i].PrevLink = CFE_TBL_END_OF_LIST; - CFE_TBL_Global.Handles[i].NextLink = CFE_TBL_END_OF_LIST; + CFE_TBL_Global.Handles[i].AppId = CFE_TBL_NOT_OWNED; + CFE_TBL_HandleLinkInit(&CFE_TBL_Global.Handles[i].Link); } /* Initialize the Table Validation Results Records nonzero values */ @@ -201,12 +225,13 @@ void CFE_TBL_InitRegistryRecord(CFE_TBL_RegistryRec_t *RegRecPtr) RegRecPtr->OwnerAppId = CFE_TBL_NOT_OWNED; RegRecPtr->NotificationMsgId = CFE_SB_INVALID_MSG_ID; - RegRecPtr->HeadOfAccessList = CFE_TBL_END_OF_LIST; RegRecPtr->LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; RegRecPtr->ValidateActiveIndex = CFE_TBL_NO_VALIDATION_PENDING; RegRecPtr->ValidateInactiveIndex = CFE_TBL_NO_VALIDATION_PENDING; RegRecPtr->CDSHandle = CFE_ES_CDS_BAD_HANDLE; RegRecPtr->DumpControlIndex = CFE_TBL_NO_DUMP_PENDING; + + CFE_TBL_HandleLinkInit(&RegRecPtr->AccessList); } /*---------------------------------------------------------------- @@ -306,11 +331,10 @@ int32 CFE_TBL_UnlockRegistry(void) int32 CFE_TBL_GetWorkingBuffer(CFE_TBL_LoadBuff_t **WorkingBufferPtr, CFE_TBL_RegistryRec_t *RegRecPtr, bool CalledByApp) { - int32 Status = CFE_SUCCESS; - int32 OsStatus; - int32 i; - int32 InactiveBufferIndex; - CFE_TBL_Handle_t AccessIterator; + int32 Status = CFE_SUCCESS; + int32 OsStatus; + int32 i; + CFE_TBL_CheckInactiveBuffer_t CheckStat; /* Initialize return pointer to NULL */ *WorkingBufferPtr = NULL; @@ -350,32 +374,27 @@ int32 CFE_TBL_GetWorkingBuffer(CFE_TBL_LoadBuff_t **WorkingBufferPtr, CFE_TBL_Re /* inactive buffer has been freed by any Applications that may have been using it */ if (RegRecPtr->DoubleBuffered) { + memset(&CheckStat, 0, sizeof(CheckStat)); + /* Determine the index of the Inactive Buffer Pointer */ - InactiveBufferIndex = 1 - RegRecPtr->ActiveBufferIndex; + CheckStat.BufferIndex = 1 - RegRecPtr->ActiveBufferIndex; /* Scan the access descriptor table to determine if anyone is still using the inactive buffer */ - AccessIterator = RegRecPtr->HeadOfAccessList; - while ((AccessIterator != CFE_TBL_END_OF_LIST) && (Status == CFE_SUCCESS)) - { - if ((CFE_TBL_Global.Handles[AccessIterator].BufferIndex == InactiveBufferIndex) && - (CFE_TBL_Global.Handles[AccessIterator].LockFlag)) - { - Status = CFE_TBL_ERR_NO_BUFFER_AVAIL; + CFE_TBL_ForeachAccessDescriptor(RegRecPtr, CFE_TBL_CheckInactiveBufferHelper, &CheckStat); - CFE_ES_WriteToSysLog("%s: Inactive Dbl Buff Locked for '%s' by AppId=%lu\n", __func__, - RegRecPtr->Name, - CFE_RESOURCEID_TO_ULONG(CFE_TBL_Global.Handles[AccessIterator].AppId)); - } + if (CFE_RESOURCEID_TEST_DEFINED(CheckStat.LockingAppId)) + { + Status = CFE_TBL_ERR_NO_BUFFER_AVAIL; - /* Move to next access descriptor in linked list */ - AccessIterator = CFE_TBL_Global.Handles[AccessIterator].NextLink; + CFE_ES_WriteToSysLog("%s: Inactive Dbl Buff Locked for '%s' by AppId=%lu\n", __func__, + RegRecPtr->Name, CFE_RESOURCEID_TO_ULONG(CheckStat.LockingAppId)); } /* If buffer is free, then return the pointer to it */ if (Status == CFE_SUCCESS) { - *WorkingBufferPtr = &RegRecPtr->Buffers[InactiveBufferIndex]; - RegRecPtr->LoadInProgress = InactiveBufferIndex; + *WorkingBufferPtr = &RegRecPtr->Buffers[CheckStat.BufferIndex]; + RegRecPtr->LoadInProgress = CheckStat.BufferIndex; } } else /* Single Buffered Table */ @@ -574,6 +593,22 @@ int32 CFE_TBL_LoadFromFile(const char *AppName, CFE_TBL_LoadBuff_t *WorkingBuffe return Status; } +/*---------------------------------------------------------------- + * + * Local helper function, not invoked outside this unit + * Intended to be used with CFE_TBL_ForeachAccessDescriptor() + * + *-----------------------------------------------------------------*/ +static void CFE_TBL_CheckLockHelper(CFE_TBL_AccessDescriptor_t *AccDescPtr, void *Arg) +{ + bool *LockStatus = Arg; + + if (AccDescPtr->LockFlag) + { + *LockStatus = true; + } +} + /*---------------------------------------------------------------- * * Application-scope internal function @@ -583,9 +618,8 @@ int32 CFE_TBL_LoadFromFile(const char *AppName, CFE_TBL_LoadBuff_t *WorkingBuffe int32 CFE_TBL_UpdateInternal(CFE_TBL_Handle_t TblHandle, CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_AccessDescriptor_t *AccessDescPtr) { - int32 Status = CFE_SUCCESS; - CFE_TBL_Handle_t AccessIterator; - bool LockStatus = false; + int32 Status = CFE_SUCCESS; + bool LockStatus = false; if ((!RegRecPtr->LoadPending) || (RegRecPtr->LoadInProgress == CFE_TBL_NO_LOAD_IN_PROGRESS)) { @@ -618,13 +652,7 @@ int32 CFE_TBL_UpdateInternal(CFE_TBL_Handle_t TblHandle, CFE_TBL_RegistryRec_t * else { /* Check to see if the Table is locked by anyone */ - AccessIterator = RegRecPtr->HeadOfAccessList; - while (AccessIterator != CFE_TBL_END_OF_LIST) - { - LockStatus = (LockStatus || CFE_TBL_Global.Handles[AccessIterator].LockFlag); - - AccessIterator = CFE_TBL_Global.Handles[AccessIterator].NextLink; - } + CFE_TBL_ForeachAccessDescriptor(RegRecPtr, CFE_TBL_CheckLockHelper, &LockStatus); if (LockStatus) { @@ -673,6 +701,17 @@ int32 CFE_TBL_UpdateInternal(CFE_TBL_Handle_t TblHandle, CFE_TBL_RegistryRec_t * return Status; } +/*---------------------------------------------------------------- + * + * Local helper function, not invoked outside this unit + * Intended to be used with CFE_TBL_ForeachAccessDescriptor() + * + *-----------------------------------------------------------------*/ +static void CFE_TBL_SetUpdatedHelper(CFE_TBL_AccessDescriptor_t *AccDescPtr, void *Arg) +{ + AccDescPtr->Updated = true; +} + /*---------------------------------------------------------------- * * Application-scope internal function @@ -681,8 +720,6 @@ int32 CFE_TBL_UpdateInternal(CFE_TBL_Handle_t TblHandle, CFE_TBL_RegistryRec_t * *-----------------------------------------------------------------*/ void CFE_TBL_NotifyTblUsersOfUpdate(CFE_TBL_RegistryRec_t *RegRecPtr) { - CFE_TBL_Handle_t AccessIterator; - /* Reset Load in Progress Values */ RegRecPtr->LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; RegRecPtr->TimeOfLastUpdate = CFE_TIME_GetTime(); @@ -690,13 +727,8 @@ void CFE_TBL_NotifyTblUsersOfUpdate(CFE_TBL_RegistryRec_t *RegRecPtr) /* Clear notification of pending load (as well as NO LOAD) and notify everyone of update */ RegRecPtr->LoadPending = false; RegRecPtr->TableLoadedOnce = true; - AccessIterator = RegRecPtr->HeadOfAccessList; - while (AccessIterator != CFE_TBL_END_OF_LIST) - { - CFE_TBL_Global.Handles[AccessIterator].Updated = true; - AccessIterator = CFE_TBL_Global.Handles[AccessIterator].NextLink; - } + CFE_TBL_ForeachAccessDescriptor(RegRecPtr, CFE_TBL_SetUpdatedHelper, NULL); } /*---------------------------------------------------------------- @@ -1353,3 +1385,164 @@ void CFE_TBL_RegisterWithCriticalTableRegistry(CFE_TBL_CritRegRec_t *CritRegRecP /* Mark the table as critical for future reference */ RegRecPtr->CriticalTable = true; } + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +static inline CFE_TBL_AccessDescriptor_t *CFE_TBL_HandleListGetNext(const CFE_TBL_HandleLink_t *Link) +{ + return CFE_TBL_LocateAccessDescriptorByHandle(Link->Next); +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +static inline CFE_TBL_AccessDescriptor_t *CFE_TBL_HandleListGetPrev(const CFE_TBL_HandleLink_t *Link) +{ + return CFE_TBL_LocateAccessDescriptorByHandle(Link->Prev); +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_TBL_HandleListGetSafeLink(CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_AccessDescriptor_t *AccDescPtr, + CFE_TBL_HandleLink_t **PtrOut, CFE_TBL_Handle_t *HandleOut) +{ + if (AccDescPtr == NULL) + { + /* Instead of returning NULL, return a pointer to the head node linkage */ + *PtrOut = &RegRecPtr->AccessList; + *HandleOut = CFE_TBL_END_OF_LIST; + } + else + { + /* Return a pointer to this linkage */ + *PtrOut = &AccDescPtr->Link; + *HandleOut = CFE_TBL_AccessDescriptorGetHandle(AccDescPtr); + } +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_TBL_HandleListRemoveLink(CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_AccessDescriptor_t *AccessDescPtr) +{ + CFE_TBL_HandleLink_t *LocalLink; + CFE_TBL_HandleLink_t *LocalPrevPtr; + CFE_TBL_HandleLink_t *LocalNextPtr; + CFE_TBL_Handle_t LocalHandle; + CFE_TBL_Handle_t PrevHandle; + CFE_TBL_Handle_t NextHandle; + + CFE_TBL_HandleListGetSafeLink(RegRecPtr, AccessDescPtr, &LocalLink, &LocalHandle); + CFE_TBL_HandleListGetSafeLink(RegRecPtr, CFE_TBL_HandleListGetNext(LocalLink), &LocalNextPtr, &NextHandle); + CFE_TBL_HandleListGetSafeLink(RegRecPtr, CFE_TBL_HandleListGetPrev(LocalLink), &LocalPrevPtr, &PrevHandle); + + LocalPrevPtr->Next = NextHandle; + LocalNextPtr->Prev = PrevHandle; + + /* now that it is removed, reset the link */ + CFE_TBL_HandleLinkInit(LocalLink); +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_TBL_HandleListInsertLink(CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_AccessDescriptor_t *AccessDescPtr) +{ + CFE_TBL_HandleLink_t *LocalLink; + CFE_TBL_HandleLink_t *LocalPrevPtr; + CFE_TBL_HandleLink_t *LocalNextPtr; + CFE_TBL_Handle_t LocalHandle; + CFE_TBL_Handle_t PrevHandle; + CFE_TBL_Handle_t NextHandle; + + /* inserting at the front, so the "previous" will always be the head node (NULL) */ + CFE_TBL_HandleListGetSafeLink(RegRecPtr, AccessDescPtr, &LocalLink, &LocalHandle); + CFE_TBL_HandleListGetSafeLink(RegRecPtr, NULL, &LocalPrevPtr, &PrevHandle); + CFE_TBL_HandleListGetSafeLink(RegRecPtr, CFE_TBL_HandleListGetNext(LocalPrevPtr), &LocalNextPtr, &NextHandle); + + LocalLink->Next = NextHandle; + LocalLink->Prev = PrevHandle; + + LocalPrevPtr->Next = LocalHandle; + LocalNextPtr->Prev = LocalHandle; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_TBL_ForeachAccessDescriptor(CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_AccessDescFunc_t Func, void *Arg) +{ + CFE_TBL_AccessDescriptor_t *AccDescPtr; + const CFE_TBL_HandleLink_t *LinkPtr; + + LinkPtr = &RegRecPtr->AccessList; + while (true) + { + AccDescPtr = CFE_TBL_HandleListGetNext(LinkPtr); + + if (AccDescPtr == NULL) + { + break; + } + + Func(AccDescPtr, Arg); + + LinkPtr = &AccDescPtr->Link; + } +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +void CFE_TBL_HandleLinkInit(CFE_TBL_HandleLink_t *LinkPtr) +{ + LinkPtr->Prev = CFE_TBL_END_OF_LIST; + LinkPtr->Next = CFE_TBL_END_OF_LIST; +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +bool CFE_TBL_HandleLinkIsAttached(CFE_TBL_HandleLink_t *LinkPtr) +{ + return (LinkPtr->Next != CFE_TBL_END_OF_LIST); +} + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * Intended to be used with CFE_TBL_ForeachAccessDescriptor() + * + *-----------------------------------------------------------------*/ +void CFE_TBL_CountAccessDescHelper(CFE_TBL_AccessDescriptor_t *AccDescPtr, void *Arg) +{ + uint32 *Count = Arg; + + ++(*Count); +} diff --git a/modules/tbl/fsw/src/cfe_tbl_internal.h b/modules/tbl/fsw/src/cfe_tbl_internal.h index cf1ab059f..76bc5bc3f 100644 --- a/modules/tbl/fsw/src/cfe_tbl_internal.h +++ b/modules/tbl/fsw/src/cfe_tbl_internal.h @@ -48,6 +48,17 @@ #define CFE_TBL_NOT_FOUND (-1) #define CFE_TBL_END_OF_LIST (CFE_TBL_Handle_t)0xFFFF +/** + * Function type used with access descriptor iterator + * + * The access descriptor iterator will invoke the supplied function + * for every descriptor associated with the table registry entry + * + * \param AccDescPtr Pointer to the current access descriptor + * \param Arg Opaque argument from caller (passed through) + */ +typedef void (* const CFE_TBL_AccessDescFunc_t)(CFE_TBL_AccessDescriptor_t *AccDescPtr, void *Arg); + /***************************** Function Prototypes **********************************/ /*---------------------------------------------------------------------------------------*/ @@ -537,6 +548,105 @@ CFE_Status_t CFE_TBL_RestoreTableDataFromCDS(CFE_TBL_RegistryRec_t *RegRecPtr, c void CFE_TBL_RegisterWithCriticalTableRegistry(CFE_TBL_CritRegRec_t *CritRegRecPtr, CFE_TBL_RegistryRec_t *RegRecPtr, const char *TblName); +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Generic iterator for access descriptors associated with a Table Registry +** +** \par Description +** This function iterates through the list of access descriptors that are associated +** with the given table registry entry. The user-supplied callback function will be +** invoked for each access descriptor, with the opaque pointer argument passed as a +** parameter. +** +** \par Assumptions, External Events, and Notes: +** The caller should ensure that the list is not modified by other threads during this call +** +** \param RegRecPtr The pointer to the registry record +** \param Func The function to invoke for each access descriptor +** \param Arg Opaque argument, passed through to function +*/ +void CFE_TBL_ForeachAccessDescriptor(CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_AccessDescFunc_t Func, void *Arg); + +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Handle iterator function that increments a counter +** +** \par Description +** When used with CFE_TBL_ForeachAccessDescriptor() this will count the number of entries +** +** \par Assumptions, External Events, and Notes: +** This is declared here so it can be used in several places that count descriptors +** +** \param AccDescPtr Pointer to descriptor entry, not used +** \param Arg a pointer to a uint32 value that is incremented on each call +*/ +void CFE_TBL_CountAccessDescHelper(CFE_TBL_AccessDescriptor_t *AccDescPtr, void *Arg); + +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Initializes a handle link +** +** \par Description +** Sets the handle link to initial condition, where it is not a member of any list +** After this call, CFE_TBL_HandleLinkIsAttached() on this link will always return false +** +** \par Assumptions, External Events, and Notes: +** None +** +** \param LinkPtr Pointer to link entry to initialize +*/ +void CFE_TBL_HandleLinkInit(CFE_TBL_HandleLink_t *LinkPtr); + +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Checks if a handle link is attached to another entry +** +** \par Description +** This will return true if the passed-in link is attached to another list node, +** indicating it is part of a list. Conversely, this will return false if the +** link is not attached to another node, indicating a singleton or empty list. +** +** \par Assumptions, External Events, and Notes: +** None +** +** \param LinkPtr Pointer to link entry to check +** \retval true if the link node is part of a list (attached) +** \retval false if the link node is not part of a list (detached) +*/ +bool CFE_TBL_HandleLinkIsAttached(CFE_TBL_HandleLink_t *LinkPtr); + +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Removes the given access descriptor from the registry list +** +** \par Description +** This will disassociate the access descriptor from the table registry record by +** removing/extracting the access descriptor from the linked list +** +** \par Assumptions, External Events, and Notes: +** None +** +** \param RegRecPtr The table registry record that is associated with the access descriptor +** \param AccessDescPtr The access descriptor that is to be removed from the list +*/ +void CFE_TBL_HandleListRemoveLink(CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_AccessDescriptor_t *AccessDescPtr); + +/*---------------------------------------------------------------------------------------*/ +/** +** \brief Inserts the given access descriptor into the registry list +** +** \par Description +** This will associate the access descriptor with the table registry record by +** inserting the access descriptor into the linked list +** +** \par Assumptions, External Events, and Notes: +** None +** +** \param RegRecPtr The table registry record that should be associated with the access descriptor +** \param AccessDescPtr The access descriptor that is to be added to the list +*/ +void CFE_TBL_HandleListInsertLink(CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_AccessDescriptor_t *AccessDescPtr); + /* ** Globals specific to the TBL module */ diff --git a/modules/tbl/fsw/src/cfe_tbl_resource.c b/modules/tbl/fsw/src/cfe_tbl_resource.c index d2428a1b8..9f0113f73 100644 --- a/modules/tbl/fsw/src/cfe_tbl_resource.c +++ b/modules/tbl/fsw/src/cfe_tbl_resource.c @@ -35,7 +35,7 @@ /*---------------------------------------------------------------- * - * Implemented per public API + * Application-scope internal function * See description in header file for argument/return detail * *-----------------------------------------------------------------*/ @@ -50,9 +50,10 @@ CFE_Status_t CFE_TBL_Handle_ToIndex(CFE_TBL_Handle_t TblHandle, uint32 *Idx) return CFE_SUCCESS; } + /*---------------------------------------------------------------- * - * Implemented per public API + * Application-scope internal function * See description in header file for argument/return detail * *-----------------------------------------------------------------*/ @@ -91,6 +92,18 @@ CFE_TBL_RegistryRec_t *CFE_TBL_LocateRegistryRecordByID(CFE_TBL_RegId_t RegId) return RegRecPtr; } +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_TBL_RegId_t CFE_TBL_RegistryRecordGetID(const CFE_TBL_RegistryRec_t *RegRecPtr) +{ + /* The pointer should be to an entry within the Registry array */ + return (RegRecPtr - CFE_TBL_Global.Registry); +} + /*---------------------------------------------------------------- * * Application-scope internal function @@ -113,3 +126,15 @@ CFE_TBL_AccessDescriptor_t *CFE_TBL_LocateAccessDescriptorByHandle(CFE_TBL_Handl return AccessDescPtr; } + +/*---------------------------------------------------------------- + * + * Application-scope internal function + * See description in header file for argument/return detail + * + *-----------------------------------------------------------------*/ +CFE_TBL_Handle_t CFE_TBL_AccessDescriptorGetHandle(const CFE_TBL_AccessDescriptor_t *AccessDescPtr) +{ + /* The pointer should be to an entry within the Handles array */ + return (AccessDescPtr - CFE_TBL_Global.Handles); +} diff --git a/modules/tbl/fsw/src/cfe_tbl_resource.h b/modules/tbl/fsw/src/cfe_tbl_resource.h index 6cf4d0f56..2195665ec 100644 --- a/modules/tbl/fsw/src/cfe_tbl_resource.h +++ b/modules/tbl/fsw/src/cfe_tbl_resource.h @@ -38,7 +38,7 @@ /*---------------------------------------------------------------------------------------*/ /** - * @brief Locate the app table entry correlating with a given app ID. + * @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. @@ -47,7 +47,7 @@ * 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. + * 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 @@ -59,67 +59,45 @@ * * @sa CFE_TBL_RegistryRecordIsMatch() * - * @param[in] RegId the app ID to locate - * @return pointer to App Table entry for the given app ID, or NULL if out of range + * @param[in] RegId the registry ID to locate + * @return pointer to Registry Table entry for the given registry ID, or NULL if out of range */ CFE_TBL_RegistryRec_t *CFE_TBL_LocateRegistryRecordByID(CFE_TBL_RegId_t RegId); /*---------------------------------------------------------------------------------------*/ /** - * @brief Locate the task table entry correlating with a given task ID. + * @brief Locate the access descriptor entry correlating with a given table handle. * - * This only returns a pointer to the table entry where the record + * This only returns a pointer to the table entry where the descriptor * 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 tasks, 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. + * 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. + * confirm that the returned descriptor is a match to the expected ID before using + * or modifying the data within the returned descriptor pointer. * * The CFE_TBL_AccessDescriptorIsMatch() function can be used to check/confirm * if the returned table entry is a positive match for the given ID. * * @sa CFE_TBL_AccessDescriptorIsMatch() * - * @param[in] TblHandle the task ID to locate - * @return pointer to Task Table entry for the given task ID, or NULL if out of range + * @param[in] TblHandle the table handle to locate + * @return pointer to decriptor table entry for the given table handle, or NULL if out of range */ CFE_TBL_AccessDescriptor_t *CFE_TBL_LocateAccessDescriptorByHandle(CFE_TBL_Handle_t TblHandle); -#ifdef jphfix /*---------------------------------------------------------------------------------------*/ /** - * @brief Check if an app record is in use or free/empty + * @brief Check if a registry record is a match for the given RegId * - * This routine checks if the App 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. - * - * @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] RegRecPtr pointer to app table entry - * @returns true if the entry is in use/configured, or false if it is free/empty - */ -static inline bool CFE_TBL_RegistryRecordIsUsed(const CFE_TBL_RegistryRec_t *RegRecPtr) -{ - return RegRecPtr->Taken; -} -#endif - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Check if an app record is a match for the given RegId - * - * This routine confirms that the previously-located record is valid - * and matches the expected app ID. + * This routine confirms that the previously-located registry record is valid + * and matches the expected registry ID. * * As this dereferences fields within the record, global data must be * locked prior to invoking this function. @@ -134,9 +112,9 @@ static inline bool CFE_TBL_RegistryRecordIsUsed(const CFE_TBL_RegistryRec_t *Reg * * @sa CFE_TBL_LocateRegistryRecordByID * - * @param[in] RegRecPtr pointer to app table entry, or NULL - * @param[in] RegId expected app ID - * @returns true if the entry matches the given app ID + * @param[in] RegRecPtr pointer to registry table entry, or NULL + * @param[in] RegId expected registry ID + * @returns true if the entry matches the given registry ID */ static inline bool CFE_TBL_RegistryRecordIsMatch(const CFE_TBL_RegistryRec_t *RegRecPtr, CFE_TBL_RegId_t RegId) { @@ -164,92 +142,23 @@ static inline const char *CFE_TBL_RegistryRecordGetName(const CFE_TBL_RegistryRe return RegRecPtr->Name; } -#ifdef jphfix /*---------------------------------------------------------------------------------------*/ /** - * @brief Get the ID value from a Task table entry + * @brief Get the Handle ID from an an access descriptor pointer * - * This routine converts the table entry back to an abstract ID. - * - * As this dereferences fields within the record, global data must be - * locked prior to invoking this function. + * This routine converts a pointer to a handle table entry to an 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] AccessDescPtr pointer to Task table entry + * @param[in] AccessDescPtr pointer to access descriptor * @returns TblHandle of entry */ -static inline CFE_TBL_Handle_t CFE_TBL_AccessDescriptorGetID(const CFE_TBL_AccessDescriptor_t *AccessDescPtr) -{ - return AccessDescPtr->TblHandle; -} +CFE_TBL_Handle_t CFE_TBL_AccessDescriptorGetHandle(const CFE_TBL_AccessDescriptor_t *AccessDescPtr); /*---------------------------------------------------------------------------------------*/ /** - * @brief Check if a Task record is in use or free/empty - * - * This routine checks if the Task 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. - * - * @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] AccessDescPtr pointer to task table entry - * @returns true if the entry is in use/configured, or false if it is free/empty - */ -static inline bool CFE_TBL_AccessDescriptorIsUsed(const CFE_TBL_AccessDescriptor_t *AccessDescPtr) -{ - return CFE_RESOURCEID_TEST_DEFINED(AccessDescPtr->TblHandle); -} - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Marks a Task table entry as used (not free) - * - * This sets the internal field(s) within this entry, and marks - * it as being associated with the given Task ID. - * - * 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 record pointers - * that are known to refer to an actual table location (i.e. non-null). - * - * @param[in] AccessDescPtr pointer to Task table entry - * @param[in] PendingId the Task ID of this entry - */ -static inline void CFE_TBL_AccessDescriptorSetUsed(CFE_TBL_AccessDescriptor_t *AccessDescPtr, - CFE_ResourceId_t PendingId) -{ - AccessDescPtr->TblHandle = CFE_TBL_ACCESSID_C(PendingId); -} - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Set a Task record table entry free - * - * This allows the table entry to be re-used by another Task. - * - * 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 record pointers - * that are known to refer to an actual table location (i.e. non-null). - * - * @param[in] AccessDescPtr pointer to task table entry - */ -static inline void CFE_TBL_AccessDescriptorSetFree(CFE_TBL_AccessDescriptor_t *AccessDescPtr) -{ - AccessDescPtr->TblHandle = CFE_TBL_ACCESSID_UNDEFINED; -} -#endif - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Check if a Task record is a match for the given TblHandle + * @brief Check if an Access Descriptor is a match for the given TblHandle * * This routine confirms that the previously-located record is valid * and matches the expected Task ID. @@ -257,7 +166,7 @@ static inline void CFE_TBL_AccessDescriptorSetFree(CFE_TBL_AccessDescriptor_t *A * 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_LocateTaskRecordByID() + * This function may be used in conjunction with CFE_TBL_LocateAccessDescriptorByHandle() * 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. @@ -265,11 +174,11 @@ static inline void CFE_TBL_AccessDescriptorSetFree(CFE_TBL_AccessDescriptor_t *A * Once a record pointer has been successfully validated using this routine, * it may be safely passed to all other internal functions. * - * @sa CFE_TBL_LocateTaskRecordByID + * @sa CFE_TBL_LocateAccessDescriptorByHandle * - * @param[in] AccessDescPtr pointer to task table entry - * @param[in] TblHandle The expected task ID to verify - * @returns true if the entry matches the given task ID + * @param[in] AccessDescPtr pointer to access descriptor table entry + * @param[in] TblHandle The expected table handle to verify + * @returns true if the descriptor entry matches the given table handle */ static inline bool CFE_TBL_AccessDescriptorIsMatch(const CFE_TBL_AccessDescriptor_t *AccessDescPtr, CFE_TBL_Handle_t TblHandle) @@ -277,240 +186,4 @@ static inline bool CFE_TBL_AccessDescriptorIsMatch(const CFE_TBL_AccessDescripto return (AccessDescPtr != NULL && AccessDescPtr->UsedFlag); } -#ifdef jphfix -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Obtain the name associated with the Task record - * - * Returns the name field from within the Task record - * - * @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] AccessDescPtr pointer to Task table entry - * @returns Pointer to Task name - */ -static inline const char *CFE_TBL_AccessDescriptorGetName(const CFE_TBL_AccessDescriptor_t *AccessDescPtr) -{ - return AccessDescPtr->TaskName; -} - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Check if a Counter record is in use or free/empty - * - * This routine checks if the Counter 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. - * - * @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] CounterRecPtr pointer to Counter table entry - * @returns true if the entry is in use/configured, or false if it is free/empty - */ -static inline bool CFE_TBL_CounterRecordIsUsed(const CFE_TBL_GenCounterRecord_t *CounterRecPtr) -{ - return CFE_RESOURCEID_TEST_DEFINED(CounterRecPtr->CounterId); -} - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Get the ID value from a Counter table entry - * - * This routine converts the table entry back to an abstract 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] CounterRecPtr pointer to Counter table entry - * @returns CounterID of entry - */ -static inline CFE_TBL_CounterId_t CFE_TBL_CounterRecordGetID(const CFE_TBL_GenCounterRecord_t *CounterRecPtr) -{ - return CounterRecPtr->CounterId; -} - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Marks a Counter table entry as used (not free) - * - * This sets the internal field(s) within this entry, and marks - * it as being associated with the given Counter ID. - * - * 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 record pointers - * that are known to refer to an actual table location (i.e. non-null). - * - * @param[in] CounterRecPtr pointer to Counter table entry - * @param[in] PendingId the Counter ID of this entry - */ -static inline void CFE_TBL_CounterRecordSetUsed(CFE_TBL_GenCounterRecord_t *CounterRecPtr, CFE_ResourceId_t PendingId) -{ - CounterRecPtr->CounterId = CFE_TBL_COUNTERID_C(PendingId); -} - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Set a Counter 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. - * - * 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 record pointers - * that are known to refer to an actual table location (i.e. non-null). - * - * @param[in] CounterRecPtr pointer to Counter table entry - */ -static inline void CFE_TBL_CounterRecordSetFree(CFE_TBL_GenCounterRecord_t *CounterRecPtr) -{ - CounterRecPtr->CounterId = CFE_TBL_COUNTERID_UNDEFINED; -} - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Check if a Counter record is a match for the given CounterID - * - * This routine confirms that the previously-located record is valid - * and matches the expected Counter 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_LocateCounterRecordByID() - * 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_LocateCounterRecordByID - * - * @param[in] CounterRecPtr pointer to Counter table entry - * @param[in] CounterID expected Counter ID - * @returns true if the entry matches the given Counter ID - */ -static inline bool CFE_TBL_CounterRecordIsMatch(const CFE_TBL_GenCounterRecord_t *CounterRecPtr, - CFE_TBL_CounterId_t CounterID) -{ - return (CounterRecPtr != NULL && CFE_RESOURCEID_TEST_EQUAL(CounterRecPtr->CounterId, CounterID)); -} - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Obtain the name associated with the counter record - * - * Returns the name field from within the counter record - * - * @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] CounterRecPtr pointer to Counter table entry - * @returns Pointer to counter name - */ -static inline const char *CFE_TBL_CounterRecordGetName(const CFE_TBL_GenCounterRecord_t *CounterRecPtr) -{ - return CounterRecPtr->CounterName; -} -#endif - -/* - * 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 Finds an application table record matching the given name - * - * Helper function, aids in finding an application record from a name string. - * Must be called while locked. - * - * @returns pointer to table entry matching name, or NULL if not found - */ -CFE_TBL_RegistryRec_t *CFE_TBL_LocateRegistryRecordByName(const char *Name); - -#ifdef jphfix -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Finds a library table record matching the given name - * - * Helper function, aids in finding a library record from a name string. - * Must be called while locked. - * - * @returns pointer to table entry matching name, or NULL if not found - */ -CFE_TBL_LoadBuff_t *CFE_TBL_LocateLibRecordByName(const char *Name); - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Finds a task table record matching the given name - * - * Helper function, aids in finding a task record from a name string. - * Must be called while locked. - * - * @returns pointer to table entry matching name, or NULL if not found - */ -CFE_TBL_AccessDescriptor_t *CFE_TBL_LocateTaskRecordByName(const char *Name); - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Finds a counter table record matching the given name - * - * Helper function, aids in finding a counter record from a name string. - * Must be called while locked. - * - * @returns pointer to table entry matching name, or NULL if not found - */ -CFE_TBL_GenCounterRecord_t *CFE_TBL_LocateCounterRecordByName(const char *Name); -#endif - -/* - * Availability check functions used in conjunction with CFE_ResourceId_FindNext() - */ - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Checks if Application slot is currently used - * - * Helper function, Aids in allocating a new ID by checking if - * a given ID is available. Must be called while locked. - * - * @returns false if slot is unused/available, true if used/unavailable - */ -bool CFE_TBL_CheckRegIdSlotUsed(CFE_ResourceId_t CheckId); - -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Checks if Library slot is currently used - * - * Helper function, Aids in allocating a new ID by checking if - * a given ID is available. Must be called while locked. - * - * @returns false if slot is unused/available, true if used/unavailable - */ -bool CFE_TBL_CheckSharedBufferSlotUsed(CFE_ResourceId_t CheckId); - -#ifdef jphfix -/*---------------------------------------------------------------------------------------*/ -/** - * @brief Checks if Counter slot is currently used - * - * Helper function, Aids in allocating a new ID by checking if - * a given ID is available. Must be called while locked. - * - * @returns false if slot is unused/available, true if used/unavailable - */ -bool CFE_TBL_CheckCounterIdSlotUsed(CFE_ResourceId_t CheckId); -#endif - #endif /* CFE_TBL_RESOURCE_H */ diff --git a/modules/tbl/fsw/src/cfe_tbl_task.h b/modules/tbl/fsw/src/cfe_tbl_task.h index a97269776..d1e369b7c 100644 --- a/modules/tbl/fsw/src/cfe_tbl_task.h +++ b/modules/tbl/fsw/src/cfe_tbl_task.h @@ -145,6 +145,15 @@ typedef struct */ typedef int16 CFE_TBL_RegId_t; +/** + * A structure to facilitate a linked-list of table handles + */ +typedef struct CFE_TBL_HandleLink +{ + CFE_TBL_Handle_t Next; /**< Next table handle in list */ + CFE_TBL_Handle_t Prev; /**< Previous table handle in list */ +} CFE_TBL_HandleLink_t; + /*******************************************************************************/ /** \brief Application to Table Access Descriptor ** @@ -155,14 +164,13 @@ typedef int16 CFE_TBL_RegId_t; */ typedef struct { - CFE_ES_AppId_t AppId; /**< \brief Application ID to verify access */ - CFE_TBL_RegId_t RegIndex; /**< \brief Index into Table Registry (a.k.a. - Global Table #) */ - CFE_TBL_Handle_t PrevLink; /**< \brief Index of previous access descriptor in linked list */ - CFE_TBL_Handle_t NextLink; /**< \brief Index of next access descriptor in linked list */ - bool UsedFlag; /**< \brief Indicates whether this descriptor is being used or not */ - bool LockFlag; /**< \brief Indicates whether thread is currently accessing table data */ - bool Updated; /**< \brief Indicates table has been updated since last GetAddress call */ - uint8 BufferIndex; /**< \brief Index of buffer currently being used */ + CFE_ES_AppId_t AppId; /**< \brief Application ID to verify access */ + CFE_TBL_RegId_t RegIndex; /**< \brief Index into Table Registry (a.k.a. - Global Table #) */ + CFE_TBL_HandleLink_t Link; /**< \brief Linkage into list of access descriptors for the table */ + bool UsedFlag; /**< \brief Indicates whether this descriptor is being used or not */ + bool LockFlag; /**< \brief Indicates whether thread is currently accessing table data */ + bool Updated; /**< \brief Indicates table has been updated since last GetAddress call */ + uint8 BufferIndex; /**< \brief Index of buffer currently being used */ } CFE_TBL_AccessDescriptor_t; /*******************************************************************************/ @@ -180,7 +188,7 @@ typedef struct CFE_TBL_LoadBuff_t Buffers[2]; /**< \brief Active and Inactive Buffer Pointers */ CFE_TBL_CallbackFuncPtr_t ValidationFuncPtr; /**< \brief Ptr to Owner App's function that validates tbl contents */ CFE_TIME_SysTime_t TimeOfLastUpdate; /**< \brief Time when Table was last updated */ - CFE_TBL_Handle_t HeadOfAccessList; /**< \brief Index into Handles Array that starts Access Linked List */ + CFE_TBL_HandleLink_t AccessList; /**< \brief Linked List of associated access descriptors */ int32 LoadInProgress; /**< \brief Flag identifies inactive buffer and whether load in progress */ int32 ValidateActiveIndex; /**< \brief Index to Validation Request on Active Table Result data */ int32 ValidateInactiveIndex; /**< \brief Index to Validation Request on Inactive Table Result data */ diff --git a/modules/tbl/fsw/src/cfe_tbl_task_cmds.c b/modules/tbl/fsw/src/cfe_tbl_task_cmds.c index e2cd7019a..afb4f5536 100644 --- a/modules/tbl/fsw/src/cfe_tbl_task_cmds.c +++ b/modules/tbl/fsw/src/cfe_tbl_task_cmds.c @@ -1018,8 +1018,8 @@ bool CFE_TBL_DumpRegistryGetter(void *Meta, uint32 RecordNum, void **Buffer, siz { CFE_TBL_RegDumpStateInfo_t *StatePtr = (CFE_TBL_RegDumpStateInfo_t *)Meta; CFE_TBL_RegistryRec_t * RegRecPtr; - CFE_TBL_Handle_t HandleIterator; CFE_ES_AppId_t OwnerAppId; + uint32 NumUsers; bool IsValidEntry; IsValidEntry = false; @@ -1035,7 +1035,7 @@ bool CFE_TBL_DumpRegistryGetter(void *Meta, uint32 RecordNum, void **Buffer, siz /* Check to see if the Registry entry is empty */ if (!CFE_RESOURCEID_TEST_EQUAL(RegRecPtr->OwnerAppId, CFE_TBL_NOT_OWNED) || - (RegRecPtr->HeadOfAccessList != CFE_TBL_END_OF_LIST)) + CFE_TBL_HandleLinkIsAttached(&RegRecPtr->AccessList)) { IsValidEntry = true; OwnerAppId = RegRecPtr->OwnerAppId; @@ -1078,13 +1078,10 @@ bool CFE_TBL_DumpRegistryGetter(void *Meta, uint32 RecordNum, void **Buffer, siz StatePtr->DumpRecord.LastFileLoaded[sizeof(StatePtr->DumpRecord.LastFileLoaded) - 1] = 0; /* Walk the access descriptor list to determine the number of users */ - StatePtr->DumpRecord.NumUsers = 0; - HandleIterator = RegRecPtr->HeadOfAccessList; - while (HandleIterator != CFE_TBL_END_OF_LIST) - { - StatePtr->DumpRecord.NumUsers++; - HandleIterator = CFE_TBL_Global.Handles[HandleIterator].NextLink; - } + + NumUsers = 0; + CFE_TBL_ForeachAccessDescriptor(RegRecPtr, CFE_TBL_CountAccessDescHelper, &NumUsers); + StatePtr->DumpRecord.NumUsers = NumUsers; } /* Unlock now - remainder of data gathering uses ES */ diff --git a/modules/tbl/fsw/src/cfe_tbl_transaction.c b/modules/tbl/fsw/src/cfe_tbl_transaction.c index a1fcc9d28..68dcc92c5 100644 --- a/modules/tbl/fsw/src/cfe_tbl_transaction.c +++ b/modules/tbl/fsw/src/cfe_tbl_transaction.c @@ -223,6 +223,24 @@ void CFE_TBL_TxnFinish(CFE_TBL_TxnState_t *Txn) } } +/*---------------------------------------------------------------- + * + * Local helper function, not invoked outside this unit + * Intended to be used with CFE_TBL_ForeachAccessDescriptor() + * + *-----------------------------------------------------------------*/ +static void CFE_TBL_FindAccessDescHelper(CFE_TBL_AccessDescriptor_t *AccDescPtr, void *Arg) +{ + CFE_TBL_TxnState_t *Txn = Arg; + + if (AccDescPtr->UsedFlag && AccDescPtr->RegIndex == CFE_TBL_TxnRegId(Txn) && + CFE_RESOURCEID_TEST_EQUAL(AccDescPtr->AppId, CFE_TBL_TxnAppId(Txn))) + { + Txn->Handle = CFE_TBL_AccessDescriptorGetHandle(AccDescPtr); + Txn->AccessDescPtr = AccDescPtr; + } +} + /*---------------------------------------------------------------- * * Application-scope internal function @@ -231,26 +249,20 @@ void CFE_TBL_TxnFinish(CFE_TBL_TxnState_t *Txn) *-----------------------------------------------------------------*/ CFE_Status_t CFE_TBL_FindAccessDescriptorForSelf(CFE_TBL_TxnState_t *Txn) { - CFE_Status_t Status = CFE_TBL_ERR_UNREGISTERED; - CFE_TBL_Handle_t AccessIndex; + CFE_Status_t Status; CFE_TBL_RegistryRec_t *RegRecPtr; /* Find the existing access descriptor for the table */ - RegRecPtr = CFE_TBL_TxnRegRec(Txn); - AccessIndex = RegRecPtr->HeadOfAccessList; + RegRecPtr = CFE_TBL_TxnRegRec(Txn); + CFE_TBL_ForeachAccessDescriptor(RegRecPtr, CFE_TBL_FindAccessDescHelper, Txn); - while (AccessIndex != CFE_TBL_END_OF_LIST) + if (Txn->AccessDescPtr == NULL) { - if ((CFE_TBL_Global.Handles[AccessIndex].UsedFlag == true) && - CFE_RESOURCEID_TEST_EQUAL(CFE_TBL_Global.Handles[AccessIndex].AppId, CFE_TBL_TxnAppId(Txn)) && - (CFE_TBL_Global.Handles[AccessIndex].RegIndex == CFE_TBL_TxnRegId(Txn))) - { - Txn->Handle = AccessIndex; - Txn->AccessDescPtr = &CFE_TBL_Global.Handles[AccessIndex]; - break; - } - - AccessIndex = CFE_TBL_Global.Handles[AccessIndex].NextLink; + Status = CFE_TBL_ERR_UNREGISTERED; + } + else + { + Status = CFE_SUCCESS; } return Status; @@ -305,37 +317,13 @@ CFE_Status_t CFE_TBL_TxnRemoveAccessLink(CFE_TBL_TxnState_t *Txn) * NOTE: In all cases where this is invoked, the registry should * already be locked under the transaction object */ - - /* If we are removing the head of the linked list, then point */ - /* the head pointer to the link after this one */ - if (AccessDescPtr->PrevLink == CFE_TBL_END_OF_LIST) - { - RegRecPtr->HeadOfAccessList = AccessDescPtr->NextLink; - - /* Update the next link, if there is one, to be the new head of the list */ - if (AccessDescPtr->NextLink != CFE_TBL_END_OF_LIST) - { - CFE_TBL_Global.Handles[AccessDescPtr->NextLink].PrevLink = CFE_TBL_END_OF_LIST; - } - } - else /* Access Descriptor is not the head of the list */ - { - /* Set the next link on the previous link to the next link of the link being removed */ - CFE_TBL_Global.Handles[AccessDescPtr->PrevLink].NextLink = AccessDescPtr->NextLink; - - /* If this link is not the end of the list, then complete two way linkage */ - /* by setting the next link's previous link to the previous link of the link being removed */ - if (AccessDescPtr->NextLink != CFE_TBL_END_OF_LIST) - { - CFE_TBL_Global.Handles[AccessDescPtr->NextLink].PrevLink = AccessDescPtr->PrevLink; - } - } + CFE_TBL_HandleListRemoveLink(RegRecPtr, AccessDescPtr); /* Return the Access Descriptor to the pool */ AccessDescPtr->UsedFlag = false; /* If this was the last Access Descriptor for this table, we can free the memory buffers as well */ - if (RegRecPtr->HeadOfAccessList == CFE_TBL_END_OF_LIST) + if (!CFE_TBL_HandleLinkIsAttached(&RegRecPtr->AccessList)) { /* Only free memory that we have allocated. If the image is User Defined, then don't bother */ if (RegRecPtr->UserDefAddr == false) @@ -504,7 +492,7 @@ CFE_Status_t CFE_TBL_TxnAllocateRegistryEntry(CFE_TBL_TxnState_t *Txn) /* A Table Registry is only "Free" when there isn't an owner AND */ /* all other applications are not sharing or locking the table */ if (CFE_RESOURCEID_TEST_EQUAL(CFE_TBL_Global.Registry[i].OwnerAppId, CFE_TBL_NOT_OWNED) && - (CFE_TBL_Global.Registry[i].HeadOfAccessList == CFE_TBL_END_OF_LIST)) + !CFE_TBL_HandleLinkIsAttached(&CFE_TBL_Global.Registry[i].AccessList)) { Txn->RegId = i; Txn->RegRecPtr = &CFE_TBL_Global.Registry[i]; @@ -627,6 +615,8 @@ void CFE_TBL_TxnConnectAccessDescriptor(CFE_TBL_TxnState_t *Txn) AccessDescPtr->AppId = CFE_TBL_TxnAppId(Txn); AccessDescPtr->LockFlag = false; AccessDescPtr->Updated = false; + AccessDescPtr->UsedFlag = true; + AccessDescPtr->RegIndex = CFE_TBL_TxnRegId(Txn); if ((RegRecPtr->DumpOnly) && (!RegRecPtr->UserDefAddr)) { @@ -635,13 +625,5 @@ void CFE_TBL_TxnConnectAccessDescriptor(CFE_TBL_TxnState_t *Txn) RegRecPtr->TableLoadedOnce = true; } - AccessDescPtr->RegIndex = CFE_TBL_TxnRegId(Txn); - - AccessDescPtr->PrevLink = CFE_TBL_END_OF_LIST; /* We are the head of the list */ - AccessDescPtr->NextLink = CFE_TBL_END_OF_LIST; /* We are the end of the list */ - - AccessDescPtr->UsedFlag = true; - - /* Make sure the Table Registry entry points to First Access Descriptor */ - RegRecPtr->HeadOfAccessList = CFE_TBL_TxnHandle(Txn); + CFE_TBL_HandleListInsertLink(RegRecPtr, AccessDescPtr); } diff --git a/modules/tbl/ut-coverage/tbl_UT.c b/modules/tbl/ut-coverage/tbl_UT.c index 2d8ce6802..b1358578f 100644 --- a/modules/tbl/ut-coverage/tbl_UT.c +++ b/modules/tbl/ut-coverage/tbl_UT.c @@ -197,10 +197,9 @@ void UT_ResetTableRegistry(void) /* Initialize the table access descriptors */ for (i = 0; i < CFE_PLATFORM_TBL_MAX_NUM_HANDLES; i++) { - CFE_TBL_Global.Handles[i].AppId = CFE_TBL_NOT_OWNED; - CFE_TBL_Global.Handles[i].RegIndex = 0; - CFE_TBL_Global.Handles[i].PrevLink = CFE_TBL_END_OF_LIST; - CFE_TBL_Global.Handles[i].NextLink = CFE_TBL_END_OF_LIST; + CFE_TBL_Global.Handles[i].AppId = CFE_TBL_NOT_OWNED; + CFE_TBL_Global.Handles[i].RegIndex = 0; + CFE_TBL_HandleLinkInit(&CFE_TBL_Global.Handles[i].Link); CFE_TBL_Global.Handles[i].UsedFlag = false; CFE_TBL_Global.Handles[i].LockFlag = false; CFE_TBL_Global.Handles[i].Updated = false; @@ -905,7 +904,7 @@ void Test_CFE_TBL_DumpRegCmd(void) for (q = 0; q < CFE_PLATFORM_TBL_MAX_NUM_TABLES; q++) { - CFE_TBL_Global.Registry[q].HeadOfAccessList = CFE_TBL_END_OF_LIST; + CFE_TBL_HandleLinkInit(&CFE_TBL_Global.Registry[q].AccessList); } /* Test command using the default dump file name (nominal path) */ @@ -967,37 +966,38 @@ void Test_CFE_TBL_DumpRegCmd(void) * table is successfully dumped */ UT_InitData(); - CFE_TBL_Global.Registry[0].OwnerAppId = AppID; - CFE_TBL_Global.Registry[0].HeadOfAccessList = CFE_TBL_END_OF_LIST; - CFE_TBL_Global.Registry[1].OwnerAppId = CFE_TBL_NOT_OWNED; - CFE_TBL_Global.Registry[0].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; - CFE_TBL_Global.Registry[0].DoubleBuffered = true; - LocalBuf = NULL; - LocalSize = 0; + CFE_TBL_Global.Registry[0].OwnerAppId = AppID; + CFE_TBL_HandleLinkInit(&CFE_TBL_Global.Registry[0].AccessList); + CFE_TBL_Global.Registry[1].OwnerAppId = CFE_TBL_NOT_OWNED; + CFE_TBL_Global.Registry[0].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; + CFE_TBL_Global.Registry[0].DoubleBuffered = true; + LocalBuf = NULL; + LocalSize = 0; UtAssert_BOOL_FALSE(CFE_TBL_DumpRegistryGetter(&CFE_TBL_Global.RegDumpState, 0, &LocalBuf, &LocalSize)); UtAssert_NOT_NULL(LocalBuf); UtAssert_NONZERO(LocalSize); /* Same but not double buffered */ UT_InitData(); - CFE_TBL_Global.Registry[0].OwnerAppId = AppID; - CFE_TBL_Global.Registry[0].HeadOfAccessList = CFE_TBL_END_OF_LIST; - CFE_TBL_Global.Registry[1].OwnerAppId = CFE_TBL_NOT_OWNED; - CFE_TBL_Global.Registry[0].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; - CFE_TBL_Global.Registry[0].DoubleBuffered = false; - LocalBuf = NULL; - LocalSize = 0; + CFE_TBL_Global.Registry[0].OwnerAppId = AppID; + CFE_TBL_HandleLinkInit(&CFE_TBL_Global.Registry[0].AccessList); + CFE_TBL_Global.Registry[1].OwnerAppId = CFE_TBL_NOT_OWNED; + CFE_TBL_Global.Registry[0].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS + 1; + CFE_TBL_Global.Registry[0].DoubleBuffered = false; + LocalBuf = NULL; + LocalSize = 0; UtAssert_BOOL_FALSE(CFE_TBL_DumpRegistryGetter(&CFE_TBL_Global.RegDumpState, 0, &LocalBuf, &LocalSize)); UtAssert_NOT_NULL(LocalBuf); UtAssert_NONZERO(LocalSize); /* Hit last entry, no load in progress */ - CFE_TBL_Global.Registry[CFE_PLATFORM_TBL_MAX_NUM_TABLES - 1].OwnerAppId = CFE_TBL_NOT_OWNED; - CFE_TBL_Global.Registry[CFE_PLATFORM_TBL_MAX_NUM_TABLES - 1].HeadOfAccessList = 2; - CFE_TBL_Global.Registry[CFE_PLATFORM_TBL_MAX_NUM_TABLES - 1].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; - CFE_TBL_Global.Handles[2].NextLink = CFE_TBL_END_OF_LIST; - LocalBuf = NULL; - LocalSize = 0; + CFE_TBL_Global.Registry[CFE_PLATFORM_TBL_MAX_NUM_TABLES - 1].OwnerAppId = CFE_TBL_NOT_OWNED; + CFE_TBL_Global.Registry[CFE_PLATFORM_TBL_MAX_NUM_TABLES - 1].AccessList.Next = 2; + CFE_TBL_Global.Registry[CFE_PLATFORM_TBL_MAX_NUM_TABLES - 1].AccessList.Prev = 2; + CFE_TBL_Global.Registry[CFE_PLATFORM_TBL_MAX_NUM_TABLES - 1].LoadInProgress = CFE_TBL_NO_LOAD_IN_PROGRESS; + CFE_TBL_HandleLinkInit(&CFE_TBL_Global.Handles[2].Link); + LocalBuf = NULL; + LocalSize = 0; UtAssert_BOOL_TRUE(CFE_TBL_DumpRegistryGetter(&CFE_TBL_Global.RegDumpState, CFE_PLATFORM_TBL_MAX_NUM_TABLES - 1, &LocalBuf, &LocalSize)); UtAssert_NOT_NULL(LocalBuf); @@ -1010,10 +1010,10 @@ void Test_CFE_TBL_DumpRegCmd(void) UtAssert_ZERO(LocalSize); /* Test empty registry */ - CFE_TBL_Global.Registry[0].OwnerAppId = CFE_TBL_NOT_OWNED; - CFE_TBL_Global.Registry[0].HeadOfAccessList = CFE_TBL_END_OF_LIST; - LocalBuf = NULL; - LocalSize = 0; + CFE_TBL_Global.Registry[0].OwnerAppId = CFE_TBL_NOT_OWNED; + CFE_TBL_HandleLinkInit(&CFE_TBL_Global.Registry[0].AccessList); + LocalBuf = NULL; + LocalSize = 0; UtAssert_BOOL_FALSE(CFE_TBL_DumpRegistryGetter(&CFE_TBL_Global.RegDumpState, 0, &LocalBuf, &LocalSize)); UtAssert_NULL(LocalBuf); UtAssert_ZERO(LocalSize); @@ -1874,7 +1874,7 @@ void Test_CFE_TBL_Register(void) for (i = 0; i < CFE_PLATFORM_TBL_MAX_NUM_TABLES; i++) { - CFE_TBL_Global.Registry[i].HeadOfAccessList = CFE_TBL_END_OF_LIST; + CFE_TBL_HandleLinkInit(&CFE_TBL_Global.Registry[i].AccessList); } UtAssert_INT32_EQ(CFE_TBL_Register(&TblHandle2, "UT_Table1", sizeof(UT_Table1_t), CFE_TBL_OPT_DBL_BUFFER, NULL), @@ -2743,7 +2743,7 @@ void Test_CFE_TBL_Manage(void) /* Save the previous table's information for a subsequent test */ AccessDescPtr = &CFE_TBL_Global.Handles[App1TblHandle1]; RegRecPtr = &CFE_TBL_Global.Registry[AccessDescPtr->RegIndex]; - AccessIterator = RegRecPtr->HeadOfAccessList; + AccessIterator = RegRecPtr->AccessList.Next; /* Test unlocking a table by releasing the address */ UT_InitData(); @@ -2773,9 +2773,9 @@ void Test_CFE_TBL_Manage(void) */ AccessDescPtr = &CFE_TBL_Global.Handles[App1TblHandle2]; RegRecPtr = &CFE_TBL_Global.Registry[AccessDescPtr->RegIndex]; - CFE_TBL_Global.Handles[AccessIterator].NextLink = RegRecPtr->HeadOfAccessList; + CFE_TBL_Global.Handles[AccessIterator].Link.Next = RegRecPtr->AccessList.Next; CFE_TBL_Global.Handles[AccessIterator].AppId = UT_TBL_APPID_2; - RegRecPtr->HeadOfAccessList = AccessIterator; + RegRecPtr->AccessList.Next = AccessIterator; CFE_TBL_Global.Handles[AccessIterator].BufferIndex = 1; CFE_TBL_Global.Handles[AccessIterator].LockFlag = true; @@ -3125,7 +3125,7 @@ void Test_CFE_TBL_TblMod(void) /* Save the previous table's information for a subsequent test */ AccessDescPtr = &CFE_TBL_Global.Handles[App1TblHandle1]; RegRecPtr = &CFE_TBL_Global.Registry[AccessDescPtr->RegIndex]; - AccessIterator = RegRecPtr->HeadOfAccessList; + AccessIterator = RegRecPtr->AccessList.Next; /* Test response to adding a TBL API for notifying table services that * the table has been updated by application @@ -3141,11 +3141,11 @@ void Test_CFE_TBL_TblMod(void) /* Reset the current table entry pointer to a previous table in order to * exercise the path where one of the application IDs don't match */ - AccessDescPtr = &CFE_TBL_Global.Handles[App1TblHandle1]; - RegRecPtr = &CFE_TBL_Global.Registry[AccessDescPtr->RegIndex]; - CFE_TBL_Global.Handles[AccessIterator].NextLink = RegRecPtr->HeadOfAccessList; - CFE_TBL_Global.Handles[AccessIterator].AppId = UT_TBL_APPID_2; - RegRecPtr->HeadOfAccessList = AccessIterator; + AccessDescPtr = &CFE_TBL_Global.Handles[App1TblHandle1]; + RegRecPtr = &CFE_TBL_Global.Registry[AccessDescPtr->RegIndex]; + CFE_TBL_Global.Handles[AccessIterator].Link.Next = RegRecPtr->AccessList.Next; + CFE_TBL_Global.Handles[AccessIterator].AppId = UT_TBL_APPID_2; + RegRecPtr->AccessList.Next = AccessIterator; /* Configure for successful file read to initialize table */ strncpy(FileHeader.Description, "FS header description", sizeof(FileHeader.Description) - 1); @@ -3814,8 +3814,8 @@ void Test_CFE_TBL_Internal(void) */ UT_InitData(); memset(&Txn, 0, sizeof(Txn)); - CFE_TBL_Global.Registry[0].OwnerAppId = CFE_TBL_NOT_OWNED; - CFE_TBL_Global.Registry[0].HeadOfAccessList = CFE_TBL_END_OF_LIST + 1; + CFE_TBL_Global.Registry[0].OwnerAppId = CFE_TBL_NOT_OWNED; + CFE_TBL_Global.Registry[0].AccessList.Next = CFE_TBL_END_OF_LIST + 1; CFE_UtAssert_SUCCESS(CFE_TBL_TxnAllocateRegistryEntry(&Txn)); UtAssert_INT32_EQ(CFE_TBL_TxnRegId(&Txn), 1); CFE_UtAssert_EVENTCOUNT(0);