diff --git a/fsw/cfe-core/src/es/cfe_es_api.c b/fsw/cfe-core/src/es/cfe_es_api.c index ef619928c..af7a38285 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);