From 787f3a829bbd3a45b7349bb74a97167d7a8ec9a9 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Tue, 13 Oct 2020 14:40:35 -0400 Subject: [PATCH] Fix #924, do not recycle ID values Use the entire resource ID space (16 bits) and do not immediately recycle ID values until the full space is used. Implement a generic routine to find the next available ID, and modify every resource ID allocation to use this routine. Where necessary, this also corrects for differences in argument checking and duplicate checking between the various resource types. All resource allocation procedures now have consistent argument checking, and will reject duplicate name creation for any resources that are also associated with names. --- fsw/cfe-core/src/es/cfe_es_api.c | 74 +++++--- fsw/cfe-core/src/es/cfe_es_apps.c | 194 ++++++++++++-------- fsw/cfe-core/src/es/cfe_es_cds.c | 133 +++++--------- fsw/cfe-core/src/es/cfe_es_cds.h | 16 +- fsw/cfe-core/src/es/cfe_es_global.h | 4 + fsw/cfe-core/src/es/cfe_es_mempool.c | 46 +++-- fsw/cfe-core/src/es/cfe_es_resource.c | 62 +++++++ fsw/cfe-core/src/es/cfe_es_resource.h | 18 ++ fsw/cfe-core/src/es/cfe_es_start.c | 80 +++----- fsw/cfe-core/src/inc/cfe_error.h | 20 +- fsw/cfe-core/unit-test/es_UT.c | 254 +++++++++++++++++++++++--- fsw/cfe-core/unit-test/es_UT.h | 1 + fsw/cfe-core/unit-test/tbl_UT.c | 2 +- 13 files changed, 585 insertions(+), 319 deletions(-) diff --git a/fsw/cfe-core/src/es/cfe_es_api.c b/fsw/cfe-core/src/es/cfe_es_api.c index b39d265ff..3b3ad0393 100644 --- a/fsw/cfe-core/src/es/cfe_es_api.c +++ b/fsw/cfe-core/src/es/cfe_es_api.c @@ -1719,39 +1719,59 @@ int32 CFE_ES_RestoreFromCDS(void *RestoreToMemory, CFE_ES_CDSHandle_t Handle) int32 CFE_ES_RegisterGenCounter(CFE_ES_ResourceID_t *CounterIdPtr, const char *CounterName) { - int32 ReturnCode = CFE_ES_BAD_ARGUMENT; - CFE_ES_ResourceID_t CheckPtr; - int32 Status; - uint32 i; CFE_ES_GenCounterRecord_t *CountRecPtr; + CFE_ES_ResourceID_t PendingCounterId; + int32 Status; - Status = CFE_ES_GetGenCounterIDByName(&CheckPtr, CounterName); + if (CounterName == NULL || CounterIdPtr == NULL) + { + return CFE_ES_BAD_ARGUMENT; + } - if ((CounterIdPtr != NULL) && (CounterName != NULL) && (Status != CFE_SUCCESS)) + if (strlen(CounterName) >= sizeof(CountRecPtr->CounterName)) { - CFE_ES_LockSharedData(__func__,__LINE__); - CountRecPtr = CFE_ES_Global.CounterTable; - for ( i = 0; i < CFE_PLATFORM_ES_MAX_GEN_COUNTERS; i++ ) - { - if ( !CFE_ES_CounterRecordIsUsed(CountRecPtr) ) - { - strncpy(CountRecPtr->CounterName,CounterName,OS_MAX_API_NAME); - CountRecPtr->Counter = 0; - CFE_ES_CounterRecordSetUsed(CountRecPtr, - CFE_ES_ResourceID_FromInteger(i + CFE_ES_COUNTID_BASE)); - *CounterIdPtr = CFE_ES_CounterRecordGetID(CountRecPtr); - break; - } - ++CountRecPtr; - } - if (i < CFE_PLATFORM_ES_MAX_GEN_COUNTERS) - { - ReturnCode = CFE_SUCCESS; - } - CFE_ES_UnlockSharedData(__func__,__LINE__); + return CFE_ES_BAD_ARGUMENT; + } + + + CFE_ES_LockSharedData(__func__,__LINE__); + + /* + * Check for an existing entry with the same name. + */ + CountRecPtr = CFE_ES_LocateCounterRecordByName(CounterName); + if (CountRecPtr != NULL) + { + CFE_ES_SysLogWrite_Unsync("ES Startup: Duplicate Counter name '%s'\n", CounterName); + Status = CFE_ES_ERR_DUPLICATE_NAME; + PendingCounterId = CFE_ES_RESOURCEID_UNDEFINED; + } + else + { + /* scan for a free slot */ + PendingCounterId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastCounterId, CFE_PLATFORM_ES_MAX_GEN_COUNTERS); + CountRecPtr = CFE_ES_LocateCounterRecordByID(PendingCounterId); + + if (CountRecPtr == NULL) + { + CFE_ES_SysLogWrite_Unsync("ES Startup: No free Counter slots available\n"); + Status = CFE_ES_NO_RESOURCE_IDS_AVAILABLE; + } + else + { + strncpy(CountRecPtr->CounterName,CounterName, + sizeof(CountRecPtr->CounterName)); + CountRecPtr->Counter = 0; + CFE_ES_CounterRecordSetUsed(CountRecPtr, PendingCounterId); + CFE_ES_Global.LastCounterId = PendingCounterId; + Status = CFE_SUCCESS; + } } - return ReturnCode; + CFE_ES_UnlockSharedData(__func__,__LINE__); + + *CounterIdPtr = PendingCounterId; + return Status; } diff --git a/fsw/cfe-core/src/es/cfe_es_apps.c b/fsw/cfe-core/src/es/cfe_es_apps.c index 0990f48d3..1cba0620a 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.c +++ b/fsw/cfe-core/src/es/cfe_es_apps.c @@ -364,45 +364,82 @@ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, { cpuaddr StartAddr; int32 ReturnCode; - uint32 i; - bool AppSlotFound; + CFE_Status_t Status; osal_id_t ModuleId; osal_id_t MainTaskId; CFE_ES_AppRecord_t *AppRecPtr; CFE_ES_TaskRecord_t *TaskRecPtr; + CFE_ES_ResourceID_t PendingAppId; /* * The FileName must not be NULL */ - if (FileName == NULL) + if (FileName == NULL || AppName == NULL) { - return CFE_ES_ERR_APP_CREATE; + return CFE_ES_BAD_ARGUMENT; + } + + if (strlen(AppName) >= OS_MAX_API_NAME) + { + return CFE_ES_BAD_ARGUMENT; } /* ** Allocate an ES_AppTable entry */ CFE_ES_LockSharedData(__func__,__LINE__); - AppSlotFound = false; - AppRecPtr = CFE_ES_Global.AppTable; - for ( i = 0; i < CFE_PLATFORM_ES_MAX_APPLICATIONS; i++ ) + + /* + ** Find an ES AppTable entry, and set to RESERVED + ** + ** In this state, the entry is no longer free, but also will not pass the + ** validation test. So this function effectively has exclusive access + ** without holding the global lock. + ** + ** IMPORTANT: it must set the ID to something else before leaving + ** this function or else the resource will be leaked. After this + ** point, execution must proceed to the end of the function to + ** guarantee that the entry is either completed or freed. + */ + + /* + * Check for an existing entry with the same name. + * Also check for a matching Library name. + * (Apps and libraries should be uniquely named) + */ + AppRecPtr = CFE_ES_LocateAppRecordByName(AppName); + if (AppRecPtr != NULL) { - if ( !CFE_ES_AppRecordIsUsed(AppRecPtr) ) - { - AppSlotFound = true; - memset ( AppRecPtr, 0, sizeof(CFE_ES_AppRecord_t)); - /* set state EARLY_INIT for OS_TaskCreate below (indicates record is in use) */ - CFE_ES_AppRecordSetUsed(AppRecPtr, CFE_ES_ResourceID_FromInteger(i + CFE_ES_APPID_BASE)); - break; - } - ++AppRecPtr; + CFE_ES_SysLogWrite_Unsync("ES Startup: Duplicate app name '%s'\n", AppName); + Status = CFE_ES_ERR_DUPLICATE_NAME; } + else + { + /* scan for a free slot */ + PendingAppId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastAppId, CFE_PLATFORM_ES_MAX_APPLICATIONS); + AppRecPtr = CFE_ES_LocateAppRecordByID(PendingAppId); + + if (AppRecPtr == NULL) + { + CFE_ES_SysLogWrite_Unsync("ES Startup: No free application slots available\n"); + Status = CFE_ES_NO_RESOURCE_IDS_AVAILABLE; + } + else + { + /* Fully clear the entry, just in case of stale data */ + memset(AppRecPtr, 0, sizeof(*AppRecPtr)); + CFE_ES_AppRecordSetUsed(AppRecPtr, CFE_ES_RESOURCEID_RESERVED); + CFE_ES_Global.LastAppId = PendingAppId; + Status = CFE_SUCCESS; + } + } + CFE_ES_UnlockSharedData(__func__,__LINE__); /* ** If a slot was found, create the application */ - if ( AppSlotFound == true) + if (Status == CFE_SUCCESS) { /* ** Load the module @@ -507,7 +544,7 @@ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, CFE_ES_AppRecordSetFree(AppRecPtr); /* Release slot */ CFE_ES_UnlockSharedData(__func__,__LINE__); - return(CFE_ES_ERR_APP_CREATE); + Status = CFE_ES_ERR_APP_CREATE; } else { @@ -523,12 +560,13 @@ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, CFE_ES_SysLogWrite_Unsync("ES Startup: Error: ES_TaskTable slot in use at task creation!\n"); } CFE_ES_TaskRecordSetUsed(TaskRecPtr,AppRecPtr->TaskInfo.MainTaskId); - TaskRecPtr->AppId = CFE_ES_AppRecordGetID(AppRecPtr); + TaskRecPtr->AppId = PendingAppId; strncpy((char *)TaskRecPtr->TaskName, (char *)AppRecPtr->TaskInfo.MainTaskName,OS_MAX_API_NAME ); TaskRecPtr->TaskName[OS_MAX_API_NAME - 1]='\0'; + CFE_ES_AppRecordSetUsed(AppRecPtr, PendingAppId); CFE_ES_SysLogWrite_Unsync("ES Startup: %s loaded and created\n", AppName); - *ApplicationIdPtr = CFE_ES_AppRecordGetID(AppRecPtr); + *ApplicationIdPtr = PendingAppId; /* ** Increment the registered App and Registered External Task variables. @@ -538,15 +576,10 @@ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, CFE_ES_UnlockSharedData(__func__,__LINE__); - return(CFE_SUCCESS); - } /* End If OS_TaskCreate */ } - else /* appSlot not found */ - { - CFE_ES_WriteToSysLog("ES Startup: No free application slots available\n"); - return(CFE_ES_ERR_APP_CREATE); - } + + return Status; } /* End Function */ /* @@ -564,19 +597,20 @@ int32 CFE_ES_LoadLibrary(CFE_ES_ResourceID_t *LibraryIdPtr, { CFE_ES_LibraryEntryFuncPtr_t FunctionPointer; CFE_ES_LibRecord_t * LibSlotPtr; - size_t StringLength; int32 Status; - uint32 LibIndex; CFE_ES_ResourceID_t PendingLibId; osal_id_t ModuleId; bool IsModuleLoaded; /* - * First, should verify that the supplied "LibName" fits within the internal limit - * (currently sized to OS_MAX_API_NAME, but not assuming that will always be) + * The FileName must not be NULL */ - StringLength = strlen(LibName); - if (StringLength >= sizeof(LibSlotPtr->LibName)) + if (FileName == NULL || LibName == NULL) + { + return CFE_ES_BAD_ARGUMENT; + } + + if (strlen(LibName) >= OS_MAX_API_NAME) { return CFE_ES_BAD_ARGUMENT; } @@ -589,65 +623,67 @@ int32 CFE_ES_LoadLibrary(CFE_ES_ResourceID_t *LibraryIdPtr, ModuleId = OS_OBJECT_ID_UNDEFINED; PendingLibId = CFE_ES_RESOURCEID_UNDEFINED; Status = CFE_ES_ERR_LOAD_LIB; /* error that will be returned if no slots found */ + + /* + ** Find an ES AppTable entry, and set to RESERVED + ** + ** In this state, the entry is no longer free, but also will not pass the + ** validation test. So this function effectively has exclusive access + ** without holding the global lock. + ** + ** IMPORTANT: it must set the ID to something else before leaving + ** this function or else the resource will be leaked. After this + ** point, execution must proceed to the end of the function to + ** guarantee that the entry is either completed or freed. + */ CFE_ES_LockSharedData(__func__,__LINE__); - LibSlotPtr = CFE_ES_Global.LibTable; - for ( LibIndex = 0; LibIndex < CFE_PLATFORM_ES_MAX_LIBRARIES; ++LibIndex ) - { - if (CFE_ES_LibRecordIsUsed(LibSlotPtr)) - { - if (strcmp(LibSlotPtr->LibName, LibName) == 0) - { - /* - * Indicate to caller that the library is already loaded. - * (This is when there was a matching LibName in the table) - * - * Do nothing more; not logging this event as it may or may - * not be an error. - */ - *LibraryIdPtr = CFE_ES_LibRecordGetID(LibSlotPtr); - Status = CFE_ES_LIB_ALREADY_LOADED; - break; - } - } - else if (!CFE_ES_ResourceID_IsDefined(PendingLibId)) - { - /* Remember list position as possible place for new entry. */ - PendingLibId = CFE_ES_ResourceID_FromInteger(LibIndex + CFE_ES_LIBID_BASE); - Status = CFE_SUCCESS; - } - else - { - /* No action */ - } - ++LibSlotPtr; + /* + * Check for an existing entry with the same name. + * Also check for a matching Library name. + * (Libs and libraries should be uniquely named) + */ + LibSlotPtr = CFE_ES_LocateLibRecordByName(LibName); + if (LibSlotPtr != NULL || CFE_ES_LocateAppRecordByName(LibName) != NULL) + { + CFE_ES_SysLogWrite_Unsync("ES Startup: Duplicate Lib name '%s'\n", LibName); + if (LibSlotPtr != NULL) + { + PendingLibId = CFE_ES_LibRecordGetID(LibSlotPtr); + } + Status = CFE_ES_ERR_DUPLICATE_NAME; } - - if (Status == CFE_SUCCESS) + else { - /* reset back to the saved index that was free */ + /* scan for a free slot */ + PendingLibId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastLibId, CFE_PLATFORM_ES_MAX_LIBRARIES); LibSlotPtr = CFE_ES_LocateLibRecordByID(PendingLibId); - /* reserve the slot while still under lock */ - strcpy(LibSlotPtr->LibName, LibName); - CFE_ES_LibRecordSetUsed(LibSlotPtr, CFE_ES_RESOURCEID_RESERVED); - *LibraryIdPtr = PendingLibId; + if (LibSlotPtr == NULL) + { + CFE_ES_SysLogWrite_Unsync("ES Startup: No free library slots available\n"); + Status = CFE_ES_NO_RESOURCE_IDS_AVAILABLE; + } + else + { + /* Fully clear the entry, just in case of stale data */ + memset(LibSlotPtr, 0, sizeof(*LibSlotPtr)); + strcpy(LibSlotPtr->LibName, LibName); /* Size already checked */ + CFE_ES_LibRecordSetUsed(LibSlotPtr, CFE_ES_RESOURCEID_RESERVED); + CFE_ES_Global.LastLibId = PendingLibId; + Status = CFE_SUCCESS; + } } CFE_ES_UnlockSharedData(__func__,__LINE__); /* * If any off-nominal condition exists, skip the rest of this logic. - * Additionally write any extra information about what happened to syslog - * Note - not logging "already loaded" conditions, as this is not necessarily an error. + * (Log message already written) */ if (Status != CFE_SUCCESS) { - if (Status == CFE_ES_ERR_LOAD_LIB) - { - CFE_ES_WriteToSysLog("ES Startup: No free library slots available\n"); - } - + *LibraryIdPtr = PendingLibId; return Status; } @@ -770,8 +806,12 @@ int32 CFE_ES_LoadLibrary(CFE_ES_ResourceID_t *LibraryIdPtr, /* Release Slot - No need to lock as it is resetting just a single value */ CFE_ES_LibRecordSetFree(LibSlotPtr); + + PendingLibId = CFE_ES_RESOURCEID_UNDEFINED; } + *LibraryIdPtr = PendingLibId; + return(Status); } /* End Function */ diff --git a/fsw/cfe-core/src/es/cfe_es_cds.c b/fsw/cfe-core/src/es/cfe_es_cds.c index 8d7ff771b..be9efc862 100644 --- a/fsw/cfe-core/src/es/cfe_es_cds.c +++ b/fsw/cfe-core/src/es/cfe_es_cds.c @@ -75,6 +75,8 @@ int32 CFE_ES_CDS_EarlyInit(void) return CFE_STATUS_EXTERNAL_RESOURCE_FAIL; } + CDS->LastCDSBlockId = CFE_ES_ResourceID_FromInteger(CFE_ES_CDSBLOCKID_BASE); + /* Get CDS size from OS BSP */ Status = CFE_PSP_GetCDSSize(&CDS->TotalSize); if (Status != CFE_PSP_SUCCESS) @@ -306,14 +308,20 @@ int32 CFE_ES_CDS_CachePreload(CFE_ES_CDS_AccessCache_t *Cache, const void *Sourc int32 CFE_ES_RegisterCDSEx(CFE_ES_CDSHandle_t *HandlePtr, CFE_ES_CDS_Offset_t UserBlockSize, const char *Name, bool CriticalTbl) { CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars; - int32 Status = CFE_SUCCESS; - int32 RegUpdateStatus = CFE_SUCCESS; + int32 Status; + int32 RegUpdateStatus; CFE_ES_CDS_RegRec_t *RegRecPtr; CFE_ES_MemOffset_t BlockOffset; CFE_ES_MemOffset_t OldBlockSize; CFE_ES_MemOffset_t NewBlockSize; - bool IsNewEntry = false; - bool IsNewOffset = false; + CFE_ES_ResourceID_t PendingBlockId; + bool IsNewEntry; + bool IsNewOffset; + + Status = CFE_SUCCESS; + RegUpdateStatus = CFE_SUCCESS; + IsNewEntry = false; + IsNewOffset = false; if (UserBlockSize == 0 || UserBlockSize > CDS_ABS_MAX_BLOCK_SIZE) { @@ -325,21 +333,38 @@ int32 CFE_ES_RegisterCDSEx(CFE_ES_CDSHandle_t *HandlePtr, CFE_ES_CDS_Offset_t Us /* trying to register CDSs at the same location at the same time */ CFE_ES_LockCDS(); - /* Check for duplicate CDS name */ + /* + * Check for an existing entry with the same name. + */ RegRecPtr = CFE_ES_LocateCDSBlockRecordByName(Name); - - /* If not found then make a new entry */ - if (RegRecPtr == NULL) + if (RegRecPtr != NULL) { - RegRecPtr = CFE_ES_AllocateNewCDSRegistryEntry(); - IsNewEntry = true; + /* in CDS a duplicate name is not necessarily an error, we + * may reuse/resize the existing entry */ + PendingBlockId = CFE_ES_CDSBlockRecordGetID(RegRecPtr); } - - if (RegRecPtr == NULL) + else { - Status = CFE_ES_CDS_REGISTRY_FULL; + /* scan for a free slot */ + PendingBlockId = CFE_ES_FindNextAvailableId(CDS->LastCDSBlockId, CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES); + RegRecPtr = CFE_ES_LocateCDSBlockRecordByID(PendingBlockId); + + if (RegRecPtr != NULL) + { + /* Fully clear the entry, just in case of stale data */ + memset(RegRecPtr, 0, sizeof(*RegRecPtr)); + CDS->LastCDSBlockId = PendingBlockId; + IsNewEntry = true; + Status = CFE_SUCCESS; + } + else + { + Status = CFE_ES_NO_RESOURCE_IDS_AVAILABLE; + PendingBlockId = CFE_ES_RESOURCEID_UNDEFINED; + } } - else + + if (RegRecPtr != NULL) { /* Account for the extra header which will be added */ NewBlockSize = UserBlockSize; @@ -379,43 +404,24 @@ int32 CFE_ES_RegisterCDSEx(CFE_ES_CDSHandle_t *HandlePtr, CFE_ES_CDS_Offset_t Us } } - if (IsNewEntry) + if (Status == CFE_SUCCESS && IsNewEntry) { - if (Status == CFE_SUCCESS) - { - /* Save flag indicating whether it is a Critical Table or not */ - RegRecPtr->Table = CriticalTbl; + /* Save flag indicating whether it is a Critical Table or not */ + RegRecPtr->Table = CriticalTbl; - /* Save CDS Name in Registry */ - strncpy(RegRecPtr->Name, Name, sizeof(RegRecPtr->Name)-1); - RegRecPtr->Name[sizeof(RegRecPtr->Name)-1] = 0; - } - else - { - /* On failure set it free */ - CFE_ES_CDSBlockRecordSetFree(RegRecPtr); - } + /* Save CDS Name in Registry */ + strncpy(RegRecPtr->Name, Name, sizeof(RegRecPtr->Name)-1); + RegRecPtr->Name[sizeof(RegRecPtr->Name)-1] = 0; + CFE_ES_CDSBlockRecordSetUsed(RegRecPtr, PendingBlockId); } - if (IsNewOffset || IsNewEntry) + if (Status == CFE_SUCCESS && (IsNewOffset || IsNewEntry)) { /* If we succeeded at creating a CDS, save updated registry in the CDS */ RegUpdateStatus = CFE_ES_UpdateCDSRegistry(); } } - /* - * Export handle to caller before unlock - */ - if (Status == CFE_SUCCESS) - { - *HandlePtr = CFE_ES_CDSBlockRecordGetID(RegRecPtr); - } - else - { - *HandlePtr = CFE_ES_RESOURCEID_UNDEFINED; - } - /* Unlock Registry for update */ CFE_ES_UnlockCDS(); @@ -447,6 +453,7 @@ int32 CFE_ES_RegisterCDSEx(CFE_ES_CDSHandle_t *HandlePtr, CFE_ES_CDS_Offset_t Us Status = CFE_ES_CDS_ALREADY_EXISTS; } + *HandlePtr = PendingBlockId; return (Status); @@ -772,50 +779,6 @@ CFE_ES_CDS_RegRec_t *CFE_ES_LocateCDSBlockRecordByName(const char *CDSName) } /* End of CFE_ES_LocateCDSBlockRecordByName() */ -/******************************************************************* -** -** CFE_ES_FindFreeCDSRegistryEntry -** -** NOTE: For complete prolog information, see 'cfe_es_cds.h' -********************************************************************/ - -CFE_ES_CDS_RegRec_t *CFE_ES_AllocateNewCDSRegistryEntry() -{ - CFE_ES_CDS_Instance_t *CDS = &CFE_ES_Global.CDSVars; - CFE_ES_CDS_RegRec_t *CDSRegRecPtr; - uint32 NumReg; - - CDSRegRecPtr = CDS->Registry; - NumReg = CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES; - while (true) - { - if (NumReg == 0) - { - CDSRegRecPtr = NULL; /* not found */ - break; - } - - if (!CFE_ES_CDSBlockRecordIsUsed(CDSRegRecPtr)) - { - /* Wipe it, just in case of stale data */ - memset(CDSRegRecPtr, 0, sizeof(*CDSRegRecPtr)); - - /* Set the ID which marks it as used */ - CFE_ES_CDSBlockRecordSetUsed(CDSRegRecPtr, - CFE_ES_ResourceID_FromInteger( - (CDSRegRecPtr - CDS->Registry) - + CFE_ES_CDSBLOCKID_BASE)); - break; - } - - ++CDSRegRecPtr; - --NumReg; - } - - return CDSRegRecPtr; -} /* End of CFE_ES_FindFreeCDSRegistryEntry() */ - - /******************************************************************* ** ** CFE_ES_RebuildCDS diff --git a/fsw/cfe-core/src/es/cfe_es_cds.h b/fsw/cfe-core/src/es/cfe_es_cds.h index c4be63996..926135a27 100644 --- a/fsw/cfe-core/src/es/cfe_es_cds.h +++ b/fsw/cfe-core/src/es/cfe_es_cds.h @@ -170,6 +170,7 @@ typedef struct osal_id_t GenMutex; /**< \brief Mutex that controls access to CDS and registry */ CFE_ES_CDS_Offset_t TotalSize; /**< \brief Total size of the CDS as reported by BSP */ CFE_ES_CDS_Offset_t DataSize; /**< \brief Size of actual user data pool */ + CFE_ES_ResourceID_t LastCDSBlockId; /**< \brief Last issued CDS block ID */ CFE_ES_CDS_RegRec_t Registry[CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES]; /**< \brief CDS Registry (Local Copy) */ } CFE_ES_CDS_Instance_t; @@ -522,21 +523,6 @@ void CFE_ES_FormCDSName(char *FullCDSName, const char *CDSName, CFE_ES_ResourceI ******************************************************************************/ CFE_ES_CDS_RegRec_t *CFE_ES_LocateCDSBlockRecordByName(const char *CDSName); -/*****************************************************************************/ -/** -** \brief Locates a free slot in the CDS Registry and configures it for new use. -** -** \par Description -** Locates a free slot in the CDS Registry, assigns an ID, -** and marks the entry as used. -** -** \par Assumptions, External Events, and Notes: -** Note: This function assumes the registry has been locked. -** -** \retval NULL if registry full, Non null entry pointer on success -******************************************************************************/ -CFE_ES_CDS_RegRec_t *CFE_ES_AllocateNewCDSRegistryEntry(void); - /*****************************************************************************/ /** ** \brief Locks access to the CDS diff --git a/fsw/cfe-core/src/es/cfe_es_global.h b/fsw/cfe-core/src/es/cfe_es_global.h index 449829f97..d3dbcc9fe 100644 --- a/fsw/cfe-core/src/es/cfe_es_global.h +++ b/fsw/cfe-core/src/es/cfe_es_global.h @@ -117,17 +117,20 @@ typedef struct */ uint32 RegisteredCoreApps; uint32 RegisteredExternalApps; + CFE_ES_ResourceID_t LastAppId; CFE_ES_AppRecord_t AppTable[CFE_PLATFORM_ES_MAX_APPLICATIONS]; /* ** ES Shared Library Table */ uint32 RegisteredLibs; + CFE_ES_ResourceID_t LastLibId; CFE_ES_LibRecord_t LibTable[CFE_PLATFORM_ES_MAX_LIBRARIES]; /* ** ES Generic Counters Table */ + CFE_ES_ResourceID_t LastCounterId; CFE_ES_GenCounterRecord_t CounterTable[CFE_PLATFORM_ES_MAX_GEN_COUNTERS]; /* @@ -145,6 +148,7 @@ typedef struct /* ** Memory Pools */ + CFE_ES_ResourceID_t LastMemPoolId; CFE_ES_MemPoolRecord_t MemPoolTable[CFE_PLATFORM_ES_MAX_MEMORY_POOLS]; } CFE_ES_Global_t; diff --git a/fsw/cfe-core/src/es/cfe_es_mempool.c b/fsw/cfe-core/src/es/cfe_es_mempool.c index d669e39be..9c25d3ba7 100644 --- a/fsw/cfe-core/src/es/cfe_es_mempool.c +++ b/fsw/cfe-core/src/es/cfe_es_mempool.c @@ -162,7 +162,6 @@ int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *PoolID, uint16 UseMutex ) { int32 Status; - uint32 Index; CFE_ES_MemHandle_t PendingID; CFE_ES_MemPoolRecord_t *PoolRecPtr; CFE_ES_MemOffset_t Alignment; @@ -216,25 +215,27 @@ int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *PoolID, - /* - * Find an open slot in the Pool Table - */ - PendingID = CFE_ES_RESOURCEID_UNDEFINED; - PoolRecPtr = CFE_ES_Global.MemPoolTable; - CFE_ES_LockSharedData(__func__, __LINE__); - for (Index = 0; Index < CFE_PLATFORM_ES_MAX_MEMORY_POOLS; ++Index) + CFE_ES_LockSharedData(__func__,__LINE__); + + /* scan for a free slot */ + PendingID = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastMemPoolId, CFE_PLATFORM_ES_MAX_MEMORY_POOLS); + PoolRecPtr = CFE_ES_LocateMemPoolRecordByID(PendingID); + + if (PoolRecPtr == NULL) { - if (!CFE_ES_MemPoolRecordIsUsed(PoolRecPtr)) - { - /* reset/clear all contents */ - memset(PoolRecPtr, 0, sizeof(*PoolRecPtr)); - PendingID = CFE_ES_ResourceID_FromInteger(Index + CFE_ES_POOLID_BASE); - CFE_ES_MemPoolRecordSetUsed(PoolRecPtr, CFE_ES_RESOURCEID_RESERVED); - break; - } - ++PoolRecPtr; + CFE_ES_SysLogWrite_Unsync("ES Startup: No free MemPoolrary slots available\n"); + Status = CFE_ES_NO_RESOURCE_IDS_AVAILABLE; + } + else + { + /* Fully clear the entry, just in case of stale data */ + memset(PoolRecPtr, 0, sizeof(*PoolRecPtr)); + CFE_ES_MemPoolRecordSetUsed(PoolRecPtr, CFE_ES_RESOURCEID_RESERVED); + CFE_ES_Global.LastMemPoolId = PendingID; + Status = CFE_SUCCESS; } - CFE_ES_UnlockSharedData(__func__, __LINE__); + + CFE_ES_UnlockSharedData(__func__,__LINE__); /* * If no open resource ID was found, return now. @@ -243,14 +244,19 @@ int32 CFE_ES_PoolCreateEx(CFE_ES_MemHandle_t *PoolID, * must continue to the end of this function where the ID is freed * if not fully successful. */ - if (!CFE_ES_ResourceID_IsDefined(PendingID)) + if (Status != CFE_SUCCESS) { - return CFE_ES_NO_RESOURCE_IDS_AVAILABLE; + return Status; } Alignment = ALIGN_OF(CFE_ES_PoolAlign_t); /* memory mapped pools should be aligned */ if (Alignment < CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN) { + /* + * Note about path coverage testing - depending on the + * system architecture and configuration this line may be + * unreachable. This is OK. + */ Alignment = CFE_PLATFORM_ES_MEMPOOL_ALIGN_SIZE_MIN; } diff --git a/fsw/cfe-core/src/es/cfe_es_resource.c b/fsw/cfe-core/src/es/cfe_es_resource.c index ca44dbd1c..39a1ebaca 100644 --- a/fsw/cfe-core/src/es/cfe_es_resource.c +++ b/fsw/cfe-core/src/es/cfe_es_resource.c @@ -83,6 +83,68 @@ CFE_ES_ResourceID_t CFE_ES_ResourceID_FromOSAL(osal_id_t id) return CFE_ES_ResourceID_FromInteger(val ^ CFE_ES_RESOURCEID_MARK); } +/*********************************************************************/ +/* + * CFE_ES_FindNextAvailableId + * + * For complete API information, see prototype in header + */ +CFE_ES_ResourceID_t CFE_ES_FindNextAvailableId(CFE_ES_ResourceID_t StartId, uint32 TableSize) +{ + uint32 Serial; + uint32 Count; + uint32 ResourceType; + CFE_ES_ResourceID_t CheckId; + bool IsTaken; + + ResourceType = CFE_ES_ResourceID_ToInteger(StartId); + Serial = ResourceType & CFE_ES_RESOURCEID_MAX; + ResourceType -= Serial; + Count = TableSize; + IsTaken = true; + + do + { + if (Count == 0) + { + CheckId = CFE_ES_RESOURCEID_UNDEFINED; + break; + } + + --Count; + ++Serial; + if (Serial >= CFE_ES_RESOURCEID_MAX) + { + Serial %= TableSize; + } + CheckId = CFE_ES_ResourceID_FromInteger(ResourceType + Serial); + + switch (ResourceType) + { + case CFE_ES_APPID_BASE: + IsTaken = CFE_ES_AppRecordIsUsed(CFE_ES_LocateAppRecordByID(CheckId)); + break; + case CFE_ES_LIBID_BASE: + IsTaken = CFE_ES_LibRecordIsUsed(CFE_ES_LocateLibRecordByID(CheckId)); + break; + case CFE_ES_COUNTID_BASE: + IsTaken = CFE_ES_CounterRecordIsUsed(CFE_ES_LocateCounterRecordByID(CheckId)); + break; + case CFE_ES_POOLID_BASE: + IsTaken = CFE_ES_MemPoolRecordIsUsed(CFE_ES_LocateMemPoolRecordByID(CheckId)); + break; + case CFE_ES_CDSBLOCKID_BASE: + IsTaken = CFE_ES_CDSBlockRecordIsUsed(CFE_ES_LocateCDSBlockRecordByID(CheckId)); + break; + default: + /* do nothing, should never happen */ + break; + } + } + while (IsTaken); + + return CheckId; +} /*********************************************************************/ /* diff --git a/fsw/cfe-core/src/es/cfe_es_resource.h b/fsw/cfe-core/src/es/cfe_es_resource.h index be5511a3b..9ca10533f 100644 --- a/fsw/cfe-core/src/es/cfe_es_resource.h +++ b/fsw/cfe-core/src/es/cfe_es_resource.h @@ -62,6 +62,24 @@ #define CFE_ES_CDSBLOCKID_BASE (CFE_ES_RESOURCEID_MARK | ((OS_OBJECT_TYPE_USER+5) << CFE_ES_RESOURCEID_SHIFT)) +/** + * @brief Locate the next resource ID which does not map to an in-use table entry + * + * This begins searching from StartId which should be the most recently issued ID + * for the resource category. This will then search for the next ID which does + * _not_ map to a table entry that is in use. That is, it does not alias any + * valid ID when converted to an array index. + * + * returns an undefined ID value if no open slots are available + * + * @param[in] StartId the last issued ID for the resource category (app, lib, etc). + * @returns Next ID value which does not map to a valid entry + * @retval #CFE_ES_RESOURCEID_UNDEFINED if no open slots. + * + */ +CFE_ES_ResourceID_t CFE_ES_FindNextAvailableId(CFE_ES_ResourceID_t StartId, uint32 TableSize); + + /** * @brief Locate the app table entry correlating with a given app ID. * diff --git a/fsw/cfe-core/src/es/cfe_es_start.c b/fsw/cfe-core/src/es/cfe_es_start.c index ecaf9e3c5..269ace225 100644 --- a/fsw/cfe-core/src/es/cfe_es_start.c +++ b/fsw/cfe-core/src/es/cfe_es_start.c @@ -84,11 +84,14 @@ CFE_ES_ResetData_t *CFE_ES_ResetDataPtr; */ void CFE_ES_Main(uint32 StartType, uint32 StartSubtype, uint32 ModeId, const char *StartFilePath ) { - uint32 i; int32 ReturnCode; - CFE_ES_AppRecord_t *AppRecPtr; - CFE_ES_TaskRecord_t *TaskRecPtr; - CFE_ES_GenCounterRecord_t *CountRecPtr; + + /* + * Clear the entire global data structure. + * This also takes care of setting all resource IDs on all table entries + * to be "undefined" (not in use). + */ + memset(&CFE_ES_Global, 0, sizeof(CFE_ES_Global)); /* ** Indicate that the CFE is the earliest initialization state @@ -177,37 +180,12 @@ void CFE_ES_Main(uint32 StartType, uint32 StartSubtype, uint32 ModeId, const cha CFE_PSP_AttachExceptions(); /* - ** Initialize the ES Application Table - ** to mark all entries as unused. + ** Initialize the Last Id */ - AppRecPtr = CFE_ES_Global.AppTable; - for ( i = 0; i < CFE_PLATFORM_ES_MAX_APPLICATIONS; i++ ) - { - CFE_ES_AppRecordSetFree(AppRecPtr); - ++AppRecPtr; - } - - /* - ** Initialize the ES Task Table - ** to mark all entries as unused. - */ - TaskRecPtr = CFE_ES_Global.TaskTable; - for ( i = 0; i < OS_MAX_TASKS; i++ ) - { - CFE_ES_TaskRecordSetFree(TaskRecPtr); - ++TaskRecPtr; - } - - /* - ** Initialize the ES Generic Counter Table - ** to mark all entries as unused. - */ - CountRecPtr = CFE_ES_Global.CounterTable; - for ( i = 0; i < CFE_PLATFORM_ES_MAX_GEN_COUNTERS; i++ ) - { - CFE_ES_CounterRecordSetFree(CountRecPtr); - ++CountRecPtr; - } + CFE_ES_Global.LastAppId = CFE_ES_ResourceID_FromInteger(CFE_ES_APPID_BASE); + CFE_ES_Global.LastLibId = CFE_ES_ResourceID_FromInteger(CFE_ES_LIBID_BASE); + CFE_ES_Global.LastCounterId = CFE_ES_ResourceID_FromInteger(CFE_ES_COUNTID_BASE); + CFE_ES_Global.LastMemPoolId = CFE_ES_ResourceID_FromInteger(CFE_ES_POOLID_BASE); /* ** Indicate that the CFE core is now starting up / going multi-threaded @@ -774,12 +752,11 @@ void CFE_ES_InitializeFileSystems(uint32 StartType) void CFE_ES_CreateObjects(void) { int32 ReturnCode; - bool AppSlotFound; uint16 i; - uint16 j; osal_id_t OsalId; CFE_ES_AppRecord_t *AppRecPtr; CFE_ES_TaskRecord_t *TaskRecPtr; + CFE_ES_ResourceID_t PendingAppId; CFE_ES_WriteToSysLog("ES Startup: Starting Object Creation calls.\n"); @@ -793,36 +770,25 @@ void CFE_ES_CreateObjects(void) /* ** Allocate an ES AppTable entry */ - AppSlotFound = false; - AppRecPtr = CFE_ES_Global.AppTable; - for ( j = 0; j < CFE_PLATFORM_ES_MAX_APPLICATIONS; j++ ) + CFE_ES_LockSharedData(__func__,__LINE__); + + PendingAppId = CFE_ES_FindNextAvailableId(CFE_ES_Global.LastAppId, CFE_PLATFORM_ES_MAX_APPLICATIONS); + AppRecPtr = CFE_ES_LocateAppRecordByID(PendingAppId); + if (AppRecPtr != NULL) { - if ( !CFE_ES_AppRecordIsUsed(AppRecPtr) ) - { - AppSlotFound = true; - break; - } - ++AppRecPtr; + CFE_ES_AppRecordSetUsed(AppRecPtr, CFE_ES_RESOURCEID_RESERVED); } + CFE_ES_UnlockSharedData(__func__,__LINE__); + /* ** If a slot was found, create the application */ - if ( AppSlotFound == true ) + if (AppRecPtr != NULL) { CFE_ES_LockSharedData(__func__,__LINE__); - /* - ** Allocate and populate the ES_AppTable entry - */ - memset ( AppRecPtr, 0, sizeof(CFE_ES_AppRecord_t)); - /* - ** Core apps still have the notion of an init/running state - ** Set the state here to mark the record as used. - */ - CFE_ES_AppRecordSetUsed(AppRecPtr, CFE_ES_ResourceID_FromInteger(j + CFE_ES_APPID_BASE)); - AppRecPtr->Type = CFE_ES_AppType_CORE; /* @@ -895,6 +861,8 @@ void CFE_ES_CreateObjects(void) CFE_ES_SysLogWrite_Unsync("ES Startup: Core App: %s created. App ID: %lu\n", CFE_ES_ObjectTable[i].ObjectName, CFE_ES_ResourceID_ToInteger(CFE_ES_AppRecordGetID(AppRecPtr))); + + CFE_ES_AppRecordSetUsed(AppRecPtr, PendingAppId); /* ** Increment the registered App and Registered External Task variables. diff --git a/fsw/cfe-core/src/inc/cfe_error.h b/fsw/cfe-core/src/inc/cfe_error.h index b2eb6efe5..4a62d6ac0 100644 --- a/fsw/cfe-core/src/inc/cfe_error.h +++ b/fsw/cfe-core/src/inc/cfe_error.h @@ -412,17 +412,6 @@ typedef int32 CFE_Status_t; #define CFE_ES_CDS_INVALID_SIZE ((int32)0xc4000010) -/** - * @brief CDS Registry Full - * - * The CDS Registry has as many entries in it as it can hold. The - * CDS Registry size can be adjusted with the #CFE_PLATFORM_ES_CDS_MAX_NUM_ENTRIES - * macro defined in the cfe_platform_cfg.h file. - * - */ -#define CFE_ES_CDS_REGISTRY_FULL ((int32)0xc4000011) - - /** * @brief CDS Invalid * @@ -659,6 +648,14 @@ typedef int32 CFE_Status_t; #define CFE_ES_POOL_BOUNDS_ERROR ((int32)0xc400002D) +/** + * @brief Duplicate Name Error + * + * Resource creation failed due to the name already existing in the system. + * + */ +#define CFE_ES_ERR_DUPLICATE_NAME ((int32)0xc400002E) + /** * @brief Not Implemented * @@ -1414,6 +1411,7 @@ typedef int32 CFE_Status_t; #define CFE_ES_ERR_MEM_HANDLE CFE_ES_ERR_RESOURCEID_NOT_VALID #define CFE_ES_ERR_APPNAME CFE_ES_ERR_NAME_NOT_FOUND #define CFE_ES_CDS_NOT_FOUND_ERR CFE_ES_ERR_NAME_NOT_FOUND +#define CFE_ES_CDS_REGISTRY_FULL CFE_ES_NO_RESOURCE_IDS_AVAILABLE #endif diff --git a/fsw/cfe-core/unit-test/es_UT.c b/fsw/cfe-core/unit-test/es_UT.c index c2f85b0cd..365e5df5a 100644 --- a/fsw/cfe-core/unit-test/es_UT.c +++ b/fsw/cfe-core/unit-test/es_UT.c @@ -74,12 +74,6 @@ CFE_ES_GMP_IndirectBuffer_t UT_MemPoolIndirectBuffer; /* Create a startup script buffer for a maximum of 5 lines * 80 chars/line */ char StartupScript[MAX_STARTUP_SCRIPT]; -/* Number of apps instantiated */ -uint32 ES_UT_NumApps; -uint32 ES_UT_NumLibs; -uint32 ES_UT_NumPools; -uint32 ES_UT_NumCDS; - static const UT_TaskPipeDispatchId_t UT_TPID_CFE_ES_CMD_NOOP_CC = { .MsgId = CFE_SB_MSGID_WRAP_VALUE(CFE_ES_CMD_MID), @@ -269,8 +263,9 @@ void ES_UT_SetupSingleAppId(CFE_ES_AppType_Enum_t AppType, CFE_ES_AppState_Enum_ OS_TaskCreate(&UtOsalId, "UT", NULL, NULL, 0, 0, 0); UtTaskId = CFE_ES_ResourceID_FromOSAL(UtOsalId); - UtAppId = ES_UT_MakeAppIdForIndex(ES_UT_NumApps); - ++ES_UT_NumApps; + UtAppId = CFE_ES_Global.LastAppId; + CFE_ES_Global.LastAppId = CFE_ES_ResourceID_FromInteger( + CFE_ES_ResourceID_ToInteger(UtAppId) + 1); LocalTaskPtr = CFE_ES_LocateTaskRecordByID(UtTaskId); LocalAppPtr = CFE_ES_LocateAppRecordByID(UtAppId); @@ -356,8 +351,9 @@ void ES_UT_SetupSingleLibId(const char *LibName, CFE_ES_LibRecord_t **OutLibRec) CFE_ES_ResourceID_t UtLibId; CFE_ES_LibRecord_t *LocalLibPtr; - UtLibId = ES_UT_MakeLibIdForIndex(ES_UT_NumLibs); - ++ES_UT_NumLibs; + UtLibId = CFE_ES_Global.LastLibId; + CFE_ES_Global.LastLibId = CFE_ES_ResourceID_FromInteger( + CFE_ES_ResourceID_ToInteger(UtLibId) + 1); LocalLibPtr = CFE_ES_LocateLibRecordByID(UtLibId); CFE_ES_LibRecordSetUsed(LocalLibPtr, UtLibId); @@ -425,8 +421,10 @@ void ES_UT_SetupMemPoolId(CFE_ES_MemPoolRecord_t **OutPoolRecPtr) CFE_ES_MemHandle_t UtPoolID; CFE_ES_MemPoolRecord_t *LocalPoolRecPtr; - UtPoolID = ES_UT_MakePoolIdForIndex(ES_UT_NumPools); - ++ES_UT_NumPools; + UtPoolID = CFE_ES_Global.LastMemPoolId; + CFE_ES_Global.LastMemPoolId = CFE_ES_ResourceID_FromInteger( + CFE_ES_ResourceID_ToInteger(UtPoolID) + 1); + LocalPoolRecPtr = CFE_ES_LocateMemPoolRecordByID(UtPoolID); @@ -506,8 +504,9 @@ void ES_UT_SetupSingleCDSRegistry(const char *CDSName, CFE_ES_MemOffset_t BlockS CFE_ES_Global.CDSIsAvailable = true; } - UtCDSID = ES_UT_MakeCDSIdForIndex(ES_UT_NumCDS); - ++ES_UT_NumCDS; + UtCDSID = CFE_ES_Global.CDSVars.LastCDSBlockId; + CFE_ES_Global.CDSVars.LastCDSBlockId = CFE_ES_ResourceID_FromInteger( + CFE_ES_ResourceID_ToInteger(UtCDSID) + 1); LocalRegRecPtr = CFE_ES_LocateCDSBlockRecordByID(UtCDSID); if (CDSName != NULL) @@ -622,6 +621,7 @@ void UtTest_Setup(void) UT_ADD_TEST(TestInit); UT_ADD_TEST(TestStartupErrorPaths); + UT_ADD_TEST(TestResourceID); UT_ADD_TEST(TestApps); UT_ADD_TEST(TestLibs); UT_ADD_TEST(TestERLog); @@ -645,10 +645,17 @@ void ES_ResetUnitTest(void) UT_InitData(); memset(&CFE_ES_Global, 0, sizeof(CFE_ES_Global)); - ES_UT_NumApps = 0; - ES_UT_NumLibs = 0; - ES_UT_NumPools = 0; - ES_UT_NumCDS = 0; + + /* + ** Initialize the Last Id + */ + CFE_ES_Global.LastAppId = CFE_ES_ResourceID_FromInteger(CFE_ES_APPID_BASE); + CFE_ES_Global.LastLibId = CFE_ES_ResourceID_FromInteger(CFE_ES_LIBID_BASE); + CFE_ES_Global.LastCounterId = CFE_ES_ResourceID_FromInteger(CFE_ES_COUNTID_BASE); + CFE_ES_Global.LastMemPoolId = CFE_ES_ResourceID_FromInteger(CFE_ES_POOLID_BASE); + CFE_ES_Global.CDSVars.LastCDSBlockId = CFE_ES_ResourceID_FromInteger(CFE_ES_CDSBLOCKID_BASE); + + } /* end ES_ResetUnitTest() */ void TestInit(void) @@ -1148,6 +1155,8 @@ void TestApps(void) CFE_ES_ResourceID_t Id; CFE_ES_TaskRecord_t *UtTaskRecPtr; CFE_ES_AppRecord_t *UtAppRecPtr; + CFE_ES_MemPoolRecord_t *UtPoolRecPtr; + char NameBuffer[OS_MAX_API_NAME+5]; UtPrintf("Begin Test Apps"); @@ -1284,10 +1293,26 @@ void TestApps(void) 4096, 1); UT_Report(__FILE__, __LINE__, - Return == CFE_ES_ERR_APP_CREATE, + Return == CFE_ES_BAD_ARGUMENT, "CFE_ES_AppCreate", "NULL file name"); + /* Test application creation with name too long */ + memset(NameBuffer, 'x', sizeof(NameBuffer)-1); + NameBuffer[sizeof(NameBuffer)-1] = 0; + Return = CFE_ES_AppCreate(&Id, + "ut/filename.x", + "EntryPoint", + NameBuffer, + 170, + 4096, + 1); + UT_Report(__FILE__, __LINE__, + Return == CFE_ES_BAD_ARGUMENT, + "CFE_ES_AppCreate", + "Name too long"); + + /* Test successful application loading and creation */ ES_ResetUnitTest(); Return = CFE_ES_AppCreate(&Id, @@ -1302,13 +1327,26 @@ void TestApps(void) "CFE_ES_AppCreate", "Application load/create; successful"); + /* Test application loading of the same name again */ + Return = CFE_ES_AppCreate(&Id, + "ut/filename.x", + "EntryPoint", + "AppName", + 170, + 8192, + 1); + UT_Report(__FILE__, __LINE__, + Return == CFE_ES_ERR_DUPLICATE_NAME, + "CFE_ES_AppCreate", + "Duplicate name"); + /* Test application loading and creation where the file cannot be loaded */ UT_InitData(); UT_SetDeferredRetcode(UT_KEY(OS_ModuleLoad), 1, -1); Return = CFE_ES_AppCreate(&Id, "ut/filename.x", "EntryPoint", - "AppName", + "AppName2", 170, 8192, 1); @@ -1335,7 +1373,7 @@ void TestApps(void) 8192, 1); UT_Report(__FILE__, __LINE__, - Return == CFE_ES_ERR_APP_CREATE && + Return == CFE_ES_NO_RESOURCE_IDS_AVAILABLE && UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_NO_FREE_APP_SLOTS]), "CFE_ES_AppCreate", "No free application slots available"); @@ -1379,6 +1417,15 @@ void TestApps(void) "CFE_ES_AppCreate", "Module unload failure after entry point lookup failure"); + /* + * Set up a situation where attempting to get appID by context, + * but the task record does not match the app record. + */ + ES_ResetUnitTest(); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, &UtTaskRecPtr); + UtTaskRecPtr->AppId = CFE_ES_RESOURCEID_UNDEFINED; + UtAssert_NULL(CFE_ES_GetAppRecordByContext()); + /* Test scanning and acting on the application table where the timer * expires for a waiting application */ @@ -1963,6 +2010,8 @@ void TestApps(void) OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); /* Setup a second entry which will NOT be deleted */ ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, NULL, &UtTaskRecPtr); + ES_UT_SetupMemPoolId(&UtPoolRecPtr); + UtPoolRecPtr->OwnerAppID = CFE_ES_AppRecordGetID(UtAppRecPtr); OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); /* Associate a child task with the app to be deleted */ ES_UT_SetupChildTaskId(UtAppRecPtr, NULL, NULL); @@ -1974,6 +2023,29 @@ void TestApps(void) CFE_ES_TaskRecordIsUsed(UtTaskRecPtr), "CFE_ES_CleanUpApp", "Main task ID matches task ID, other task unaffected"); + UT_Report(__FILE__, __LINE__, + !CFE_ES_MemPoolRecordIsUsed(UtPoolRecPtr), + "CFE_ES_CleanUpApp", + "Main task ID matches task ID, memory pool deleted"); + + /* Test deleting an application and cleaning up its resources where the + * memory pool deletion fails + */ + ES_ResetUnitTest(); + /* Setup an entry which will be deleted */ + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); + OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); + ES_UT_SetupMemPoolId(&UtPoolRecPtr); + UtPoolRecPtr->OwnerAppID = CFE_ES_AppRecordGetID(UtAppRecPtr); + UtPoolRecPtr->PoolID = CFE_ES_ResourceID_FromInteger(99999); /* Mismatch */ + UT_Report(__FILE__, __LINE__, + CFE_ES_CleanUpApp(UtAppRecPtr) == CFE_ES_APP_CLEANUP_ERR, + "CFE_ES_CleanUpApp", + "Mem Pool delete error"); + UT_Report(__FILE__, __LINE__, + CFE_ES_MemPoolRecordIsUsed(UtPoolRecPtr), + "CFE_ES_CleanUpApp", + "Mem Pool not freed"); /* Test deleting an application and cleaning up its resources where the * application ID doesn't match the main task ID @@ -2065,6 +2137,45 @@ void TestApps(void) CFE_ES_CleanupTaskResources(Id) == CFE_SUCCESS, "CFE_ES_CleanupTaskResources", "Get OS information failures"); + +} + +void TestResourceID(void) +{ + /* + * Test cases for generic resource ID functions which are + * not sufficiently covered by other app/lib tests. + */ + CFE_ES_ResourceID_t Id; + CFE_ES_ResourceID_t LastId; + uint32 Count; + + /* Call CFE_ES_FindNextAvailableId() using an invalid resource type */ + ES_ResetUnitTest(); + Id = CFE_ES_FindNextAvailableId(CFE_ES_RESOURCEID_UNDEFINED, 5); + UtAssert_True(!CFE_ES_ResourceID_IsDefined(Id), "CFE_ES_FindNextAvailableId() on undefined resource type"); + + /* Verify that CFE_ES_FindNextAvailableId() does not repeat until CFE_ES_RESOURCEID_MAX is reached */ + LastId = CFE_ES_Global.LastAppId; + Count = CFE_ES_RESOURCEID_MAX-1; + while (Count > 0) + { + Id = CFE_ES_FindNextAvailableId(LastId, CFE_PLATFORM_ES_MAX_APPLICATIONS); + if (CFE_ES_ResourceID_ToInteger(Id) - CFE_ES_ResourceID_ToInteger(LastId) != 1) + { + /* Numbers should be incrementing by 1 each time, never decreasing */ + break; + } + + LastId = Id; + --Count; + } + UtAssert_True(Count == 0, "CFE_ES_FindNextAvailableId() allocate all resource ID space"); + + /* Now verify that CFE_ES_FindNextAvailableId() recycles the first item again */ + Id = CFE_ES_FindNextAvailableId(LastId, CFE_PLATFORM_ES_MAX_APPLICATIONS); + UtAssert_True(CFE_ES_ResourceID_IsDefined(Id), "CFE_ES_FindNextAvailableId() after wrap"); + UtAssert_True(CFE_ES_ResourceID_ToInteger(Id) < (CFE_ES_APPID_BASE + CFE_PLATFORM_ES_MAX_APPLICATIONS), "CFE_ES_FindNextAvailableId() wrap ID"); } void TestLibs(void) @@ -2090,6 +2201,24 @@ void TestLibs(void) "CFE_ES_LoadLibrary", "Load shared library initialization failure"); + /* Test Load library returning an error on a null pointer argument */ + Return = CFE_ES_LoadLibrary(&Id, + NULL, + "EntryPoint", + "LibName"); + UT_Report(__FILE__, __LINE__, + Return == CFE_ES_BAD_ARGUMENT, + "CFE_ES_LoadLibrary", + "Load shared library bad argument (NULL filename)"); + + Return = CFE_ES_LoadLibrary(&Id, + "filename", + "EntryPoint", + NULL); + UT_Report(__FILE__, __LINE__, + Return == CFE_ES_BAD_ARGUMENT, + "CFE_ES_LoadLibrary", + "Load shared library bad argument (NULL library name)"); /* Test Load library returning an error on a too long library name */ memset(&LongLibraryName[0], 'a', sizeof(UtLibRecPtr->LibName)); @@ -2125,7 +2254,7 @@ void TestLibs(void) "TST_LIB_Init", "TST_LIB"); UT_Report(__FILE__, __LINE__, - Return == CFE_ES_LIB_ALREADY_LOADED, + Return == CFE_ES_ERR_DUPLICATE_NAME, "CFE_ES_LoadLibrary", "Duplicate"); UtAssert_True(CFE_ES_ResourceID_Equal(Id, CFE_ES_LibRecordGetID(UtLibRecPtr)), @@ -2191,7 +2320,7 @@ void TestLibs(void) "EntryPoint", "LibName"); UT_Report(__FILE__, __LINE__, - Return == CFE_ES_ERR_LOAD_LIB && + Return == CFE_ES_NO_RESOURCE_IDS_AVAILABLE && UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_LIBRARY_SLOTS]), "CFE_ES_LoadLibrary", "No free library slots"); @@ -2201,6 +2330,7 @@ void TestLibs(void) */ ES_ResetUnitTest(); ES_UT_SetupSingleLibId("UT", &UtLibRecPtr); + Id = CFE_ES_LibRecordGetID(UtLibRecPtr); UtAssert_INT32_EQ(CFE_ES_GetLibName(LongLibraryName, Id, sizeof(LongLibraryName)), CFE_SUCCESS); UtAssert_INT32_EQ(CFE_ES_GetLibIDByName(&Id, "Nonexistent"), CFE_ES_ERR_NAME_NOT_FOUND); UtAssert_INT32_EQ(CFE_ES_GetLibIDByName(&Id, LongLibraryName), CFE_SUCCESS); @@ -4397,7 +4527,7 @@ void TestAPI(void) /* Test restarting an app that doesn't exist */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_STOPPED, NULL, &UtAppRecPtr, NULL); - AppId = ES_UT_MakeAppIdForIndex(ES_UT_NumApps); /* Should be within range, but not used */ + AppId = ES_UT_MakeAppIdForIndex(CFE_PLATFORM_ES_MAX_APPLICATIONS-1); /* Should be within range, but not used */ UT_Report(__FILE__, __LINE__, CFE_ES_RestartApp(AppId) == CFE_ES_ERR_RESOURCEID_NOT_VALID, "CFE_ES_RestartApp", @@ -5084,7 +5214,7 @@ void TestGenericCounterAPI(void) /* Test registering a generic counter that is already registered */ UT_Report(__FILE__, __LINE__, CFE_ES_RegisterGenCounter(&CounterId, - "Counter1") == CFE_ES_BAD_ARGUMENT, + "Counter1") == CFE_ES_ERR_DUPLICATE_NAME, "CFE_ES_RegisterGenCounter", "Attempt to register an existing counter"); @@ -5107,7 +5237,7 @@ void TestGenericCounterAPI(void) /* Test registering a generic counter after the maximum are registered */ UT_Report(__FILE__, __LINE__, CFE_ES_RegisterGenCounter(&CounterId, - "Counter999") == CFE_ES_BAD_ARGUMENT, + "Counter999") == CFE_ES_NO_RESOURCE_IDS_AVAILABLE, "CFE_ES_RegisterGenCounter", "Maximum number of counters exceeded"); @@ -5408,7 +5538,7 @@ void TestCDS() } UT_Report(__FILE__, __LINE__, - CFE_ES_RegisterCDS(&CDSHandle, 4, "Name2") == CFE_ES_CDS_REGISTRY_FULL, + CFE_ES_RegisterCDS(&CDSHandle, 4, "Name2") == CFE_ES_NO_RESOURCE_IDS_AVAILABLE, "CFE_ES_RegisterCDS", "No available entries"); @@ -6101,6 +6231,28 @@ void TestESMempool(void) "CFE_ES_PoolCreateEx", "Memory pool size too small (default block size)"); + /* Test calling CFE_ES_PoolCreateEx() with NULL pointer arguments + */ + UT_Report(__FILE__, __LINE__, + CFE_ES_PoolCreateEx(NULL, + Buffer1, + sizeof(Buffer1), + CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES, + BlockSizes, + CFE_ES_USE_MUTEX) == CFE_ES_BAD_ARGUMENT, + "CFE_ES_PoolCreateEx", + "Memory pool bad arguments (NULL handle pointer)"); + + UT_Report(__FILE__, __LINE__, + CFE_ES_PoolCreateEx(&PoolID1, + NULL, + sizeof(Buffer1), + CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES, + BlockSizes, + CFE_ES_USE_MUTEX) == CFE_ES_BAD_ARGUMENT, + "CFE_ES_PoolCreateEx", + "Memory pool bad arguments (NULL mem pointer)"); + /* * Test to use default block sizes if none are given @@ -6126,6 +6278,54 @@ void TestESMempool(void) "CFE_ES_PoolCreateEx", "Invalid mutex option"); + /* + * Test creating a memory pool after the limit reached (no slots) + */ + ES_ResetUnitTest(); + PoolPtr = CFE_ES_Global.MemPoolTable; + for (i = 0; i < CFE_PLATFORM_ES_MAX_MEMORY_POOLS; ++i) + { + CFE_ES_MemPoolRecordSetUsed(PoolPtr, CFE_ES_ResourceID_FromInteger(i + CFE_ES_POOLID_BASE)); + ++PoolPtr; + } + UT_Report(__FILE__, __LINE__, + CFE_ES_PoolCreateEx(&PoolID1, + Buffer1, + sizeof(Buffer1), + CFE_ES_DEFAULT_MEMPOOL_BLOCK_SIZES, + BlockSizes, + CFE_ES_USE_MUTEX) == CFE_ES_NO_RESOURCE_IDS_AVAILABLE, + "CFE_ES_PoolCreateEx", + "Memory pool limit reached"); + + /* + * Test creating a memory pool with a semaphore error + */ + ES_ResetUnitTest(); + UT_SetDeferredRetcode(UT_KEY(OS_MutSemCreate), 1, OS_ERROR); + UT_Report(__FILE__, __LINE__, + CFE_ES_PoolCreate(&PoolID1, + Buffer1, + sizeof(Buffer1)) == CFE_STATUS_EXTERNAL_RESOURCE_FAIL, + "CFE_ES_PoolCreateEx", + "Memory pool mutex create error"); + + /* + * Test creating a memory pool with a semaphore error + * This still returns success as there is no recourse, but there + * should be a syslog about it. + */ + ES_UT_SetupMemPoolId(&PoolPtr); + OS_MutSemCreate(&PoolPtr->MutexId, "UT", 0); + UT_SetDeferredRetcode(UT_KEY(OS_MutSemDelete), 1, OS_ERROR); + PoolID1 = CFE_ES_MemPoolRecordGetID(PoolPtr); + UT_Report(__FILE__, __LINE__, + CFE_ES_PoolDelete(PoolID1) == CFE_SUCCESS, + "CFE_ES_PoolDelete", + "Memory pool delete with semaphore delete error"); + + + /* Test initializing a pre-allocated pool specifying * the block size with one block size set to zero */ diff --git a/fsw/cfe-core/unit-test/es_UT.h b/fsw/cfe-core/unit-test/es_UT.h index 4a8db6650..c33b5546c 100644 --- a/fsw/cfe-core/unit-test/es_UT.h +++ b/fsw/cfe-core/unit-test/es_UT.h @@ -333,6 +333,7 @@ void TestCDSMempool(void); void TestESMempool(void); void TestSysLog(void); +void TestResourceID(void); void TestGenericCounterAPI(void); void TestGenericPool(void); void TestLibs(void); diff --git a/fsw/cfe-core/unit-test/tbl_UT.c b/fsw/cfe-core/unit-test/tbl_UT.c index 0cd48b447..e395262f4 100644 --- a/fsw/cfe-core/unit-test/tbl_UT.c +++ b/fsw/cfe-core/unit-test/tbl_UT.c @@ -2285,7 +2285,7 @@ void Test_CFE_TBL_Register(void) * is full */ UT_InitData(); - UT_SetDeferredRetcode(UT_KEY(CFE_ES_RegisterCDSEx), 1, CFE_ES_CDS_REGISTRY_FULL); + UT_SetDeferredRetcode(UT_KEY(CFE_ES_RegisterCDSEx), 1, CFE_ES_NO_RESOURCE_IDS_AVAILABLE); RtnCode = CFE_TBL_Register(&TblHandle1, "UT_Table1", sizeof(UT_Table1_t), CFE_TBL_OPT_CRITICAL, NULL);