diff --git a/README.md b/README.md index c77258fdc..ad74241a1 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,25 @@ The detailed cFE user's guide can be viewed at + ### Development Build: 6.8.0-rc1+dev139 - For all resource types which have names, IDs are not re-issued after deletion, helping ensure safety as previously deleted IDs will not validate. Provides a consistent Name-ID translation API for all resource types. Enforces consistent argument/name validation on all resource types, and also enforces name uniqueness where relevant. diff --git a/cmake/mission_defaults.cmake b/cmake/mission_defaults.cmake index 33e8c292b..444a1138e 100644 --- a/cmake/mission_defaults.cmake +++ b/cmake/mission_defaults.cmake @@ -15,6 +15,7 @@ set(MISSION_CORE_MODULES "osal" "psp" "msg" + "sbr" ) # The "MISSION_GLOBAL_APPLIST" is a set of apps/libs that will be built diff --git a/cmake/sample_defs/cpu1_platform_cfg.h b/cmake/sample_defs/cpu1_platform_cfg.h index e82e24abb..fa5f9ced7 100644 --- a/cmake/sample_defs/cpu1_platform_cfg.h +++ b/cmake/sample_defs/cpu1_platform_cfg.h @@ -47,7 +47,11 @@ ** regarding this parameter, send an SB command to 'Send Statistics Pkt'. ** ** \par Limits -** This parameter has a lower limit of 1 and an upper limit of 1024. +** This must be a power of two if software bus message routing hash implementation +** is being used. Lower than 64 will cause unit test failures, and +** telemetry reporting is impacted below 32. There is no hard +** upper limit, but impacts memory footprint. For software bus message routing +** search implementation the number of msg ids subscribed to impacts performance. ** */ #define CFE_PLATFORM_SB_MAX_MSG_IDS 256 diff --git a/fsw/cfe-core/src/es/cfe_es_api.c b/fsw/cfe-core/src/es/cfe_es_api.c index 22cbbe1e5..3955160bd 100644 --- a/fsw/cfe-core/src/es/cfe_es_api.c +++ b/fsw/cfe-core/src/es/cfe_es_api.c @@ -256,7 +256,7 @@ int32 CFE_ES_ReloadApp(CFE_ES_ResourceID_t AppID, const char *AppFileName) { CFE_ES_SysLogWrite_Unsync("CFE_ES_ReloadApp: Reload Application %s Initiated. New filename = %s\n", CFE_ES_AppRecordGetName(AppRecPtr), AppFileName); - strncpy((char *)AppRecPtr->StartParams.FileName, AppFileName, OS_MAX_PATH_LEN); + strncpy(AppRecPtr->StartParams.BasicInfo.FileName, AppFileName, OS_MAX_PATH_LEN); AppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RELOAD; } else @@ -965,8 +965,10 @@ int32 CFE_ES_GetTaskName(char *TaskName, CFE_ES_ResourceID_t TaskId, uint32 Buff */ int32 CFE_ES_GetAppInfo(CFE_ES_AppInfo_t *AppInfo, CFE_ES_ResourceID_t AppId) { - int32 ReturnCode = CFE_SUCCESS; CFE_ES_AppRecord_t *AppRecPtr; + CFE_ES_TaskRecord_t *TaskRecPtr; + int32 Status; + uint32 i; if ( AppInfo == NULL ) { @@ -976,73 +978,233 @@ int32 CFE_ES_GetAppInfo(CFE_ES_AppInfo_t *AppInfo, CFE_ES_ResourceID_t AppId) memset(AppInfo, 0, sizeof(*AppInfo)); - /* - ** Get App Record - */ AppRecPtr = CFE_ES_LocateAppRecordByID(AppId); - if ( AppRecPtr == NULL ) + + CFE_ES_LockSharedData(__func__,__LINE__); + + if ( !CFE_ES_AppRecordIsMatch(AppRecPtr, AppId) ) { - CFE_ES_WriteToSysLog("CFE_ES_GetAppInfo: App ID Invalid: %lu\n", + /* + * Log a message if called with an invalid ID. + */ + CFE_ES_WriteToSysLog("CFE_ES_GetAppInfo: App ID not active: %lu\n", CFE_ES_ResourceID_ToInteger(AppId)); - return CFE_ES_ERR_RESOURCEID_NOT_VALID; - } + + Status = CFE_ES_ERR_RESOURCEID_NOT_VALID; + } + else + { + AppInfo->AppId = AppId; + AppInfo->Type = AppRecPtr->Type; + + CFE_ES_CopyModuleBasicInfo(&AppRecPtr->StartParams.BasicInfo, AppInfo); + CFE_ES_CopyModuleStatusInfo(&AppRecPtr->ModuleInfo, AppInfo); + + AppInfo->StackSize = AppRecPtr->StartParams.StackSize; + AppInfo->ExceptionAction = AppRecPtr->StartParams.ExceptionAction; + AppInfo->Priority = AppRecPtr->StartParams.Priority; + AppInfo->MainTaskId = AppRecPtr->MainTaskId; + + /* + ** Calculate the number of child tasks + */ + AppInfo->NumOfChildTasks = 0; + TaskRecPtr = CFE_ES_Global.TaskTable; + for (i=0; iAppId, AppId)) + { + if (CFE_ES_ResourceID_Equal(CFE_ES_TaskRecordGetID(TaskRecPtr), AppInfo->MainTaskId)) + { + /* This is the main task - capture its name and execution count */ + AppInfo->ExecutionCounter = TaskRecPtr->ExecutionCounter; + strncpy(AppInfo->MainTaskName, TaskRecPtr->TaskName, + sizeof(AppInfo->MainTaskName) - 1); + AppInfo->MainTaskName[sizeof(AppInfo->MainTaskName) - 1] = '\0'; + } + else + { + /* This is a child task, no extra info, just increment count */ + ++AppInfo->NumOfChildTasks; + } + } + ++TaskRecPtr; + } + + Status = CFE_SUCCESS; + } + + CFE_ES_UnlockSharedData(__func__,__LINE__); /* - * Note - cannot check if the AppID is active here, - * as the table is not locked. The internal function - * should lock and check. - */ - ReturnCode = CFE_ES_GetAppInfoInternal(AppRecPtr, AppInfo); - if (ReturnCode != CFE_SUCCESS) + ** Get the address information from the OSAL + */ + if (Status == CFE_SUCCESS) { - CFE_ES_WriteToSysLog("CFE_ES_GetAppInfo: App ID Not Active: %lu\n", - CFE_ES_ResourceID_ToInteger(AppId)); + CFE_ES_CopyModuleAddressInfo(AppInfo->ModuleId, AppInfo); } - return(ReturnCode); + return Status; +} + +/* +** Function: CFE_ES_GetLibInfo - See API and header file for details +*/ +int32 CFE_ES_GetLibInfo(CFE_ES_AppInfo_t *LibInfo, CFE_ES_ResourceID_t LibId) +{ + int32 Status; + CFE_ES_LibRecord_t *LibRecPtr; + + if ( LibInfo == NULL ) + { + CFE_ES_WriteToSysLog("CFE_ES_GetLibInfo: Invalid Parameter ( Null Pointer )\n"); + return CFE_ES_ERR_BUFFER; + } + + LibRecPtr = CFE_ES_LocateLibRecordByID(LibId); + + CFE_ES_LockSharedData(__func__,__LINE__); + + if ( !CFE_ES_LibRecordIsMatch(LibRecPtr, LibId) ) + { + /* + * Log a message if called with an invalid ID. + */ + CFE_ES_SysLogWrite_Unsync("CFE_ES_GetLibInfo: Lib ID not active: %lu\n", + CFE_ES_ResourceID_ToInteger(LibId)); + + Status = CFE_ES_ERR_RESOURCEID_NOT_VALID; + } + else + { + LibInfo->AppId = CFE_ES_LibRecordGetID(LibRecPtr);; + LibInfo->Type = CFE_ES_AppType_LIBRARY; + + CFE_ES_CopyModuleBasicInfo(&LibRecPtr->BasicInfo, LibInfo); + CFE_ES_CopyModuleStatusInfo(&LibRecPtr->ModuleInfo, LibInfo); + + Status = CFE_SUCCESS; + } + + CFE_ES_UnlockSharedData(__func__,__LINE__); + + /* + ** Get the address information from the OSAL + */ + if (Status == CFE_SUCCESS) + { + CFE_ES_CopyModuleAddressInfo(LibInfo->ModuleId, LibInfo); + } + + return Status; +} + +/* +** Function: CFE_ES_GetModuleInfo - See API and header file for details +*/ +int32 CFE_ES_GetModuleInfo(CFE_ES_AppInfo_t *ModuleInfo, CFE_ES_ResourceID_t ResourceId) +{ + uint32 ResourceType; + int32 Status; + + ResourceType = CFE_ES_ResourceID_ToInteger(ResourceId); + ResourceType -= ResourceType & CFE_ES_RESOURCEID_MAX; + switch(ResourceType) + { + case CFE_ES_APPID_BASE: + Status = CFE_ES_GetAppInfo(ModuleInfo, ResourceId); + break; + case CFE_ES_LIBID_BASE: + Status = CFE_ES_GetLibInfo(ModuleInfo, ResourceId); + break; + default: + /* + * Log a message if called with an invalid ID. + */ + CFE_ES_WriteToSysLog("CFE_ES_GetModuleInfo: Resource ID not valid: %lu\n", + CFE_ES_ResourceID_ToInteger(ResourceId)); + Status = CFE_ES_ERR_RESOURCEID_NOT_VALID; + break; + + } + + return(Status); -} /* End of CFE_ES_GetAppInfo() */ +} /* End of CFE_ES_GetModuleInfo() */ /* ** Function: CFE_ES_GetTaskInfo - See API and header file for details */ int32 CFE_ES_GetTaskInfo(CFE_ES_TaskInfo_t *TaskInfo, CFE_ES_ResourceID_t TaskId) { - CFE_ES_TaskRecord_t *TaskRecPtr; - int32 ReturnCode; + CFE_ES_TaskRecord_t *TaskRecPtr; + CFE_ES_AppRecord_t *AppRecPtr; + int32 Status; - if ( TaskInfo == NULL ) - { - CFE_ES_WriteToSysLog("CFE_ES_GetTaskInfo: Invalid Parameter ( Null Pointer )\n"); - return CFE_ES_ERR_BUFFER; - } + if ( TaskInfo == NULL ) + { + CFE_ES_WriteToSysLog("CFE_ES_GetTaskInfo: Invalid Parameter ( Null Pointer )\n"); + return CFE_ES_ERR_BUFFER; + } - memset(TaskInfo, 0, sizeof(*TaskInfo)); + memset(TaskInfo, 0, sizeof(*TaskInfo)); - /* - ** Get Task Record - */ - TaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskId); - if ( TaskRecPtr == NULL ) - { - CFE_ES_WriteToSysLog("CFE_ES_GetTaskInfo: Task ID Not Valid: %lu\n", - CFE_ES_ResourceID_ToInteger(TaskId)); - return CFE_ES_ERR_RESOURCEID_NOT_VALID; - } + TaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskId); - /* - * Note - cannot check if the TaskID is active here, - * as the table is not locked. The internal function - * should lock and check. - */ - ReturnCode = CFE_ES_GetTaskInfoInternal(TaskRecPtr, TaskInfo); - if (ReturnCode != CFE_SUCCESS) - { - CFE_ES_WriteToSysLog("CFE_ES_GetTaskInfo: Task ID Not Active: %lu\n", - CFE_ES_ResourceID_ToInteger(TaskId)); - } + CFE_ES_LockSharedData(__func__,__LINE__); - return(ReturnCode); + if ( !CFE_ES_TaskRecordIsMatch(TaskRecPtr, TaskId) ) + { + /* task ID is bad */ + Status = CFE_ES_ERR_RESOURCEID_NOT_VALID; + CFE_ES_SysLogWrite_Unsync("CFE_ES_GetTaskInfo: Task ID Not Active: %lu\n", + CFE_ES_ResourceID_ToInteger(TaskId)); + } + else + { + + /* + ** Get the Application ID and Task Name + */ + TaskInfo->AppId = TaskRecPtr->AppId; + strncpy(TaskInfo->TaskName, + CFE_ES_TaskRecordGetName(TaskRecPtr), + sizeof(TaskInfo->TaskName)-1); + TaskInfo->TaskName[sizeof(TaskInfo->TaskName)-1] = '\0'; + + /* + ** Store away the Task ID ( for the QueryAllTasks Cmd ) + */ + TaskInfo->TaskId = CFE_ES_TaskRecordGetID(TaskRecPtr); + + /* + ** Get the Execution counter for the task + */ + TaskInfo->ExecutionCounter = TaskRecPtr->ExecutionCounter; + + /* + ** Get the Application Details + */ + AppRecPtr = CFE_ES_LocateAppRecordByID(TaskRecPtr->AppId); + if (CFE_ES_AppRecordIsMatch(AppRecPtr, TaskRecPtr->AppId)) + { + strncpy(TaskInfo->AppName, + CFE_ES_AppRecordGetName(AppRecPtr), + sizeof(TaskInfo->AppName)-1); + TaskInfo->AppName[sizeof(TaskInfo->AppName)-1] = '\0'; + Status = CFE_SUCCESS; + } + else + { + /* task ID was OK but parent app ID is bad */ + Status = CFE_ES_ERR_RESOURCEID_NOT_VALID; + } + } + + CFE_ES_UnlockSharedData(__func__,__LINE__); + + return(Status); } /* End of CFE_ES_GetTaskInfo() */ diff --git a/fsw/cfe-core/src/es/cfe_es_apps.c b/fsw/cfe-core/src/es/cfe_es_apps.c index ebd7916de..3800a898c 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.c +++ b/fsw/cfe-core/src/es/cfe_es_apps.c @@ -343,6 +343,236 @@ int32 CFE_ES_ParseFileEntry(const char **TokenList, uint32 NumTokens) } +/* +**------------------------------------------------------------------------------------- +** Name: CFE_ES_LoadModule +** +** Helper function to load + configure (but not start) a new app/lib module +** +** Loads the module file via OSAL and stores all relevant info in the table entry as necessary. +** +**------------------------------------------------------------------------------------- +*/ +int32 CFE_ES_LoadModule(const CFE_ES_ModuleLoadParams_t* LoadParams, CFE_ES_ModuleLoadStatus_t *LoadStatus) +{ + osal_id_t ModuleId; + cpuaddr StartAddr; + int32 ReturnCode; + int32 StatusCode; + + StartAddr = 0; + ReturnCode = CFE_SUCCESS; + + if (LoadParams->FileName[0] != 0) + { + /* + ** Load the module via OSAL. + */ + StatusCode = OS_ModuleLoad ( &ModuleId, + LoadParams->Name, + LoadParams->FileName ); + + if (StatusCode != OS_SUCCESS) + { + CFE_ES_WriteToSysLog("ES Startup: Could not load file:%s. EC = 0x%08X\n", + LoadParams->FileName, (unsigned int)StatusCode); + ModuleId = OS_OBJECT_ID_UNDEFINED; + ReturnCode = CFE_STATUS_EXTERNAL_RESOURCE_FAIL; + } + } + else + { + ModuleId = OS_OBJECT_ID_UNDEFINED; + } + + /* + ** If the Load was OK, then lookup the address of the entry point + */ + if (ReturnCode == CFE_SUCCESS && LoadParams->EntryPoint[0] != 0) + { + StatusCode = OS_SymbolLookup(&StartAddr, LoadParams->EntryPoint); + if (StatusCode != OS_SUCCESS) + { + CFE_ES_WriteToSysLog("ES Startup: Could not find symbol:%s. EC = 0x%08X\n", + LoadParams->EntryPoint, (unsigned int)StatusCode); + ReturnCode = CFE_STATUS_EXTERNAL_RESOURCE_FAIL; + } + } + + if ( ReturnCode == CFE_SUCCESS ) + { + /* store the data in the app record after successful load+lookup */ + LoadStatus->ModuleId = ModuleId; + LoadStatus->EntryAddress = StartAddr; + } + else if (OS_ObjectIdDefined(ModuleId)) + { + /* If the module had been successfully loaded, then unload it, + * so that it does not consume resources */ + StatusCode = OS_ModuleUnload(ModuleId); + if ( StatusCode != OS_SUCCESS ) /* There's not much we can do except notify */ + { + CFE_ES_WriteToSysLog("ES Startup: Failed to unload: %s. EC = 0x%08X\n", + LoadParams->Name, (unsigned int)StatusCode); + } + } + + return ReturnCode; +} + +/* +**------------------------------------------------------------------------------------- +** Name: CFE_ES_GetAppEntryPoint +** +** Helper function to act as the intermediate entry point of an app +** This is to support starting apps before having a fully completed entry in the +** global app table. The app startup will delay until the app creation is completed +** and verified, then the actual entry point will be determined. +** +**------------------------------------------------------------------------------------- +*/ +int32 CFE_ES_GetAppEntryPoint(osal_task_entry *FuncPtr) +{ + CFE_ES_AppRecord_t *AppRecPtr; + int32 ReturnCode; + int32 Timeout; + + /* + * Use the same timeout as was used for the startup script itself. + */ + ReturnCode = CFE_ES_ERR_APP_REGISTER; + Timeout = CFE_PLATFORM_ES_STARTUP_SCRIPT_TIMEOUT_MSEC; + + while(true) + { + OS_TaskDelay(CFE_PLATFORM_ES_STARTUP_SYNC_POLL_MSEC); + + CFE_ES_LockSharedData(__func__,__LINE__); + AppRecPtr = CFE_ES_GetAppRecordByContext(); + if (AppRecPtr != NULL) + { + AppRecPtr->AppState = CFE_ES_AppState_EARLY_INIT; + *FuncPtr = (osal_task_entry)AppRecPtr->ModuleInfo.EntryAddress; + ReturnCode = CFE_SUCCESS; + } + CFE_ES_UnlockSharedData(__func__,__LINE__); + + if (ReturnCode == CFE_SUCCESS || Timeout <= 0) + { + /* end of loop condition */ + break; + } + + Timeout -= CFE_PLATFORM_ES_STARTUP_SYNC_POLL_MSEC; + } + + return (ReturnCode); +} + +/* +**------------------------------------------------------------------------------------- +** Name: CFE_ES_AppEntryPoint +** +** Helper function to act as the intermediate entry point of an app +** This is to support starting apps before having a fully completed entry in the +** global app table. The app startup will delay until the app creation is completed +** and verified, then the actual entry point will be determined. +** +**------------------------------------------------------------------------------------- +*/ +void CFE_ES_AppEntryPoint(void) +{ + osal_task_entry RealEntryFunc; + + if (CFE_ES_GetAppEntryPoint(&RealEntryFunc) == CFE_SUCCESS && + RealEntryFunc != NULL) + { + (*RealEntryFunc)(); + } +} + +/* +**------------------------------------------------------------------------------------- +** Name: CFE_ES_StartMainTask +** +** Helper function to start (but not load) a new app/lib module +** +** Note that OSAL does not separate the action of creating and start a task, providing +** only OS_TaskCreate which does both. But there is a potential race condition if +** the real task code starts and calls e.g. CFE_ES_RegisterApp() or any other function +** that depends on having an AppID context, before its fully registered in the global app table. +** +** Therefore this calls a dedicated CFE_ES_AppEntryPoint which then will wait until +** the task is fully registered in the global, before calling the actual app entry point. +** +**------------------------------------------------------------------------------------- +*/ +int32 CFE_ES_StartAppTask(const CFE_ES_AppStartParams_t* StartParams, CFE_ES_ResourceID_t RefAppId, CFE_ES_ResourceID_t *TaskIdPtr) +{ + CFE_ES_TaskRecord_t *TaskRecPtr; + osal_id_t OsalTaskId; + CFE_ES_ResourceID_t TaskId; + int32 StatusCode; + int32 ReturnCode; + + /* + ** Create the primary task for the newly loaded task + */ + StatusCode = OS_TaskCreate(&OsalTaskId, /* task id */ + StartParams->BasicInfo.Name, /* task name */ + CFE_ES_AppEntryPoint, /* task function pointer */ + NULL, /* stack pointer (allocate) */ + StartParams->StackSize, /* stack size */ + StartParams->Priority, /* task priority */ + OS_FP_ENABLED); /* task options */ + + CFE_ES_LockSharedData(__func__,__LINE__); + + if ( StatusCode == OS_SUCCESS ) + { + /* + * As this is a newly-created task, this shouldn't fail. + * The entry is not (yet) matching the task ID - it will be + * initialized here. + */ + TaskId = CFE_ES_ResourceID_FromOSAL(OsalTaskId); + TaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskId); + if ( CFE_ES_TaskRecordIsUsed(TaskRecPtr) ) + { + CFE_ES_SysLogWrite_Unsync("ES Startup: Error: ES_TaskTable slot for ID %lx in use at task creation!\n", + OS_ObjectIdToInteger(OsalTaskId)); + } + + /* + * Clear any other/stale data that might be in the entry, + * and reset all fields to the correct value. + */ + memset(TaskRecPtr, 0, sizeof(*TaskRecPtr)); + + TaskRecPtr->AppId = RefAppId; + strncpy(TaskRecPtr->TaskName, StartParams->BasicInfo.Name, sizeof(TaskRecPtr->TaskName)-1); + CFE_ES_TaskRecordSetUsed(TaskRecPtr, TaskId); + + /* + ** Increment the registered Task count. + */ + CFE_ES_Global.RegisteredTasks++; + ReturnCode = CFE_SUCCESS; + *TaskIdPtr = TaskId; + } + else + { + CFE_ES_SysLogWrite_Unsync("ES Startup: AppCreate Error: TaskCreate %s Failed. EC = 0x%08X!\n", + StartParams->BasicInfo.Name,(unsigned int)StatusCode); + ReturnCode = CFE_STATUS_EXTERNAL_RESOURCE_FAIL; + *TaskIdPtr = CFE_ES_RESOURCEID_UNDEFINED; + } + + CFE_ES_UnlockSharedData(__func__,__LINE__); + + return ReturnCode; +} + /* **--------------------------------------------------------------------------------------- ** Name: ES_AppCreate @@ -356,19 +586,15 @@ int32 CFE_ES_ParseFileEntry(const char **TokenList, uint32 NumTokens) */ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, const char *FileName, - const void *EntryPointData, + const char *EntryPointName, const char *AppName, uint32 Priority, uint32 StackSize, uint32 ExceptionAction) { - cpuaddr StartAddr; - int32 ReturnCode; CFE_Status_t Status; - osal_id_t ModuleId; - osal_id_t MainTaskId; + CFE_ES_ResourceID_t MainTaskId; CFE_ES_AppRecord_t *AppRecPtr; - CFE_ES_TaskRecord_t *TaskRecPtr; CFE_ES_ResourceID_t PendingAppId; /* @@ -428,6 +654,31 @@ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, { /* Fully clear the entry, just in case of stale data */ memset(AppRecPtr, 0, sizeof(*AppRecPtr)); + + /* + * Fill out the parameters in the StartParams sub-structure + */ + AppRecPtr->Type = CFE_ES_AppType_EXTERNAL; + strncpy(AppRecPtr->StartParams.BasicInfo.Name, AppName, + sizeof(AppRecPtr->StartParams.BasicInfo.Name)-1); + strncpy(AppRecPtr->StartParams.BasicInfo.FileName, FileName, + sizeof(AppRecPtr->StartParams.BasicInfo.FileName)-1); + if (EntryPointName != NULL && strcmp(EntryPointName, "NULL") != 0) + { + strncpy(AppRecPtr->StartParams.BasicInfo.EntryPoint, EntryPointName, + sizeof(AppRecPtr->StartParams.BasicInfo.EntryPoint)-1); + } + + AppRecPtr->StartParams.StackSize = StackSize; + AppRecPtr->StartParams.ExceptionAction = ExceptionAction; + AppRecPtr->StartParams.Priority = Priority; + + /* + * Fill out the Task State info + */ + AppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; + AppRecPtr->ControlReq.AppTimerMsec = 0; + CFE_ES_AppRecordSetUsed(AppRecPtr, CFE_ES_RESOURCEID_RESERVED); CFE_ES_Global.LastAppId = PendingAppId; Status = CFE_SUCCESS; @@ -437,142 +688,63 @@ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, CFE_ES_UnlockSharedData(__func__,__LINE__); /* - ** If a slot was found, create the application - */ - if (Status == CFE_SUCCESS) + * If ID allocation was not successful, return now. + * A message regarding the issue should have already been logged + */ + if (Status != CFE_SUCCESS) { - /* - ** Load the module - */ - ReturnCode = OS_ModuleLoad ( &ModuleId, AppName, FileName ); - - /* - ** If the Load was OK, then lookup the address of the entry point - */ - if ( ReturnCode == OS_SUCCESS ) - { - ReturnCode = OS_SymbolLookup( &StartAddr, (const char*)EntryPointData ); - if ( ReturnCode != OS_SUCCESS ) - { - CFE_ES_WriteToSysLog("ES Startup: Could not find symbol:%s. EC = 0x%08X\n", - (const char*)EntryPointData, (unsigned int)ReturnCode); - - CFE_ES_LockSharedData(__func__,__LINE__); - CFE_ES_AppRecordSetFree(AppRecPtr); /* Release slot */ - CFE_ES_UnlockSharedData(__func__,__LINE__); - - /* Unload the module from memory, so that it does not consume resources */ - ReturnCode = OS_ModuleUnload(ModuleId); - if ( ReturnCode != OS_SUCCESS ) /* There's not much we can do except notify */ - { - CFE_ES_WriteToSysLog("ES Startup: Failed to unload APP: %s. EC = 0x%08X\n", - AppName, (unsigned int)ReturnCode); - } - - return(CFE_ES_ERR_APP_CREATE); - } - } - else /* load not successful */ - { - CFE_ES_WriteToSysLog("ES Startup: Could not load cFE application file:%s. EC = 0x%08X\n", - FileName, (unsigned int)ReturnCode); - - CFE_ES_LockSharedData(__func__,__LINE__); - CFE_ES_AppRecordSetFree(AppRecPtr); /* Release slot */ - CFE_ES_UnlockSharedData(__func__,__LINE__); - - return(CFE_ES_ERR_APP_CREATE); - } - - /* - ** If the EntryPoint symbol was found, then start creating the App - */ - CFE_ES_LockSharedData(__func__,__LINE__); - /* - ** Allocate and populate the ES_AppTable entry - */ - AppRecPtr->Type = CFE_ES_AppType_EXTERNAL; - - /* - ** Fill out the parameters in the AppStartParams sub-structure - */ - strncpy((char *)AppRecPtr->StartParams.Name, AppName, OS_MAX_API_NAME); - AppRecPtr->StartParams.Name[OS_MAX_API_NAME - 1] = '\0'; - - strncpy((char *)AppRecPtr->StartParams.EntryPoint, (const char *)EntryPointData, OS_MAX_API_NAME); - AppRecPtr->StartParams.EntryPoint[OS_MAX_API_NAME - 1] = '\0'; - strncpy((char *)AppRecPtr->StartParams.FileName, FileName, OS_MAX_PATH_LEN); - AppRecPtr->StartParams.FileName[OS_MAX_PATH_LEN - 1] = '\0'; - - AppRecPtr->StartParams.StackSize = StackSize; - - AppRecPtr->StartParams.StartAddress = StartAddr; - AppRecPtr->StartParams.ModuleId = ModuleId; - - AppRecPtr->StartParams.ExceptionAction = ExceptionAction; - AppRecPtr->StartParams.Priority = Priority; - - /* - ** Fill out the Task State info - */ - AppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; - AppRecPtr->ControlReq.AppTimerMsec = 0; - - /* - ** Create the primary task for the newly loaded task - */ - ReturnCode = OS_TaskCreate(&MainTaskId, /* task id */ - AppName, /* task name */ - (osal_task_entry)StartAddr, /* task function pointer */ - NULL, /* stack pointer */ - StackSize, /* stack size */ - Priority, /* task priority */ - OS_FP_ENABLED); /* task options */ - + return Status; + } - if(ReturnCode != OS_SUCCESS) - { - CFE_ES_SysLogWrite_Unsync("ES Startup: AppCreate Error: TaskCreate %s Failed. EC = 0x%08X!\n", - AppName,(unsigned int)ReturnCode); + /* + * Load the module based on StartParams configured above. + */ + Status = CFE_ES_LoadModule(&AppRecPtr->StartParams.BasicInfo, &AppRecPtr->ModuleInfo); - CFE_ES_AppRecordSetFree(AppRecPtr); /* Release slot */ - CFE_ES_UnlockSharedData(__func__,__LINE__); + /* + * If the Load was OK, then complete the initialization + */ + if (Status == CFE_SUCCESS) + { + Status = CFE_ES_StartAppTask(&AppRecPtr->StartParams, PendingAppId, &MainTaskId); + } + else + { + MainTaskId = CFE_ES_RESOURCEID_UNDEFINED; + } - Status = CFE_ES_ERR_APP_CREATE; - } - else - { + /* + * Finalize data in the app table entry, which must be done under lock. + * This transitions the entry from being RESERVED to the real ID. + */ + CFE_ES_LockSharedData(__func__,__LINE__); - /* - ** Record the ES_TaskTable entry - */ - AppRecPtr->MainTaskId = CFE_ES_ResourceID_FromOSAL(MainTaskId); - TaskRecPtr = CFE_ES_LocateTaskRecordByID(AppRecPtr->MainTaskId); + if ( Status == CFE_SUCCESS ) + { + /* + * important - set the ID to its proper value + * which turns this into a real/valid table entry + */ + AppRecPtr->MainTaskId = MainTaskId; + CFE_ES_AppRecordSetUsed(AppRecPtr, PendingAppId); - if ( CFE_ES_TaskRecordIsUsed(TaskRecPtr) ) - { - CFE_ES_SysLogWrite_Unsync("ES Startup: Error: ES_TaskTable slot in use at task creation!\n"); - } - CFE_ES_TaskRecordSetUsed(TaskRecPtr,AppRecPtr->MainTaskId); - TaskRecPtr->AppId = PendingAppId; - /* The main task name is the same as the app name */ - strncpy(TaskRecPtr->TaskName, AppName, - sizeof(TaskRecPtr->TaskName)-1); - TaskRecPtr->TaskName[sizeof(TaskRecPtr->TaskName)-1]='\0'; - CFE_ES_AppRecordSetUsed(AppRecPtr, PendingAppId); - CFE_ES_SysLogWrite_Unsync("ES Startup: %s loaded and created\n", AppName); - *ApplicationIdPtr = PendingAppId; - - /* - ** Increment the registered App and Registered External Task variables. - */ - CFE_ES_Global.RegisteredTasks++; - CFE_ES_Global.RegisteredExternalApps++; + /* + ** Increment the registered App counter. + */ + CFE_ES_Global.RegisteredExternalApps++; + } + else + { + /* + * Set the table entry back to free + */ + CFE_ES_AppRecordSetFree(AppRecPtr); + PendingAppId = CFE_ES_RESOURCEID_UNDEFINED; + } - CFE_ES_UnlockSharedData(__func__,__LINE__); + CFE_ES_UnlockSharedData(__func__,__LINE__); - } /* End If OS_TaskCreate */ - } + *ApplicationIdPtr = PendingAppId; return Status; @@ -587,15 +759,13 @@ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, */ int32 CFE_ES_LoadLibrary(CFE_ES_ResourceID_t *LibraryIdPtr, const char *FileName, - const void *EntryPointData, + const char *EntryPointName, const char *LibName) { CFE_ES_LibraryEntryFuncPtr_t FunctionPointer; CFE_ES_LibRecord_t * LibSlotPtr; int32 Status; CFE_ES_ResourceID_t PendingLibId; - osal_id_t ModuleId; - bool IsModuleLoaded; /* * The FileName must not be NULL @@ -613,11 +783,8 @@ int32 CFE_ES_LoadLibrary(CFE_ES_ResourceID_t *LibraryIdPtr, /* ** Allocate an ES_LibTable entry */ - IsModuleLoaded = false; FunctionPointer = NULL; - 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 @@ -663,7 +830,20 @@ int32 CFE_ES_LoadLibrary(CFE_ES_ResourceID_t *LibraryIdPtr, { /* Fully clear the entry, just in case of stale data */ memset(LibSlotPtr, 0, sizeof(*LibSlotPtr)); - strcpy(LibSlotPtr->LibName, LibName); /* Size already checked */ + + /* + * Fill out the parameters in the AppStartParams sub-structure + */ + strncpy(LibSlotPtr->BasicInfo.Name, LibName, + sizeof(LibSlotPtr->BasicInfo.Name)-1); + strncpy(LibSlotPtr->BasicInfo.FileName, FileName, + sizeof(LibSlotPtr->BasicInfo.FileName)-1); + if (EntryPointName != NULL && strcmp(EntryPointName, "NULL") != 0) + { + strncpy(LibSlotPtr->BasicInfo.EntryPoint, EntryPointName, + sizeof(LibSlotPtr->BasicInfo.EntryPoint)-1); + } + CFE_ES_LibRecordSetUsed(LibSlotPtr, CFE_ES_RESOURCEID_RESERVED); CFE_ES_Global.LastLibId = PendingLibId; Status = CFE_SUCCESS; @@ -683,128 +863,51 @@ int32 CFE_ES_LoadLibrary(CFE_ES_ResourceID_t *LibraryIdPtr, } /* - * ------------------- - * IMPORTANT: - * - * there is now a reserved entry in the global library table, - * which must be freed if something goes wrong hereafter. - * - * Avoid any inline "return" statements - all paths must proceed to - * the end of this function where the cleanup will be done. - * - * Record sufficient breadcrumbs along the way, such that proper - * cleanup can be done in case it is necessary. - * ------------------- - */ - - /* - * STAGE 2: - * Do the OS_ModuleLoad() if is called for (i.e. ModuleLoadFile is NOT null) + * Load the module based on StartParams configured above. */ - if (Status == CFE_SUCCESS && FileName != NULL) + Status = CFE_ES_LoadModule(&LibSlotPtr->BasicInfo, &LibSlotPtr->ModuleInfo); + if (Status == CFE_SUCCESS) { - Status = OS_ModuleLoad( &ModuleId, LibName, FileName ); - if (Status == OS_SUCCESS) - { - Status = CFE_SUCCESS; /* just in case CFE_SUCCESS is different than OS_SUCCESS */ - IsModuleLoaded = true; - } - else - { - /* load not successful. Note OS errors are better displayed as decimal integers. */ - CFE_ES_WriteToSysLog("ES Startup: Could not load cFE Shared Library: %d\n", (int)Status); - Status = CFE_ES_ERR_LOAD_LIB; /* convert OS error to CFE error code */ - } + FunctionPointer = (CFE_ES_LibraryEntryFuncPtr_t)LibSlotPtr->ModuleInfo.EntryAddress; + if (FunctionPointer != NULL) + { + Status = (*FunctionPointer)(PendingLibId); + if (Status != CFE_SUCCESS) + { + CFE_ES_WriteToSysLog("ES Startup: Load Shared Library Init Error = 0x%08x\n", + (unsigned int)Status); + } + } } /* - * STAGE 3: - * Figure out the Entry point / Initialization function. - * - * This depends on whether it is a dynamically loaded or a statically linked library, - * or it could be omitted altogether for libraries which do not require an init function. - * - * For dynamically loaded objects where FileName is non-NULL, the - * "EntryPointData" is a normal C string (const char *) with the name of the function. - * - * If the name of the function is the string "NULL" -- then treat this as no function - * needed and skip the lookup entirely (this is to support startup scripts where some - * string must be in the entry point field). + * Finalize data in the app table entry, which must be done under lock. + * This transitions the entry from being RESERVED to the real type, + * either MAIN_TASK (success) or returning to INVALID (failure). */ - if (Status == CFE_SUCCESS && EntryPointData != NULL) - { - if (strcmp(EntryPointData, "NULL") != 0) - { - /* - * If the entry point is explicitly set as NULL, - * this means the library has no init function - skip the lookup. - * Otherwise lookup the address of the entry point - */ - cpuaddr StartAddr; - - Status = OS_SymbolLookup( &StartAddr, EntryPointData ); - if (Status == OS_SUCCESS) - { - Status = CFE_SUCCESS; /* just in case CFE_SUCCESS is different than OS_SUCCESS */ - FunctionPointer = (CFE_ES_LibraryEntryFuncPtr_t)StartAddr; - } - else - { - /* could not find symbol. Note OS errors are better displayed as decimal integers */ - CFE_ES_WriteToSysLog("ES Startup: Could not find Library Init symbol:%s. EC = %d\n", - (const char *)EntryPointData, (int)Status); - Status = CFE_ES_ERR_LOAD_LIB; /* convert OS error to CFE error code */ - } - } - } + CFE_ES_LockSharedData(__func__,__LINE__); - /* - * STAGE 4: - * Call the Initialization function, if one was identified during the previous stage - */ - if (Status == CFE_SUCCESS && FunctionPointer != NULL) + if ( Status == CFE_SUCCESS ) { - /* - ** Call the library initialization routine + /* + * important - set the ID to its proper value + * which turns this into a real/valid table entry */ - Status = (*FunctionPointer)(*LibraryIdPtr); - if (Status != CFE_SUCCESS) - { - CFE_ES_WriteToSysLog("ES Startup: Load Shared Library Init Error = 0x%08x\n", (unsigned int)Status); - } - } + CFE_ES_LibRecordSetUsed(LibSlotPtr, PendingLibId); - /* - * LAST STAGE: - * Do final clean-up - * - * If fully successful, then increment the "RegisteredLibs" counter. - * Otherwise in case of an error, do clean up based on the breadcrumbs - */ - if(Status == CFE_SUCCESS) - { - /* Increment the counter, which needs to be done under lock */ - CFE_ES_LockSharedData(__func__,__LINE__); - CFE_ES_LibRecordSetUsed(LibSlotPtr, PendingLibId); - CFE_ES_Global.RegisteredLibs++; - CFE_ES_UnlockSharedData(__func__,__LINE__); + /* + * Increment the registered Lib counter. + */ + CFE_ES_Global.RegisteredLibs++; } else { - /* - * If the above code had loaded a module, then unload it - */ - if (IsModuleLoaded) - { - OS_ModuleUnload( ModuleId ); - } - - /* Release Slot - No need to lock as it is resetting just a single value */ - CFE_ES_LibRecordSetFree(LibSlotPtr); - - PendingLibId = CFE_ES_RESOURCEID_UNDEFINED; + CFE_ES_LibRecordSetFree(LibSlotPtr); + PendingLibId = CFE_ES_RESOURCEID_UNDEFINED; } + CFE_ES_UnlockSharedData(__func__,__LINE__); + *LibraryIdPtr = PendingLibId; return(Status); @@ -822,9 +925,11 @@ int32 CFE_ES_LoadLibrary(CFE_ES_ResourceID_t *LibraryIdPtr, */ bool CFE_ES_RunAppTableScan(uint32 ElapsedTime, void *Arg) { - uint32 i; - CFE_ES_AppRecord_t *AppPtr; CFE_ES_AppTableScanState_t *State = (CFE_ES_AppTableScanState_t *)Arg; + uint32 i; + CFE_ES_AppRecord_t *AppPtr; + CFE_ES_ResourceID_t AppTimeoutList[CFE_PLATFORM_ES_MAX_APPLICATIONS]; + uint32 NumAppTimeouts; if (State->PendingAppStateChanges == 0) { @@ -845,6 +950,7 @@ bool CFE_ES_RunAppTableScan(uint32 ElapsedTime, void *Arg) * reset the background scan timer to the full value, * and take a snapshot of the the command counter. */ + NumAppTimeouts = 0; State->BackgroundScanTimer = CFE_PLATFORM_ES_APP_SCAN_RATE; State->LastScanCommandCount = CFE_ES_TaskData.CommandCounter; State->PendingAppStateChanges = 0; @@ -888,14 +994,10 @@ bool CFE_ES_RunAppTableScan(uint32 ElapsedTime, void *Arg) { AppPtr->ControlReq.AppTimerMsec = 0; - /* - * Temporarily unlock the table, and invoke the - * control request function for this app. - */ - CFE_ES_UnlockSharedData(__func__,__LINE__); - CFE_ES_ProcessControlRequest(AppPtr); - CFE_ES_LockSharedData(__func__,__LINE__); - } /* end if */ + /* Add it to the list to be processed later */ + AppTimeoutList[NumAppTimeouts] = CFE_ES_AppRecordGetID(AppPtr); + ++NumAppTimeouts; + } } else if (AppPtr->AppState == CFE_ES_AppState_RUNNING && AppPtr->ControlReq.AppControlRequest > CFE_ES_RunStatus_APP_RUN) @@ -915,6 +1017,22 @@ bool CFE_ES_RunAppTableScan(uint32 ElapsedTime, void *Arg) CFE_ES_UnlockSharedData(__func__,__LINE__); + + /* + * Now invoke the CFE_ES_ProcessControlRequest() routine for any app + * which has reached that point. + */ + for ( i = 0; i < NumAppTimeouts; i++ ) + { + /* + * Call CFE_ES_ProcessControlRequest() with a reference to + * the _copies_ of the app record details. (This avoids + * needing to access the global records outside of the lock). + */ + CFE_ES_ProcessControlRequest(AppTimeoutList[i]); + } + + /* * This state machine is considered active if there are any * pending app state changes. Returning "true" will cause this job @@ -932,180 +1050,228 @@ bool CFE_ES_RunAppTableScan(uint32 ElapsedTime, void *Arg) ** Purpose: This function will perform the requested control action for an application. **--------------------------------------------------------------------------------------- */ -void CFE_ES_ProcessControlRequest(CFE_ES_AppRecord_t *AppRecPtr) +void CFE_ES_ProcessControlRequest(CFE_ES_ResourceID_t AppId) { + CFE_ES_AppRecord_t *AppRecPtr; + uint32 PendingControlReq; + CFE_ES_AppStartParams_t OrigStartParams; + CFE_Status_t CleanupStatus; + CFE_Status_t StartupStatus; + CFE_ES_ResourceID_t NewAppId; + const char *ReqName; + char MessageDetail[48]; + uint16 EventID; + CFE_EVS_EventType_Enum_t EventType; + + /* Init/clear all local state variables */ + ReqName = NULL; + MessageDetail[0] = 0; + EventID = 0; + EventType = 0; + StartupStatus = CFE_SUCCESS; + PendingControlReq = 0; + NewAppId = CFE_ES_RESOURCEID_UNDEFINED; + AppRecPtr = CFE_ES_LocateAppRecordByID(AppId); + memset(&OrigStartParams, 0, sizeof(OrigStartParams)); - int32 Status; - CFE_ES_AppStartParams_t AppStartParams; - CFE_ES_ResourceID_t NewAppId; - /* - ** First get a copy of the Apps Start Parameters - */ - memcpy(&AppStartParams, &(AppRecPtr->StartParams), sizeof(CFE_ES_AppStartParams_t)); + /* + * Take a local snapshot of the important app record data + * This way it becomes private and can be accessed without + * concerns about other threads/tasks, even after the global + * data records are eventually cleared. + */ + CFE_ES_LockSharedData(__func__,__LINE__); - /* - ** Now, find out what kind of Application control is being requested - */ - switch ( AppRecPtr->ControlReq.AppControlRequest ) - { + if (CFE_ES_AppRecordIsMatch(AppRecPtr, AppId)) + { + PendingControlReq = AppRecPtr->ControlReq.AppControlRequest; + OrigStartParams = AppRecPtr->StartParams; + } - case CFE_ES_RunStatus_APP_EXIT: - /* - ** Kill the app, and dont restart it - */ - Status = CFE_ES_CleanUpApp(AppRecPtr); + CFE_ES_UnlockSharedData(__func__,__LINE__); - if ( Status == CFE_SUCCESS ) - { - CFE_EVS_SendEvent(CFE_ES_EXIT_APP_INF_EID, CFE_EVS_EventType_INFORMATION, - "Exit Application %s Completed.",AppStartParams.Name); - } - else - { - CFE_EVS_SendEvent(CFE_ES_EXIT_APP_ERR_EID, CFE_EVS_EventType_ERROR, - "Exit Application %s Failed: CleanUpApp Error 0x%08X.",AppStartParams.Name, (unsigned int)Status); - } - break; + /* + * All control requests start by deleting the app/task and + * all associated resources. + * + * The reload/restart requests will start it again, and it gets + * a new appID. For other requests it just leaves it deleted. + * + * Note that Cleanup can fail for a variety of reasons, including + * situations where e.g. a task ID had become stale because the task + * already exited itself. In most cases these are minor errors and + * reflect problems with the consistency of the old app record. + * + * Even when this happens the cleanup should still do its best effort + * to release all relevant global data entries. So it should not + * prevent starting the new app, if a restart/reload is indicated. + */ + CleanupStatus = CFE_ES_CleanUpApp(AppId); - case CFE_ES_RunStatus_APP_ERROR: - /* - ** Kill the app, and dont restart it - */ - Status = CFE_ES_CleanUpApp(AppRecPtr); + /* + * Attempt to restart the app if the request indicated to do so, + * regardless of the CleanupStatus. + */ + if ( PendingControlReq == CFE_ES_RunStatus_SYS_RESTART || + PendingControlReq == CFE_ES_RunStatus_SYS_RELOAD ) + { + StartupStatus = CFE_ES_AppCreate(&NewAppId, + OrigStartParams.BasicInfo.FileName, + OrigStartParams.BasicInfo.EntryPoint, + OrigStartParams.BasicInfo.Name, + OrigStartParams.Priority, + OrigStartParams.StackSize, + OrigStartParams.ExceptionAction); + } - if ( Status == CFE_SUCCESS ) - { - CFE_EVS_SendEvent(CFE_ES_ERREXIT_APP_INF_EID, CFE_EVS_EventType_INFORMATION, - "Exit Application %s on Error Completed.",AppStartParams.Name); - } - else - { - CFE_EVS_SendEvent(CFE_ES_ERREXIT_APP_ERR_EID, CFE_EVS_EventType_ERROR, - "Exit Application %s on Error Failed: CleanUpApp Error 0x%08X.",AppStartParams.Name, (unsigned int)Status); - } - break; + /* + * Determine the event ID associated with the control request, + * which indicates the success/failure of the operation and + * any other relevant detail. + * + * Note that the specific event ID that gets generated is the only + * other difference between all these control request types. + */ + switch ( PendingControlReq ) + { + case CFE_ES_RunStatus_APP_EXIT: + ReqName = "Exit"; + if (CleanupStatus != CFE_SUCCESS) + { + /* error event for this request */ + EventID = CFE_ES_EXIT_APP_ERR_EID; + } + else + { + /* success event for this request */ + EventID = CFE_ES_EXIT_APP_INF_EID; + } + break; - case CFE_ES_RunStatus_SYS_DELETE: - /* - ** Kill the app, and dont restart it - */ - Status = CFE_ES_CleanUpApp(AppRecPtr); + case CFE_ES_RunStatus_APP_ERROR: + ReqName = "Exit"; + if ( CleanupStatus != CFE_SUCCESS ) + { + /* error event for this request */ + EventID = CFE_ES_ERREXIT_APP_ERR_EID; + } + else + { + /* success event for this request */ + EventID = CFE_ES_ERREXIT_APP_INF_EID; + } + break; - if ( Status == CFE_SUCCESS ) - { - CFE_EVS_SendEvent(CFE_ES_STOP_INF_EID, CFE_EVS_EventType_INFORMATION, - "Stop Application %s Completed.",AppStartParams.Name); - } - else - { - CFE_EVS_SendEvent(CFE_ES_STOP_ERR3_EID, CFE_EVS_EventType_ERROR, - "Stop Application %s Failed: CleanUpApp Error 0x%08X.",AppStartParams.Name, (unsigned int)Status); - } - break; + case CFE_ES_RunStatus_SYS_DELETE: + ReqName = "Stop"; + if ( CleanupStatus != CFE_SUCCESS ) + { + /* error event for this request */ + EventID = CFE_ES_STOP_ERR3_EID; + } + else + { + /* success event for this request */ + EventID = CFE_ES_STOP_INF_EID; + } + break; - case CFE_ES_RunStatus_SYS_RESTART: - /* - ** Kill the app - */ - Status = CFE_ES_CleanUpApp(AppRecPtr); + case CFE_ES_RunStatus_SYS_RESTART: + ReqName = "Restart"; + if ( CleanupStatus != CFE_SUCCESS ) + { + /* error event for this request */ + EventID = CFE_ES_RESTART_APP_ERR4_EID; + } + else if ( StartupStatus != CFE_SUCCESS ) + { + /* error event for this request */ + EventID = CFE_ES_RESTART_APP_ERR3_EID; + } + else + { + /* success event for this request */ + EventID = CFE_ES_RESTART_APP_INF_EID; + } + break; - if ( Status == CFE_SUCCESS ) - { - /* - ** And start it back up again - */ - Status = CFE_ES_AppCreate(&NewAppId, (char *)AppStartParams.FileName, - (char *)AppStartParams.EntryPoint, - (char *)AppStartParams.Name, - AppStartParams.Priority, - AppStartParams.StackSize, - AppStartParams.ExceptionAction); - - if ( Status == CFE_SUCCESS ) - { - CFE_EVS_SendEvent(CFE_ES_RESTART_APP_INF_EID, CFE_EVS_EventType_INFORMATION, - "Restart Application %s Completed.", AppStartParams.Name); - } - else - { - CFE_EVS_SendEvent(CFE_ES_RESTART_APP_ERR3_EID, CFE_EVS_EventType_ERROR, - "Restart Application %s Failed: AppCreate Error 0x%08X.", AppStartParams.Name, (unsigned int)Status); - } - } - else - { - CFE_EVS_SendEvent(CFE_ES_RESTART_APP_ERR4_EID, CFE_EVS_EventType_ERROR, - "Restart Application %s Failed: CleanUpApp Error 0x%08X.", AppStartParams.Name, (unsigned int)Status); - } - break; + case CFE_ES_RunStatus_SYS_RELOAD: + ReqName = "Reload"; + if ( CleanupStatus != CFE_SUCCESS ) + { + /* error event for this request */ + EventID = CFE_ES_RELOAD_APP_ERR4_EID; + } + else if ( StartupStatus != CFE_SUCCESS ) + { + /* error event for this request */ + EventID = CFE_ES_RELOAD_APP_ERR3_EID; + } + else + { + /* success event for this request */ + EventID = CFE_ES_RELOAD_APP_INF_EID; + } + break; - case CFE_ES_RunStatus_SYS_RELOAD: - /* - ** Kill the app + /* + * These two cases below should never occur so they are always + * reported as errors, but the CFE_ES_CleanUpApp() should hopefully + * have fixed it either way. */ - Status = CFE_ES_CleanUpApp(AppRecPtr); + case CFE_ES_RunStatus_SYS_EXCEPTION: + ReqName = "ES_ProcControlReq: Invalid State"; + EventID = CFE_ES_PCR_ERR1_EID; + snprintf(MessageDetail, sizeof(MessageDetail), "EXCEPTION"); + break; - if ( Status == CFE_SUCCESS ) - { - /* - ** And start it back up again - */ - Status = CFE_ES_AppCreate(&NewAppId, (char *)AppStartParams.FileName, - (char *)AppStartParams.EntryPoint, - (char *)AppStartParams.Name, - AppStartParams.Priority, - AppStartParams.StackSize, - AppStartParams.ExceptionAction); - if ( Status == CFE_SUCCESS ) - { - CFE_EVS_SendEvent(CFE_ES_RELOAD_APP_INF_EID, CFE_EVS_EventType_INFORMATION, - "Reload Application %s Completed.", AppStartParams.Name); - } - else - { - CFE_EVS_SendEvent(CFE_ES_RELOAD_APP_ERR3_EID, CFE_EVS_EventType_ERROR, - "Reload Application %s Failed: AppCreate Error 0x%08X.", AppStartParams.Name, (unsigned int)Status); - } - } - else - { - CFE_EVS_SendEvent(CFE_ES_RELOAD_APP_ERR4_EID, CFE_EVS_EventType_ERROR, - "Reload Application %s Failed: CleanUpApp Error 0x%08X.", AppStartParams.Name, (unsigned int)Status); - } + default: + ReqName = "ES_ProcControlReq: Unknown State"; + EventID = CFE_ES_PCR_ERR2_EID; + snprintf(MessageDetail, sizeof(MessageDetail), "( %lu )", + (unsigned long)PendingControlReq); + break; + } - break; - - case CFE_ES_RunStatus_SYS_EXCEPTION: - - CFE_EVS_SendEvent(CFE_ES_PCR_ERR1_EID, CFE_EVS_EventType_ERROR, - "ES_ProcControlReq: Invalid State (EXCEPTION) Application %s.", - AppStartParams.Name); - /* - * Bug #58: This message/event keeps repeating itself indefinitely. - * - * Change the request state to DELETE so the next scan will clean - * up this table entry. - */ - AppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_DELETE; - break; - - default: - - CFE_EVS_SendEvent(CFE_ES_PCR_ERR2_EID, CFE_EVS_EventType_ERROR, - "ES_ProcControlReq: Unknown State ( %d ) Application %s.", - (int)AppRecPtr->ControlReq.AppControlRequest, AppStartParams.Name); - - /* - * Bug #58: This message/event keeps repeating itself indefinitely. - * - * Change the request state to DELETE so the next scan will clean - * up this table entry. - */ - AppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_DELETE; - break; + if (EventID != 0 && ReqName != NULL) + { + if ( MessageDetail[0] != 0 ) + { + /* Detail message already set, assume it is an error event */ + EventType = CFE_EVS_EventType_ERROR; + } + else if ( StartupStatus != CFE_SUCCESS ) + { + /* Make detail message for event containing startup error code */ + EventType = CFE_EVS_EventType_ERROR; + snprintf(MessageDetail, sizeof(MessageDetail), + "Failed: AppCreate Error 0x%08X.",(unsigned int)StartupStatus); + } + else if ( CleanupStatus != CFE_SUCCESS ) + { + /* Make detail message for event containing cleanup error code */ + EventType = CFE_EVS_EventType_ERROR; + snprintf(MessageDetail, sizeof(MessageDetail), + "Failed: CleanUpApp Error 0x%08X.",(unsigned int)CleanupStatus); + } + else if (CFE_ES_ResourceID_IsDefined(NewAppId)) + { + /* Record success message for event where app is restarted */ + EventType = CFE_EVS_EventType_INFORMATION; + snprintf(MessageDetail, sizeof(MessageDetail), "Completed, AppID=%lu", + CFE_ES_ResourceID_ToInteger(NewAppId)); + } + else + { + /* Record success message for event */ + EventType = CFE_EVS_EventType_INFORMATION; + snprintf(MessageDetail, sizeof(MessageDetail), "Completed."); + } - } + CFE_EVS_SendEvent(EventID, EventType, "%s Application %s %s", + ReqName, OrigStartParams.BasicInfo.Name, MessageDetail); + } } /* End Function */ @@ -1116,154 +1282,248 @@ void CFE_ES_ProcessControlRequest(CFE_ES_AppRecord_t *AppRecPtr) ** Purpose: Delete an application by cleaning up all of it's resources. **--------------------------------------------------------------------------------------- */ -int32 CFE_ES_CleanUpApp(CFE_ES_AppRecord_t *AppRecPtr) +int32 CFE_ES_CleanUpApp(CFE_ES_ResourceID_t AppId) { - uint32 i; - int32 Status; - CFE_ES_ResourceID_t MainTaskId; - CFE_ES_ResourceID_t CurrTaskId; - int32 ReturnCode = CFE_SUCCESS; - CFE_ES_TaskRecord_t *TaskRecPtr; - CFE_ES_MemPoolRecord_t *MemPoolRecPtr; - CFE_ES_MemHandle_t PoolId; - CFE_ES_ResourceID_t AppId; + uint32 i; + int32 Status; + int32 ReturnCode; + CFE_ES_ResourceID_t TaskList[OS_MAX_TASKS]; + CFE_ES_MemHandle_t PoolList[CFE_PLATFORM_ES_MAX_MEMORY_POOLS]; + osal_id_t ModuleId; + uint32 NumTasks; + uint32 NumPools; + CFE_ES_AppRecord_t *AppRecPtr; + CFE_ES_TaskRecord_t *TaskRecPtr; + CFE_ES_MemPoolRecord_t *MemPoolRecPtr; - /* - * Retrieve the abstract AppID for calling cleanup - * routine in _other_ modules. - */ - AppId = CFE_ES_AppRecordGetID(AppRecPtr); - /* - ** Call the Table Clean up function - */ -#ifndef EXCLUDE_CFE_TBL - CFE_TBL_CleanUpApp(AppId); -#endif - /* - ** Call the Software Bus clean up function - */ - CFE_SB_CleanUpApp(AppId); + NumTasks = 0; + NumPools = 0; + ModuleId = OS_OBJECT_ID_UNDEFINED; + ReturnCode = CFE_SUCCESS; - /* - ** Call the TIME Clean up function - */ - CFE_TIME_CleanUpApp(AppId); + AppRecPtr = CFE_ES_LocateAppRecordByID(AppId); - /* - ** Call the EVS Clean up function - */ - Status = CFE_EVS_CleanUpApp(AppId); - if ( Status != CFE_SUCCESS ) - { - CFE_ES_WriteToSysLog("CFE_ES_CleanUpApp: Call to CFE_EVS_CleanUpApp returned Error: 0x%08X\n",(unsigned int)Status); - ReturnCode = CFE_ES_APP_CLEANUP_ERR; - } + /* + * Collect a list of resources previously owned by this app, which + * must be done while the global data is locked. + */ + CFE_ES_LockSharedData(__func__,__LINE__); + if (CFE_ES_AppRecordIsMatch(AppRecPtr, AppId)) + { + if (AppRecPtr->Type == CFE_ES_AppType_EXTERNAL) + { + CFE_ES_Global.RegisteredExternalApps--; - /* - ** Delete the ES Resources - */ - CFE_ES_LockSharedData(__func__,__LINE__); + /* + * Get the Module ID, if it was an external app + * + * (this will be OS_OBJECT_ID_UNDEFINED if it was not loaded dynamically) + */ + ModuleId = AppRecPtr->ModuleInfo.ModuleId; + } - /* - ** Get Main Task ID - */ - MainTaskId = AppRecPtr->MainTaskId; + /* + * Collect all tasks associated with this app + */ + TaskRecPtr = CFE_ES_Global.TaskTable; + for ( i = 0; i < OS_MAX_TASKS; i++ ) + { + if ( CFE_ES_TaskRecordIsUsed(TaskRecPtr) && + CFE_ES_ResourceID_Equal(TaskRecPtr->AppId, AppId)) + { + TaskList[NumTasks] = CFE_ES_TaskRecordGetID(TaskRecPtr); - /* - ** Delete any child tasks associated with this app - */ - TaskRecPtr = CFE_ES_Global.TaskTable; - for ( i = 0; i < OS_MAX_TASKS; i++ ) - { - /* delete only CHILD tasks - not the MainTaskId, which will be deleted later (below) */ - if ( CFE_ES_TaskRecordIsUsed(TaskRecPtr) && - CFE_ES_ResourceID_Equal(TaskRecPtr->AppId, AppId)) - { - CurrTaskId = CFE_ES_TaskRecordGetID(TaskRecPtr); - if (!CFE_ES_ResourceID_Equal(CurrTaskId, MainTaskId)) - { - Status = CFE_ES_CleanupTaskResources(CurrTaskId); - if ( Status != CFE_SUCCESS ) - { - CFE_ES_SysLogWrite_Unsync("CFE_ES_CleanUpApp: CleanUpTaskResources for Task ID:%lu returned Error: 0x%08X\n", - CFE_ES_ResourceID_ToInteger(CurrTaskId), (unsigned int)Status); - ReturnCode = CFE_ES_APP_CLEANUP_ERR; - } - } /* end if */ - } + /* Store the main task ID at index 0 (swap with whatever was there) */ + if (CFE_ES_ResourceID_Equal(TaskList[NumTasks], AppRecPtr->MainTaskId) && + NumTasks != 0) + { + TaskList[NumTasks] = TaskList[0]; + TaskList[0] = AppRecPtr->MainTaskId; + } - ++TaskRecPtr; - } /* end for */ + /* Mark record for removal */ + CFE_ES_TaskRecordSetUsed(TaskRecPtr, CFE_ES_RESOURCEID_RESERVED); + ++NumTasks; + } - /* - ** Delete all of the OS resources, close files, and delete the main task - */ - Status = CFE_ES_CleanupTaskResources(MainTaskId); - if ( Status != CFE_SUCCESS ) - { - CFE_ES_SysLogWrite_Unsync("CFE_ES_CleanUpApp: CleanUpTaskResources for Task ID:%lu returned Error: 0x%08X\n", - CFE_ES_ResourceID_ToInteger(MainTaskId), (unsigned int)Status); - ReturnCode = CFE_ES_APP_CLEANUP_ERR; + ++TaskRecPtr; + } /* end for */ - } + CFE_ES_Global.RegisteredTasks -= NumTasks; - /* - ** Remove the app from the AppTable - */ - if ( AppRecPtr->Type == CFE_ES_AppType_EXTERNAL ) - { - /* - ** Unload the module only if it is an external app - */ - Status = OS_ModuleUnload(AppRecPtr->StartParams.ModuleId); - if ( Status == OS_ERROR ) - { - CFE_ES_SysLogWrite_Unsync("CFE_ES_CleanUpApp: Module (ID:0x%08lX) Unload failed. RC=0x%08X\n", - OS_ObjectIdToInteger(AppRecPtr->StartParams.ModuleId), (unsigned int)Status); - ReturnCode = CFE_ES_APP_CLEANUP_ERR; - } - CFE_ES_Global.RegisteredExternalApps--; - } + /* + * Collect memory pools associated with this app + */ + MemPoolRecPtr = CFE_ES_Global.MemPoolTable; + for ( i = 0; i < CFE_PLATFORM_ES_MAX_MEMORY_POOLS; i++ ) + { + if ( CFE_ES_MemPoolRecordIsUsed(MemPoolRecPtr) && + CFE_ES_ResourceID_Equal(MemPoolRecPtr->OwnerAppID, AppId)) + { + PoolList[NumPools] = CFE_ES_MemPoolRecordGetID(MemPoolRecPtr); + ++NumPools; + } - CFE_ES_AppRecordSetFree(AppRecPtr); + ++MemPoolRecPtr; + } /* end for */ - /* - ** Delete any memory pools associated with this app - */ - MemPoolRecPtr = CFE_ES_Global.MemPoolTable; - for ( i = 0; i < CFE_PLATFORM_ES_MAX_MEMORY_POOLS; i++ ) - { - if ( CFE_ES_MemPoolRecordIsUsed(MemPoolRecPtr) && - CFE_ES_ResourceID_Equal(MemPoolRecPtr->OwnerAppID, AppId)) - { - PoolId = CFE_ES_MemPoolRecordGetID(MemPoolRecPtr); + /* + * Set the record to RESERVED. + * + * This prevents reallocation of this slot while the remainder + * of resources are freed. + */ + CFE_ES_AppRecordSetUsed(AppRecPtr, CFE_ES_RESOURCEID_RESERVED); - /* - * This needs to release the lock first because - * CFE_ES_PoolDelete acquires the lock. - */ - CFE_ES_UnlockSharedData(__func__, __LINE__); - Status = CFE_ES_PoolDelete(PoolId); - CFE_ES_LockSharedData(__func__, __LINE__); - - if ( Status != CFE_SUCCESS ) - { - CFE_ES_SysLogWrite_Unsync("CFE_ES_MemPoolCleanupApp: delete pool %lu returned Error: 0x%08X\n", - CFE_ES_ResourceID_ToInteger(PoolId), (unsigned int)Status); - ReturnCode = CFE_ES_APP_CLEANUP_ERR; - } - } + ReturnCode = CFE_SUCCESS; + } + else + { + CFE_ES_SysLogWrite_Unsync("CFE_ES_CleanUpApp: AppID %lu is not valid for deletion\n", + CFE_ES_ResourceID_ToInteger(AppId)); + ReturnCode = CFE_ES_APP_CLEANUP_ERR; + } - ++MemPoolRecPtr; - } /* end for */ + CFE_ES_UnlockSharedData(__func__, __LINE__); + if (ReturnCode != CFE_SUCCESS) + { + return ReturnCode; + } - CFE_ES_UnlockSharedData(__func__,__LINE__); + /* + * Now actually delete all the resources associated with the task. + * + * Most of this involves calling into other subsystems, so it is + * done while the ES global data is UNLOCKED to avoid holding more + * than one lock at a time. + */ - return(ReturnCode); + /* + ** Call the Table Clean up function + */ + CFE_TBL_CleanUpApp(AppId); + + /* + ** Call the Software Bus clean up function + */ + CFE_SB_CleanUpApp(AppId); + + /* + ** Call the TIME Clean up function + */ + CFE_TIME_CleanUpApp(AppId); + + /* + ** Call the EVS Clean up function + */ + Status = CFE_EVS_CleanUpApp(AppId); + if ( Status != CFE_SUCCESS ) + { + CFE_ES_WriteToSysLog("CFE_ES_CleanUpApp: Call to CFE_EVS_CleanUpApp returned Error: 0x%08X\n",(unsigned int)Status); + ReturnCode = CFE_ES_APP_CLEANUP_ERR; + } + + /* + * Delete all tasks. + * + * Note that the main task is always positioned at index 0 in this list. + * + * This iterates the list in reverse order, such that the child + * tasks are deleted first (in any order) and main task is deleted last. + */ + i = NumTasks; + while (i > 0) + { + --i; + Status = CFE_ES_CleanupTaskResources(TaskList[i]); + if ( Status != CFE_SUCCESS ) + { + CFE_ES_WriteToSysLog("CFE_ES_CleanUpApp: CleanUpTaskResources for Task ID:%lu returned Error: 0x%08X\n", + CFE_ES_ResourceID_ToInteger(TaskList[i]), (unsigned int)Status); + ReturnCode = CFE_ES_APP_CLEANUP_ERR; + } + } + + /* + * Delete all mem pools. + */ + for (i=0; i < NumPools; ++i) + { + Status = CFE_ES_PoolDelete(PoolList[i]); + if ( Status != CFE_SUCCESS ) + { + CFE_ES_WriteToSysLog("CFE_ES_MemPoolCleanupApp: delete pool %lu returned Error: 0x%08X\n", + CFE_ES_ResourceID_ToInteger(PoolList[i]), (unsigned int)Status); + ReturnCode = CFE_ES_APP_CLEANUP_ERR; + } + } + + /* + ** Unload the module, if applicable + */ + if ( OS_ObjectIdDefined(ModuleId) ) + { + /* + ** Unload the module only if it is an external app + */ + Status = OS_ModuleUnload(ModuleId); + if ( Status != OS_SUCCESS ) + { + CFE_ES_WriteToSysLog("CFE_ES_CleanUpApp: Module (ID:0x%08lX) Unload failed. RC=0x%08X\n", + OS_ObjectIdToInteger(ModuleId), (unsigned int)Status); + ReturnCode = CFE_ES_APP_CLEANUP_ERR; + } + } + + /* + * Finally, re-acquire the ES lock and set all + * table entries free for re-use. + */ + CFE_ES_LockSharedData(__func__,__LINE__); + +#ifdef jphfix + /* + * This just confirms that the main task ID associated with this app was properly + * located and deleted during the previous process. + * + * If not, display a log message about it - this indicates table corruption or a + * bug with the record keeping. + */ + if (NumTasks == 0 || !CFE_ES_ResourceID_Equal(TaskList[0], AppRecPtr->MainTaskId)) + { + CFE_ES_SysLogWrite_Unsync("CFE_ES_CleanUpApp: MainTask ID:%lu not found when deleting AppID %lu\n", + CFE_ES_ResourceID_ToInteger(AppRecPtr->MainTaskId), CFE_ES_ResourceID_ToInteger(AppId)); + ReturnCode = CFE_ES_APP_CLEANUP_ERR; + } +#endif + + /* + * Free all task records. + */ + for (i=0; i < NumTasks; ++i) + { + TaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskList[i]); + if (CFE_ES_TaskRecordIsMatch(TaskRecPtr, CFE_ES_RESOURCEID_RESERVED)) + { + CFE_ES_TaskRecordSetFree(TaskRecPtr); + } + } + + /* + * Now finally delete the record and allow re-use of the slot. + */ + if (CFE_ES_AppRecordIsMatch(AppRecPtr, CFE_ES_RESOURCEID_RESERVED)) + { + CFE_ES_AppRecordSetFree(AppRecPtr); + } + + CFE_ES_UnlockSharedData(__func__,__LINE__); + + return(ReturnCode); } /* end function */ @@ -1387,13 +1647,14 @@ void CFE_ES_CleanupObjectCallback(osal_id_t ObjectId, void *arg) ** Name: CFE_ES_CleanupTaskResources ** ** Purpose: Clean up the OS resources associated with an individual Task +** Note: This is called when the ES global is UNLOCKED - so it should not touch +** any ES global data structures. It should only clean up at the OSAL level. **--------------------------------------------------------------------------------------- */ int32 CFE_ES_CleanupTaskResources(CFE_ES_ResourceID_t TaskId) { CFE_ES_CleanupState_t CleanState; int32 Result; - CFE_ES_TaskRecord_t *TaskRecPtr; osal_id_t OsalId; /* Get the Task ID for calling OSAL APIs (convert type) */ @@ -1424,16 +1685,15 @@ int32 CFE_ES_CleanupTaskResources(CFE_ES_ResourceID_t TaskId) CleanState.DeletedObjects = 0; } - /* - * Locate the ES Task table entry - */ - TaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskId); - /* ** Delete the task itself + ** + ** Note, if the task self exited, then the ID becomes invalid. + ** In this case the OS_ERR_INVALID_ID status is returned, but + ** that is OK, there is nothing else needed to do. */ Result = OS_TaskDelete(OsalId); - if (Result == OS_SUCCESS) + if (Result == OS_SUCCESS || Result == OS_ERR_INVALID_ID) { Result = CleanState.OverallStatus; if (Result == CFE_SUCCESS && CleanState.FoundObjects > 0) @@ -1447,22 +1707,13 @@ int32 CFE_ES_CleanupTaskResources(CFE_ES_ResourceID_t TaskId) Result = CFE_ES_TASK_DELETE_ERR; } - /* - ** Invalidate ES Task Table entry - */ - if (TaskRecPtr != NULL) - { - CFE_ES_TaskRecordSetFree(TaskRecPtr); - } - - CFE_ES_Global.RegisteredTasks--; return(Result); } /* **--------------------------------------------------------------------------------------- -** Name: CFE_ES_GetAppInfoInternal +** Name: CFE_ES_CopyModuleBasicInfo ** ** Purpose: Populate the cFE_ES_AppInfo structure with the data for an app. ** @@ -1470,181 +1721,71 @@ int32 CFE_ES_CleanupTaskResources(CFE_ES_ResourceID_t TaskId) ** to check the return code and log any relevant errors based on the context. **--------------------------------------------------------------------------------------- */ -int32 CFE_ES_GetAppInfoInternal(CFE_ES_AppRecord_t *AppRecPtr, CFE_ES_AppInfo_t *AppInfoPtr ) +void CFE_ES_CopyModuleBasicInfo(const CFE_ES_ModuleLoadParams_t *ParamsPtr, CFE_ES_AppInfo_t *AppInfoPtr) { - int32 Status; - int32 ReturnCode; - OS_module_prop_t ModuleInfo; - uint32 i; - CFE_ES_TaskRecord_t *TaskRecPtr; - CFE_ES_ResourceID_t AppId; - - CFE_ES_LockSharedData(__func__,__LINE__); - - if ( !CFE_ES_AppRecordIsUsed(AppRecPtr) ) - { - Status = CFE_ES_ERR_RESOURCEID_NOT_VALID; - } - else - { - Status = CFE_SUCCESS; - - AppId = CFE_ES_AppRecordGetID(AppRecPtr); - AppInfoPtr->AppId = AppId; - AppInfoPtr->Type = AppRecPtr->Type; - strncpy(AppInfoPtr->Name, - CFE_ES_AppRecordGetName(AppRecPtr), - sizeof(AppInfoPtr->Name)-1); - AppInfoPtr->Name[sizeof(AppInfoPtr->Name)-1] = '\0'; - - strncpy((char *)AppInfoPtr->EntryPoint, - AppRecPtr->StartParams.EntryPoint, - sizeof(AppInfoPtr->EntryPoint) - 1); - AppInfoPtr->EntryPoint[sizeof(AppInfoPtr->EntryPoint) - 1] = '\0'; - - strncpy((char *)AppInfoPtr->FileName, (char *)AppRecPtr->StartParams.FileName, - sizeof(AppInfoPtr->FileName) - 1); - AppInfoPtr->FileName[sizeof(AppInfoPtr->FileName) - 1] = '\0'; - - AppInfoPtr->ModuleId = AppRecPtr->StartParams.ModuleId; - AppInfoPtr->StackSize = AppRecPtr->StartParams.StackSize; - CFE_SB_SET_MEMADDR(AppInfoPtr->StartAddress, AppRecPtr->StartParams.StartAddress); - AppInfoPtr->ExceptionAction = AppRecPtr->StartParams.ExceptionAction; - AppInfoPtr->Priority = AppRecPtr->StartParams.Priority; - - AppInfoPtr->MainTaskId = AppRecPtr->MainTaskId; - - /* - ** Calculate the number of child tasks - */ - AppInfoPtr->NumOfChildTasks = 0; - TaskRecPtr = CFE_ES_Global.TaskTable; - for (i=0; iAppId, AppId) && - !CFE_ES_ResourceID_Equal(CFE_ES_TaskRecordGetID(TaskRecPtr), AppInfoPtr->MainTaskId) ) - { - AppInfoPtr->NumOfChildTasks++; - } - ++TaskRecPtr; - } - - /* - ** Get the execution counter for the main task - */ - TaskRecPtr = CFE_ES_LocateTaskRecordByID(AppInfoPtr->MainTaskId); - if (CFE_ES_TaskRecordIsMatch(TaskRecPtr,AppInfoPtr->MainTaskId)) - { - AppInfoPtr->ExecutionCounter = TaskRecPtr->ExecutionCounter; - strncpy(AppInfoPtr->MainTaskName, TaskRecPtr->TaskName, - sizeof(AppInfoPtr->MainTaskName) - 1); - AppInfoPtr->MainTaskName[sizeof(AppInfoPtr->MainTaskName) - 1] = '\0'; - } + strncpy(AppInfoPtr->Name, ParamsPtr->Name, + sizeof(AppInfoPtr->Name)-1); + AppInfoPtr->Name[sizeof(AppInfoPtr->Name)-1] = '\0'; - /* - ** Get the address information from the OSAL - */ - ReturnCode = OS_ModuleInfo ( AppInfoPtr->ModuleId, &ModuleInfo ); - if ( ReturnCode == OS_SUCCESS ) - { - AppInfoPtr->AddressesAreValid = - (sizeof(ModuleInfo.addr.code_address) <= sizeof(AppInfoPtr->CodeAddress)) && - ModuleInfo.addr.valid; - CFE_SB_SET_MEMADDR(AppInfoPtr->CodeAddress, ModuleInfo.addr.code_address); - CFE_SB_SET_MEMADDR(AppInfoPtr->CodeSize, ModuleInfo.addr.code_size); - CFE_SB_SET_MEMADDR(AppInfoPtr->DataAddress, ModuleInfo.addr.data_address); - CFE_SB_SET_MEMADDR(AppInfoPtr->DataSize, ModuleInfo.addr.data_size); - CFE_SB_SET_MEMADDR(AppInfoPtr->BSSAddress, ModuleInfo.addr.bss_address); - CFE_SB_SET_MEMADDR(AppInfoPtr->BSSSize, ModuleInfo.addr.bss_size); - } - else - { - AppInfoPtr->AddressesAreValid = false; - AppInfoPtr->CodeAddress = 0; - AppInfoPtr->CodeSize = 0; - AppInfoPtr->DataAddress = 0; - AppInfoPtr->DataSize = 0; - AppInfoPtr->BSSAddress = 0; - AppInfoPtr->BSSSize = 0; - } - - } + strncpy(AppInfoPtr->EntryPoint, ParamsPtr->EntryPoint, + sizeof(AppInfoPtr->EntryPoint) - 1); + AppInfoPtr->EntryPoint[sizeof(AppInfoPtr->EntryPoint) - 1] = '\0'; - CFE_ES_UnlockSharedData(__func__,__LINE__); - - return Status; - -} /* end function */ + strncpy(AppInfoPtr->FileName, ParamsPtr->FileName, + sizeof(AppInfoPtr->FileName) - 1); + AppInfoPtr->FileName[sizeof(AppInfoPtr->FileName) - 1] = '\0'; +} /* **--------------------------------------------------------------------------------------- -** Name: CFE_ES_GetAppInfoInternal +** Name: CFE_ES_CopyModuleStatusInfo ** -** Purpose: Populate the cFE_ES_TaskInfo structure with the data for a task. +** Purpose: Populate the cFE_ES_AppInfo structure with the data for an app. ** ** This internal function does not log any errors/events. The caller is expected ** to check the return code and log any relevant errors based on the context. **--------------------------------------------------------------------------------------- */ -int32 CFE_ES_GetTaskInfoInternal(CFE_ES_TaskRecord_t *TaskRecPtr, CFE_ES_TaskInfo_t *TaskInfoPtr) +void CFE_ES_CopyModuleStatusInfo(const CFE_ES_ModuleLoadStatus_t *StatusPtr, CFE_ES_AppInfo_t *AppInfoPtr) { - CFE_ES_AppRecord_t *AppRecPtr; - int32 ReturnCode; - - CFE_ES_LockSharedData(__func__,__LINE__); - - if ( CFE_ES_TaskRecordIsUsed(TaskRecPtr) ) - { - - /* - ** Get the Application ID and Task Name - */ - TaskInfoPtr->AppId = TaskRecPtr->AppId; - strncpy(TaskInfoPtr->TaskName, - CFE_ES_TaskRecordGetName(TaskRecPtr), - sizeof(TaskInfoPtr->TaskName)-1); - TaskInfoPtr->TaskName[sizeof(TaskInfoPtr->TaskName)-1] = '\0'; - - /* - ** Store away the Task ID ( for the QueryAllTasks Cmd ) - */ - TaskInfoPtr->TaskId = CFE_ES_TaskRecordGetID(TaskRecPtr); - - /* - ** Get the Execution counter for the task - */ - TaskInfoPtr->ExecutionCounter = TaskRecPtr->ExecutionCounter; - - /* - ** Get the Application Details - */ - AppRecPtr = CFE_ES_LocateAppRecordByID(TaskRecPtr->AppId); - if (CFE_ES_AppRecordIsMatch(AppRecPtr, TaskRecPtr->AppId)) - { - strncpy(TaskInfoPtr->AppName, - CFE_ES_AppRecordGetName(AppRecPtr), - sizeof(TaskInfoPtr->AppName)-1); - TaskInfoPtr->AppName[sizeof(TaskInfoPtr->AppName)-1] = '\0'; - ReturnCode = CFE_SUCCESS; - } - else - { - /* task ID was OK but parent app ID is bad */ - ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID; - } - } - else - { - /* task ID is bad */ - ReturnCode = CFE_ES_ERR_RESOURCEID_NOT_VALID; - } - - CFE_ES_UnlockSharedData(__func__,__LINE__); + AppInfoPtr->ModuleId = StatusPtr->ModuleId; + CFE_SB_SET_MEMADDR(AppInfoPtr->StartAddress, StatusPtr->EntryAddress); +} - return(ReturnCode); +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_CopyModuleAddressInfo +** +** Purpose: Populate the cFE_ES_AppInfo structure with the data for an app. +** +** This internal function does not log any errors/events. The caller is expected +** to check the return code and log any relevant errors based on the context. +**--------------------------------------------------------------------------------------- +*/ +void CFE_ES_CopyModuleAddressInfo(osal_id_t ModuleId, CFE_ES_AppInfo_t *AppInfoPtr) +{ + OS_module_prop_t ModuleInfo; + int32 ReturnCode; -} /* End of CFE_ES_GetTaskInfoInternal() */ + ReturnCode = OS_ModuleInfo ( ModuleId, &ModuleInfo ); + if ( ReturnCode == OS_SUCCESS ) + { + AppInfoPtr->AddressesAreValid = + (sizeof(ModuleInfo.addr.code_address) <= sizeof(AppInfoPtr->CodeAddress)) && + ModuleInfo.addr.valid; + } + else + { + AppInfoPtr->AddressesAreValid = false; + memset(&ModuleInfo, 0, sizeof(ModuleInfo)); + } + CFE_SB_SET_MEMADDR(AppInfoPtr->CodeAddress, ModuleInfo.addr.code_address); + CFE_SB_SET_MEMADDR(AppInfoPtr->CodeSize, ModuleInfo.addr.code_size); + CFE_SB_SET_MEMADDR(AppInfoPtr->DataAddress, ModuleInfo.addr.data_address); + CFE_SB_SET_MEMADDR(AppInfoPtr->DataSize, ModuleInfo.addr.data_size); + CFE_SB_SET_MEMADDR(AppInfoPtr->BSSAddress, ModuleInfo.addr.bss_address); + CFE_SB_SET_MEMADDR(AppInfoPtr->BSSSize, ModuleInfo.addr.bss_size); +} diff --git a/fsw/cfe-core/src/es/cfe_es_apps.h b/fsw/cfe-core/src/es/cfe_es_apps.h index fa29774b4..e9aaa7562 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.h +++ b/fsw/cfe-core/src/es/cfe_es_apps.h @@ -65,21 +65,61 @@ typedef struct /* -** CFE_ES_AppStartParams_t is a structure of information used when an application is -** created in the system. It is stored in the cFE ES App Table +** CFE_ES_ModuleLoadParams_t contains the information used when a module +** (library or app) load request initially processed in the system. It captures +** the fundamental information - the name, the file to load, its entry point. +** It contains information directly provided by the user, not runtime status or +** other derived information. +** +** This information should remain fairly constant after initial allocation, even +** if the application is restarted for some reason. The major exception is the +** ReloadApp command, which can change the FileName. +*/ +typedef struct +{ + char Name[OS_MAX_API_NAME]; + char EntryPoint[OS_MAX_API_NAME]; + char FileName[OS_MAX_PATH_LEN]; + +} CFE_ES_ModuleLoadParams_t; + +/* +** CFE_ES_ModuleLoadStatus_t is a structure of information used when a module +** (library or app) is actually loaded in the system. It captures the +** runtime information - the module ID and starting address. +** +** This information may change if the module is reloaded. */ typedef struct { - char Name[OS_MAX_API_NAME]; - char EntryPoint[OS_MAX_API_NAME]; - char FileName[OS_MAX_PATH_LEN]; + cpuaddr EntryAddress; + osal_id_t ModuleId; + +} CFE_ES_ModuleLoadStatus_t; - uint32 StackSize; - cpuaddr StartAddress; - osal_id_t ModuleId; - uint16 ExceptionAction; - uint16 Priority; + +/* +** CFE_ES_AppStartParams_t is a structure of information used when an application is +** created in the system. +** +** This is an extension of the CFE_ES_ModuleLoadParams_t which adds information +** about the task stack size and priority. It is only used for apps, as libraries +** do not have a task associated. +*/ +typedef struct +{ + /* + * Basic (static) information about the module + */ + CFE_ES_ModuleLoadParams_t BasicInfo; + + /* + * Extra information the pertains to applications only, not libraries. + */ + cpusize StackSize; + uint16 Priority; + CFE_ES_ExceptionAction_Enum_t ExceptionAction; } CFE_ES_AppStartParams_t; @@ -89,12 +129,13 @@ typedef struct */ typedef struct { - CFE_ES_ResourceID_t AppId; /* The actual AppID of this entry, or undefined */ - CFE_ES_AppState_Enum_t AppState; /* Is the app running, or stopped, or waiting? */ - uint32 Type; /* The type of App: CORE or EXTERNAL */ - CFE_ES_AppStartParams_t StartParams; /* The start parameters for an App */ - CFE_ES_ControlReq_t ControlReq; /* The Control Request Record for External cFE Apps */ - CFE_ES_ResourceID_t MainTaskId; /* The Application's Main Task ID */ + CFE_ES_ResourceID_t AppId; /* The actual AppID of this entry, or undefined */ + CFE_ES_AppState_Enum_t AppState; /* Is the app running, or stopped, or waiting? */ + CFE_ES_AppType_Enum_t Type; /* The type of App: CORE or EXTERNAL */ + CFE_ES_AppStartParams_t StartParams; /* The start parameters for an App */ + CFE_ES_ModuleLoadStatus_t ModuleInfo; /* Runtime module information */ + CFE_ES_ControlReq_t ControlReq; /* The Control Request Record for External cFE Apps */ + CFE_ES_ResourceID_t MainTaskId; /* The Application's Main Task ID */ } CFE_ES_AppRecord_t; @@ -119,8 +160,9 @@ typedef struct */ typedef struct { - CFE_ES_ResourceID_t LibId; /* The actual LibID of this entry, or undefined */ - char LibName[OS_MAX_API_NAME]; /* Library Name */ + CFE_ES_ResourceID_t LibId; /* The actual LibID of this entry, or undefined */ + CFE_ES_ModuleLoadParams_t BasicInfo; /* Basic (static) information about the module */ + CFE_ES_ModuleLoadStatus_t ModuleInfo; /* Runtime information about the module */ } CFE_ES_LibRecord_t; /* @@ -151,13 +193,39 @@ void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath ); */ int32 CFE_ES_ParseFileEntry(const char **TokenList, uint32 NumTokens); +/* +** Internal function to load a module (app or library) +** This only loads the code and looks up relevent runtime information. +** It does not start any tasks. +*/ +int32 CFE_ES_LoadModule(const CFE_ES_ModuleLoadParams_t* LoadParams, CFE_ES_ModuleLoadStatus_t *LoadStatus); + +/* +** Internal function to determine the entry point of an app. +** If the app isn't fully registered in the global app table, +** then this delays until the app is completely configured and the entry point is +** confirmed to be valid. +*/ +int32 CFE_ES_GetAppEntryPoint(osal_task_entry *FuncPtr); + +/* +** Intermediate entry point of an app. Determines the actual +** entry point from the global data structures. +*/ +void CFE_ES_AppEntryPoint(void); + +/* +** Internal function to start the main task of an app. +*/ +int32 CFE_ES_StartAppTask(const CFE_ES_AppStartParams_t* StartParams, CFE_ES_ResourceID_t RefAppId, CFE_ES_ResourceID_t *TaskIdPtr); + /* ** Internal function to create/start a new cFE app ** based on the parameters passed in */ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, const char *FileName, - const void *EntryPointData, + const char *EntryPointName, const char *AppName, uint32 Priority, uint32 StackSize, @@ -167,7 +235,7 @@ int32 CFE_ES_AppCreate(CFE_ES_ResourceID_t *ApplicationIdPtr, */ int32 CFE_ES_LoadLibrary(CFE_ES_ResourceID_t *LibraryIdPtr, const char *FileName, - const void *EntryPointData, + const char *EntryPointName, const char *LibName); /* @@ -199,30 +267,45 @@ bool CFE_ES_RunERLogDump(uint32 ElapsedTime, void *Arg); /* ** Perform the requested control action for an application */ -void CFE_ES_ProcessControlRequest(CFE_ES_AppRecord_t *AppRecPtr); +void CFE_ES_ProcessControlRequest(CFE_ES_ResourceID_t AppId); /* ** Clean up all app resources and delete it */ -int32 CFE_ES_CleanUpApp(CFE_ES_AppRecord_t *AppRecPtr); +int32 CFE_ES_CleanUpApp(CFE_ES_ResourceID_t AppId); /* ** Clean up all Task resources and detete the task */ int32 CFE_ES_CleanupTaskResources(CFE_ES_ResourceID_t TaskId); + /* -** Populate the cFE_ES_AppInfo structure with the data for an app -** This is an internal function for use in ES. -** The newer external API is : CFE_ES_GetAppInfo +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_CopyModuleBasicInfo +** +** Purpose: Populate the cFE_ES_AppInfo structure from the CFE_ES_ModuleLoadParams_t data +**--------------------------------------------------------------------------------------- */ -int32 CFE_ES_GetAppInfoInternal(CFE_ES_AppRecord_t *AppRecPtr, CFE_ES_AppInfo_t *AppInfoPtr ); +void CFE_ES_CopyModuleBasicInfo(const CFE_ES_ModuleLoadParams_t *ParamsPtr, CFE_ES_AppInfo_t *AppInfoPtr); /* - * Populate the CFE_ES_TaskInfo_t structure with the data for a task - * This is an internal function for use in ES. - * (Equivalent pattern to CFE_ES_GetAppInfoInternal() but for tasks) - */ -int32 CFE_ES_GetTaskInfoInternal(CFE_ES_TaskRecord_t *TaskRecPtr, CFE_ES_TaskInfo_t *TaskInfoPtr ); +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_CopyModuleStatusInfo +** +** Purpose: Populate the cFE_ES_AppInfo structure from the CFE_ES_ModuleLoadStatus_t data +**--------------------------------------------------------------------------------------- +*/ +void CFE_ES_CopyModuleStatusInfo(const CFE_ES_ModuleLoadStatus_t *StatusPtr, CFE_ES_AppInfo_t *AppInfoPtr); + +/* +**--------------------------------------------------------------------------------------- +** Name: CFE_ES_CopyModuleAddressInfo +** +** Purpose: Populate the cFE_ES_AppInfo structure with address information from OSAL. +**--------------------------------------------------------------------------------------- +*/ +void CFE_ES_CopyModuleAddressInfo(osal_id_t ModuleId, CFE_ES_AppInfo_t *AppInfoPtr); + #endif /* _cfe_es_apps_ */ diff --git a/fsw/cfe-core/src/es/cfe_es_resource.h b/fsw/cfe-core/src/es/cfe_es_resource.h index 9ca10533f..82c936cd3 100644 --- a/fsw/cfe-core/src/es/cfe_es_resource.h +++ b/fsw/cfe-core/src/es/cfe_es_resource.h @@ -214,7 +214,7 @@ static inline bool CFE_ES_AppRecordIsMatch(const CFE_ES_AppRecord_t *AppRecPtr, */ static inline const char* CFE_ES_AppRecordGetName(const CFE_ES_AppRecord_t *AppRecPtr) { - return AppRecPtr->StartParams.Name; + return AppRecPtr->StartParams.BasicInfo.Name; } @@ -307,7 +307,7 @@ static inline bool CFE_ES_LibRecordIsMatch(const CFE_ES_LibRecord_t *LibRecPtr, */ static inline const char* CFE_ES_LibRecordGetName(const CFE_ES_LibRecord_t *LibRecPtr) { - return LibRecPtr->LibName; + return LibRecPtr->BasicInfo.Name; } diff --git a/fsw/cfe-core/src/es/cfe_es_start.c b/fsw/cfe-core/src/es/cfe_es_start.c index 9f8c8eb66..2a883ef13 100644 --- a/fsw/cfe-core/src/es/cfe_es_start.c +++ b/fsw/cfe-core/src/es/cfe_es_start.c @@ -753,10 +753,9 @@ void CFE_ES_CreateObjects(void) { int32 ReturnCode; uint16 i; - osal_id_t OsalId; CFE_ES_AppRecord_t *AppRecPtr; - CFE_ES_TaskRecord_t *TaskRecPtr; CFE_ES_ResourceID_t PendingAppId; + CFE_ES_ResourceID_t PendingTaskId; CFE_ES_WriteToSysLog("ES Startup: Starting Object Creation calls.\n"); @@ -776,7 +775,27 @@ void CFE_ES_CreateObjects(void) AppRecPtr = CFE_ES_LocateAppRecordByID(PendingAppId); if (AppRecPtr != NULL) { + /* + ** Fill out the parameters in the AppStartParams sub-structure + */ + AppRecPtr->Type = CFE_ES_AppType_CORE; + strncpy(AppRecPtr->StartParams.BasicInfo.Name, CFE_ES_ObjectTable[i].ObjectName, + sizeof(AppRecPtr->StartParams.BasicInfo.Name)-1); + + /* FileName and EntryPoint is not valid for core apps */ + AppRecPtr->StartParams.StackSize = CFE_ES_ObjectTable[i].ObjectSize; + AppRecPtr->StartParams.ExceptionAction = CFE_ES_ExceptionAction_PROC_RESTART; + AppRecPtr->StartParams.Priority = CFE_ES_ObjectTable[i].ObjectPriority; + AppRecPtr->ModuleInfo.EntryAddress = (cpuaddr)CFE_ES_ObjectTable[i].FuncPtrUnion.VoidPtr; + + /* + ** Fill out the Task State info + */ + AppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; + AppRecPtr->ControlReq.AppTimerMsec = 0; + CFE_ES_AppRecordSetUsed(AppRecPtr, CFE_ES_RESOURCEID_RESERVED); + CFE_ES_Global.LastAppId = PendingAppId; } CFE_ES_UnlockSharedData(__func__,__LINE__); @@ -786,111 +805,60 @@ void CFE_ES_CreateObjects(void) */ if (AppRecPtr != NULL) { - - CFE_ES_LockSharedData(__func__,__LINE__); - - AppRecPtr->Type = CFE_ES_AppType_CORE; - - /* - ** Fill out the parameters in the AppStartParams sub-structure - */ - strncpy((char *)AppRecPtr->StartParams.Name, (char *)CFE_ES_ObjectTable[i].ObjectName, OS_MAX_API_NAME); - AppRecPtr->StartParams.Name[OS_MAX_API_NAME - 1] = '\0'; - /* EntryPoint field is not valid here for base apps */ - /* FileName is not valid for base apps, either */ - AppRecPtr->StartParams.StackSize = CFE_ES_ObjectTable[i].ObjectSize; - AppRecPtr->StartParams.StartAddress = (cpuaddr)CFE_ES_ObjectTable[i].FuncPtrUnion.VoidPtr; - AppRecPtr->StartParams.ExceptionAction = CFE_ES_ExceptionAction_PROC_RESTART; - AppRecPtr->StartParams.Priority = CFE_ES_ObjectTable[i].ObjectPriority; - - - /* - ** Create the task - */ - ReturnCode = OS_TaskCreate(&OsalId, /* task id */ - CFE_ES_ObjectTable[i].ObjectName, /* task name */ - CFE_ES_ObjectTable[i].FuncPtrUnion.MainAppPtr, /* task function pointer */ - NULL, /* stack pointer */ - CFE_ES_ObjectTable[i].ObjectSize, /* stack size */ - CFE_ES_ObjectTable[i].ObjectPriority, /* task priority */ - OS_FP_ENABLED); /* task options */ - - if(ReturnCode != OS_SUCCESS) - { - CFE_ES_AppRecordSetFree(AppRecPtr); - CFE_ES_UnlockSharedData(__func__,__LINE__); - - CFE_ES_WriteToSysLog("ES Startup: OS_TaskCreate error creating core App: %s: EC = 0x%08X\n", - CFE_ES_ObjectTable[i].ObjectName, (unsigned int)ReturnCode); - - /* - ** Delay to allow the message to be read - */ - OS_TaskDelay(CFE_ES_PANIC_DELAY); - - /* - ** cFE Cannot continue to start up. - */ - CFE_PSP_Panic(CFE_PSP_PANIC_CORE_APP); - - } - else - { - AppRecPtr->MainTaskId = CFE_ES_ResourceID_FromOSAL(OsalId); - TaskRecPtr = CFE_ES_LocateTaskRecordByID(AppRecPtr->MainTaskId); - - /* - ** Allocate and populate the CFE_ES_Global.TaskTable entry - */ - if ( CFE_ES_TaskRecordIsUsed(TaskRecPtr) ) - { - CFE_ES_SysLogWrite_Unsync("ES Startup: CFE_ES_Global.TaskTable record used error for App: %s, continuing.\n", - CFE_ES_ObjectTable[i].ObjectName); - } - CFE_ES_TaskRecordSetUsed(TaskRecPtr, AppRecPtr->MainTaskId); - TaskRecPtr->AppId = PendingAppId; - strncpy(TaskRecPtr->TaskName, CFE_ES_ObjectTable[i].ObjectName, sizeof(TaskRecPtr->TaskName)-1); - TaskRecPtr->TaskName[sizeof(TaskRecPtr->TaskName)-1] = '\0'; - - CFE_ES_SysLogWrite_Unsync("ES Startup: Core App: %s created. App ID: %lu\n", - CFE_ES_ObjectTable[i].ObjectName, - CFE_ES_ResourceID_ToInteger(PendingAppId)); + /* + ** Start the core app main task + ** (core apps are already in memory - no loading needed) + */ + ReturnCode = CFE_ES_StartAppTask(&AppRecPtr->StartParams, PendingAppId, &PendingTaskId); - CFE_ES_AppRecordSetUsed(AppRecPtr, PendingAppId); - - /* - ** Increment the registered App and Registered External Task variables. - */ - CFE_ES_Global.RegisteredTasks++; - CFE_ES_Global.RegisteredCoreApps++; - - CFE_ES_UnlockSharedData(__func__,__LINE__); - - } + /* + * Finalize data in the app table entry, which must be done under lock. + * This transitions the entry from being RESERVED to the real type, + * either MAIN_TASK (success) or returning to INVALID (failure). + */ + CFE_ES_LockSharedData(__func__,__LINE__); + + if ( ReturnCode == OS_SUCCESS ) + { + AppRecPtr->MainTaskId = PendingTaskId; + CFE_ES_AppRecordSetUsed(AppRecPtr, PendingAppId); + + /* + ** Increment the Core App counter. + */ + CFE_ES_Global.RegisteredCoreApps++; + ReturnCode = CFE_SUCCESS; + } + else + { + /* failure mode - just clear the whole app table entry. + * This will set the AppType back to CFE_ES_ResourceType_INVALID (0), + * as well as clearing any other data that had been written */ + memset(AppRecPtr, 0, sizeof(*AppRecPtr)); + } + + CFE_ES_UnlockSharedData(__func__,__LINE__); } - else /* appSlot not found -- This should never happen!*/ + else { - CFE_ES_WriteToSysLog("ES Startup: Error, No free application slots available for CORE App!\n"); - /* - ** Delay to allow the message to be read - */ - OS_TaskDelay(CFE_ES_PANIC_DELAY); - - /* - ** cFE Cannot continue to start up. - */ - CFE_PSP_Panic(CFE_PSP_PANIC_CORE_APP); - + /* appSlot not found -- This should never happen!*/ + CFE_ES_WriteToSysLog("ES Startup: Error, No free application slots available for CORE App!\n"); + ReturnCode = CFE_ES_ERR_APP_CREATE; } - /* - * CFE_ES_MainTaskSyncDelay() will delay this thread until the - * newly-started thread calls CFE_ES_WaitForSystemState() - */ - if (CFE_ES_MainTaskSyncDelay(CFE_ES_AppState_RUNNING, CFE_PLATFORM_CORE_MAX_STARTUP_MSEC) != CFE_SUCCESS) + if ( ReturnCode == CFE_SUCCESS ) + { + /* + * CFE_ES_MainTaskSyncDelay() will delay this thread until the + * newly-started thread calls CFE_ES_WaitForSystemState() + */ + ReturnCode = CFE_ES_MainTaskSyncDelay(CFE_ES_AppState_RUNNING, CFE_PLATFORM_CORE_MAX_STARTUP_MSEC*1000); + } + + if ( ReturnCode != CFE_SUCCESS ) { - CFE_ES_WriteToSysLog("ES Startup: Core App %s did not complete initialization\n", - CFE_ES_ObjectTable[i].ObjectName); + CFE_ES_WriteToSysLog("ES Startup: OS_TaskCreate error creating core App: %s: EC = 0x%08X\n", + CFE_ES_ObjectTable[i].ObjectName, (unsigned int)ReturnCode); /* ** Delay to allow the message to be read diff --git a/fsw/cfe-core/src/es/cfe_es_task.c b/fsw/cfe-core/src/es/cfe_es_task.c index 3540b3f2a..8411d3ac7 100644 --- a/fsw/cfe-core/src/es/cfe_es_task.c +++ b/fsw/cfe-core/src/es/cfe_es_task.c @@ -41,6 +41,7 @@ #include "cfe_version.h" #include "cfe_es_global.h" #include "cfe_es_apps.h" +#include "cfe_es_resource.h" #include "cfe_es_events.h" #include "cfe_es_verify.h" #include "cfe_es_task.h" @@ -1118,16 +1119,21 @@ int32 CFE_ES_QueryOneCmd(const CFE_ES_QueryOne_t *data) { const CFE_ES_AppNameCmd_Payload_t *cmd = &data->Payload; char LocalApp[OS_MAX_API_NAME]; - CFE_ES_ResourceID_t AppID; + CFE_ES_ResourceID_t ResourceID; int32 Result; CFE_SB_MessageStringGet(LocalApp, (char *)cmd->Application, NULL, OS_MAX_API_NAME, sizeof(cmd->Application)); - Result = CFE_ES_GetAppIDByName(&AppID, LocalApp); + Result = CFE_ES_GetAppIDByName(&ResourceID, LocalApp); + if (Result == CFE_ES_ERR_NAME_NOT_FOUND) + { + /* Also check for a matching library name */ + Result = CFE_ES_GetLibIDByName(&ResourceID, LocalApp); + } if (Result == CFE_SUCCESS) { - Result = CFE_ES_GetAppInfo(&(CFE_ES_TaskData.OneAppPacket.Payload.AppInfo), AppID); + Result = CFE_ES_GetModuleInfo(&(CFE_ES_TaskData.OneAppPacket.Payload.AppInfo), ResourceID); } /* @@ -1182,7 +1188,10 @@ int32 CFE_ES_QueryAllCmd(const CFE_ES_QueryAll_t *data) CFE_ES_AppInfo_t AppInfo; const CFE_ES_FileNameCmd_Payload_t *CmdPtr = &data->Payload; char QueryAllFilename[OS_MAX_PATH_LEN]; + CFE_ES_ResourceID_t ResourceList[CFE_ES_QUERY_ALL_MAX_ENTRIES]; + uint32 NumResources; CFE_ES_AppRecord_t *AppRecPtr; + CFE_ES_LibRecord_t *LibRecPtr; /* ** Copy the commanded filename into local buffer to ensure size limitation and to allow for modification @@ -1190,6 +1199,38 @@ int32 CFE_ES_QueryAllCmd(const CFE_ES_QueryAll_t *data) CFE_SB_MessageStringGet(QueryAllFilename, (char *)CmdPtr->FileName, CFE_PLATFORM_ES_DEFAULT_APP_LOG_FILE, OS_MAX_PATH_LEN, sizeof(CmdPtr->FileName)); + /* + * Collect list of active resource IDs. + * + * This should be done while locked, but the actual writing + * of the AppInfo data should be done while NOT locked. + */ + CFE_ES_LockSharedData(__func__, __LINE__); + NumResources = 0; + AppRecPtr = CFE_ES_Global.AppTable; + for(i=0; i < CFE_PLATFORM_ES_MAX_APPLICATIONS && + NumResources < CFE_ES_QUERY_ALL_MAX_ENTRIES; ++i) + { + if (CFE_ES_AppRecordIsUsed(AppRecPtr)) + { + ResourceList[NumResources] = CFE_ES_AppRecordGetID(AppRecPtr); + ++NumResources; + } + ++AppRecPtr; + } + LibRecPtr = CFE_ES_Global.LibTable; + for(i=0; i < CFE_PLATFORM_ES_MAX_LIBRARIES && + NumResources < CFE_ES_QUERY_ALL_MAX_ENTRIES; ++i) + { + if (CFE_ES_LibRecordIsUsed(LibRecPtr)) + { + ResourceList[NumResources] = CFE_ES_LibRecordGetID(LibRecPtr); + ++NumResources; + } + ++LibRecPtr; + } + CFE_ES_UnlockSharedData(__func__, __LINE__); + /* ** Check to see if the file already exists */ @@ -1240,21 +1281,13 @@ int32 CFE_ES_QueryAllCmd(const CFE_ES_QueryAll_t *data) /* ** Loop through the ES AppTable for main applications */ - AppRecPtr = CFE_ES_Global.AppTable; - for(i=0;iPayload; char QueryAllFilename[OS_MAX_PATH_LEN]; + CFE_ES_ResourceID_t TaskList[OS_MAX_TASKS]; + uint32 NumTasks; CFE_ES_TaskRecord_t *TaskRecPtr; + /* ** Copy the commanded filename into local buffer to ensure size limitation and to allow for modification */ CFE_SB_MessageStringGet(QueryAllFilename, (char *)CmdPtr->FileName, CFE_PLATFORM_ES_DEFAULT_TASK_LOG_FILE, OS_MAX_PATH_LEN, sizeof(CmdPtr->FileName)); + /* + * Collect list of active task IDs. + * + * This should be done while locked, but the actual writing + * of the AppInfo data should be done while NOT locked. + */ + CFE_ES_LockSharedData(__func__, __LINE__); + NumTasks = 0; + TaskRecPtr = CFE_ES_Global.TaskTable; + for(i=0; i < OS_MAX_TASKS; ++i) + { + if (CFE_ES_TaskRecordIsUsed(TaskRecPtr)) + { + TaskList[NumTasks] = CFE_ES_TaskRecordGetID(TaskRecPtr); + ++NumTasks; + } + ++TaskRecPtr; + } + CFE_ES_UnlockSharedData(__func__, __LINE__); + /* ** Check to see if the file already exists */ @@ -1371,20 +1427,13 @@ int32 CFE_ES_QueryAllTasksCmd(const CFE_ES_QueryAllTasks_t *data) /* ** Loop through the ES AppTable for main applications */ - TaskRecPtr = CFE_ES_Global.TaskTable; - for(i=0;i 'Restart Application \%s Completed.' -** \event 'Restart Application \%s Completed.' +/** \brief 'Restart Application \%s Completed, AppID=%lu' +** \event 'Restart Application \%s Completed, AppID=%lu' ** ** \par Type: INFORMATION ** @@ -178,7 +178,8 @@ ** That was started when the \link #CFE_ES_RESTART_APP_CC Restart Application command \endlink ** was issued. ** -** The \c 's' field identifies the name of the Application that was reloaded. +** The \c 's' field identifies the name of the Application that was restarted, and +** the %lu field identifies the new Application ID */ #define CFE_ES_RESTART_APP_INF_EID 10 @@ -202,8 +203,8 @@ #define CFE_ES_RELOAD_APP_DBG_EID 11 -/** \brief 'Reload Application \%s Completed.' -** \event 'Reload Application \%s Completed.' +/** \brief 'Reload Application \%s Completed, AppID=%lu' +** \event 'Reload Application \%s Completed, AppID=%lu' ** ** \par Type: INFORMATION ** @@ -213,7 +214,8 @@ ** That was started when the \link #CFE_ES_RELOAD_APP_CC Restart Application command \endlink ** was issued. ** -** The \c 's' field identifies the name of the Application that was reloaded. +** The \c 's' field identifies the name of the Application that was reloaded, and +** the %lu field identifies the new Application ID */ #define CFE_ES_RELOAD_APP_INF_EID 12 diff --git a/fsw/cfe-core/src/inc/cfe_es_extern_typedefs.h b/fsw/cfe-core/src/inc/cfe_es_extern_typedefs.h index 2a5ce3f28..47456a0dc 100644 --- a/fsw/cfe-core/src/inc/cfe_es_extern_typedefs.h +++ b/fsw/cfe-core/src/inc/cfe_es_extern_typedefs.h @@ -99,7 +99,12 @@ enum CFE_ES_AppType /** * @brief CFE external application */ - CFE_ES_AppType_EXTERNAL = 2 + CFE_ES_AppType_EXTERNAL = 2, + + /** + * @brief CFE library + */ + CFE_ES_AppType_LIBRARY = 3 }; /** diff --git a/fsw/cfe-core/src/inc/cfe_sb_events.h b/fsw/cfe-core/src/inc/cfe_sb_events.h index 9144d852e..c99e55eed 100644 --- a/fsw/cfe-core/src/inc/cfe_sb_events.h +++ b/fsw/cfe-core/src/inc/cfe_sb_events.h @@ -497,6 +497,21 @@ **/ #define CFE_SB_SUBSCRIPTION_RPT_EID 22 +/** \brief 'Msg hash collision: MsgId = 0x\%x, collisions = \%u' +** \event 'Msg hash collision: MsgId = 0x\%x, collisions = \%u' +** +** \par Type: DEBUG +** +** \par Cause: +** +** This event message is generated when a message id hash collision occurs when subscribing +** to a message. Collisions indicate how many slots were incremented to find an opening. +** +** Number of collisions will directly impact software bus performance. These can be resolved +** by adjusting MsgId values or increasing CFE_PLATFORM_SB_MAX_MSG_IDS. +**/ +#define CFE_SB_HASHCOLLISION_EID 23 + /** \brief 'Pipe Overflow,MsgId 0x\%x,pipe \%s,stat 0x\%x,app \%s' ** \event 'Pipe Overflow,MsgId 0x\%x,pipe \%s,stat 0x\%x,app \%s' ** diff --git a/fsw/cfe-core/src/inc/cfe_sb_extern_typedefs.h b/fsw/cfe-core/src/inc/cfe_sb_extern_typedefs.h index 810355005..8eaea63e7 100644 --- a/fsw/cfe-core/src/inc/cfe_sb_extern_typedefs.h +++ b/fsw/cfe-core/src/inc/cfe_sb_extern_typedefs.h @@ -88,7 +88,7 @@ typedef uint8 CFE_SB_QosReliability_E /** * @brief An integer type that should be used for indexing into the Routing Table */ -typedef uint16 CFE_SB_MsgRouteIdx_Atom_t; +typedef uint16 CFE_SB_RouteId_Atom_t; /** * @brief CFE_SB_MsgId_Atom_t primitive type definition diff --git a/fsw/cfe-core/src/inc/cfe_sb_msg.h b/fsw/cfe-core/src/inc/cfe_sb_msg.h index f8ad212bc..03407b0c9 100644 --- a/fsw/cfe-core/src/inc/cfe_sb_msg.h +++ b/fsw/cfe-core/src/inc/cfe_sb_msg.h @@ -683,8 +683,8 @@ typedef struct CFE_SB_RoutingFileEntry { ** Structure of one element of the map information in response to #CFE_SB_SEND_MAP_INFO_CC */ typedef struct CFE_SB_MsgMapFileEntry { - CFE_SB_MsgId_t MsgId;/**< \brief Message Id which has been subscribed to */ - CFE_SB_MsgRouteIdx_Atom_t Index;/**< \brief Routing table index where pipe destinations are found */ + CFE_SB_MsgId_t MsgId;/**< \brief Message Id which has been subscribed to */ + CFE_SB_RouteId_Atom_t Index;/**< \brief Routing raw index value (0 based, not Route ID) */ }CFE_SB_MsgMapFileEntry_t; diff --git a/fsw/cfe-core/src/inc/cfe_version.h b/fsw/cfe-core/src/inc/cfe_version.h index 64bb3c4a1..ceec43e8e 100644 --- a/fsw/cfe-core/src/inc/cfe_version.h +++ b/fsw/cfe-core/src/inc/cfe_version.h @@ -35,7 +35,7 @@ /* Development Build Macro Definitions */ -#define CFE_BUILD_NUMBER 139 /*!< Development Build: Number of commits since baseline */ +#define CFE_BUILD_NUMBER 150 /*!< Development Build: Number of commits since baseline */ #define CFE_BUILD_BASELINE "v6.8.0-rc1" /*!< Development Build: git tag that is the base for the current development */ /* Version Macro Definitions */ diff --git a/fsw/cfe-core/src/inc/private/cfe_sb_destination_typedef.h b/fsw/cfe-core/src/inc/private/cfe_sb_destination_typedef.h new file mode 100644 index 000000000..8627b8476 --- /dev/null +++ b/fsw/cfe-core/src/inc/private/cfe_sb_destination_typedef.h @@ -0,0 +1,52 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/** + * Definition of the CFE_SB_DestinationD_t type. + * This was moved into its own header file since it is referenced by multiple CFE modules. + */ + +#ifndef CFE_SB_DESTINATION_TYPEDEF_H_ +#define CFE_SB_DESTINATION_TYPEDEF_H_ + +#include "common_types.h" +#include "cfe_sb.h" /* Required for CFE_SB_PipeId_t definition */ + +/****************************************************************************** + * This structure defines a DESTINATION DESCRIPTOR used to specify + * each destination pipe for a message. + * + * Note: Changing the size of this structure may require the memory pool + * block sizes to change. + */ +typedef struct +{ + CFE_SB_PipeId_t PipeId; + uint8 Active; + uint16 MsgId2PipeLim; + uint16 BuffCount; + uint16 DestCnt; + uint8 Scope; + uint8 Spare[3]; + void *Prev; + void *Next; +} CFE_SB_DestinationD_t; + +#endif /* CFE_SB_DESTINATION_TYPEDEF_H_ */ diff --git a/fsw/cfe-core/src/inc/private/cfe_sbr.h b/fsw/cfe-core/src/inc/private/cfe_sbr.h new file mode 100644 index 000000000..de0123bd7 --- /dev/null +++ b/fsw/cfe-core/src/inc/private/cfe_sbr.h @@ -0,0 +1,205 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/****************************************************************************** + * File: cfe_sbr.h + * + * Purpose: + * Prototypes for private functions and type definitions for SB + * routing internal use. + *****************************************************************************/ + +#ifndef CFE_SBR_H_ +#define CFE_SBR_H_ + +/* + * Includes + */ +#include "common_types.h" +#include "private/cfe_sb_destination_typedef.h" +#include "cfe_sb.h" +#include "cfe_msg_typedefs.h" +#include "cfe_platform_cfg.h" + +/****************************************************************************** + * Type Definitions + */ + +/** + * \brief Routing table id + * + * This is intended as a form of "strong typedef" where direct assignments should + * be restricted. Software bus uses numeric indexes into multiple tables to perform + * its duties, and it is important that these index values are distinct and separate + * and not mixed together. + * + * Using this holding structure prevents assignment directly into a different index + * or direct usage as numeric value. + */ +typedef struct +{ + CFE_SB_RouteId_Atom_t RouteId; /**< \brief Holding value, do not use directly in code */ +} CFE_SBR_RouteId_t; + +/** \brief Callback throttling structure */ +typedef struct +{ + uint32 StartIndex; /**< /brief 0 based index to start at */ + uint32 MaxLoop; /**< /brief Max number to process */ + uint32 NextIndex; /**< /brief Next start index (output), 0 if completed */ +} CFE_SBR_Throttle_t; + +/** \brief For each id callback function prototype */ +typedef void (*CFE_SBR_CallbackPtr_t)(CFE_SBR_RouteId_t RouteId, void *ArgPtr); + +/****************************************************************************** + * Function prototypes + */ + +/** + * \brief Initialize software bus routing module + */ +void CFE_SBR_Init(void); + +/** + * \brief Add a route for the given a message id + * + * Called for the first subscription to a message ID, uses up one + * element in the routing table. Assumes check for existing + * route was already performed or routes could leak + * + * \param[in] MsgId Message ID of the route to add + * \param[out] CollisionsPtr Number of collisions (if not null) + * + * \returns Route ID, will be invalid if route can not be added + */ +CFE_SBR_RouteId_t CFE_SBR_AddRoute(CFE_SB_MsgId_t MsgId, uint32 *CollisionsPtr); + +/** + * \brief Obtain the route id given a message id + * + * \param[in] MsgId Message ID of the route to get + * + * \returns Route ID, will be invalid if can't be returned + */ +CFE_SBR_RouteId_t CFE_SBR_GetRouteId(CFE_SB_MsgId_t MsgId); + +/** + * \brief Obtain the message id given a route id + * + * \param[in] RouteId Route ID of the message id to get + * + * \returns Message ID, will be invalid if cant be returned + */ +CFE_SB_MsgId_t CFE_SBR_GetMsgId(CFE_SBR_RouteId_t RouteId); + +/** + * \brief Obtain the destination list head pointer given a route id + * + * \param[in] RouteId Route ID + * + * \returns Destination list head pointer for the given route id. + * Will be null if route doesn't exist or no subscribers. + */ +CFE_SB_DestinationD_t *CFE_SBR_GetDestListHeadPtr(CFE_SBR_RouteId_t RouteId); + +/** + * \brief Set the destination list head pointer for given route id + * + * \param[in] RouteId Route Id + * \param[in] DestPtr Destination list head pointer + */ +void CFE_SBR_SetDestListHeadPtr(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *DestPtr); + +/** + * \brief Increment the sequence counter associated with the supplied route ID + * + * \param[in] RouteId Route ID + */ +void CFE_SBR_IncrementSequenceCounter(CFE_SBR_RouteId_t RouteId); + +/** + * \brief Get the sequence counter associated with the supplied route ID + * + * \param[in] RouteId Route ID + * + * \returns the sequence counter + */ +CFE_MSG_SequenceCount_t CFE_SBR_GetSequenceCounter(CFE_SBR_RouteId_t RouteId); + +/** + * \brief Call the supplied callback function for all routes + * + * Invokes callback for each route in the table. Message ID order + * depends on the routing table implementation. Possiblities include + * in subscription order and in order if incrementing message ids. + * + * \param[in] CallbackPtr Function to invoke for each matching ID + * \param[in] ArgPtr Opaque argument to pass to callback function + * \param[in,out] ThrottlePtr Throttling structure, NULL for no throttle + */ +void CFE_SBR_ForEachRouteId(CFE_SBR_CallbackPtr_t CallbackPtr, void *ArgPtr, CFE_SBR_Throttle_t *ThrottlePtr); + +/****************************************************************************** +** Inline functions +*/ + +/** + * \brief Identifies whether a given CFE_SBR_RouteId_t is valid + * + * Implements a basic sanity check on the value provided + * + * \returns true if sanity checks passed, false otherwise. + */ +static inline bool CFE_SBR_IsValidRouteId(CFE_SBR_RouteId_t RouteId) +{ + return (RouteId.RouteId != 0 && RouteId.RouteId <= CFE_PLATFORM_SB_MAX_MSG_IDS); +} + +/** + * \brief Converts from raw value to CFE_SBR_RouteId_t + * + * Converts the supplied "bare number" into a type-safe CFE_SBR_RouteId_t value + * + * \returns A CFE_SBR_RouteId_t + */ +static inline CFE_SBR_RouteId_t CFE_SBR_ValueToRouteId(CFE_SB_RouteId_Atom_t Value) +{ + return ((CFE_SBR_RouteId_t) {.RouteId = 1 + Value}); +} + +/** + * \brief Converts from CFE_SBR_RouteId_t to raw value + * + * Converts the supplied route id into a "bare number" suitable for performing + * array lookups or other tasks for which the holding structure cannot be used directly. + * + * Use with caution, as this removes the type safety information from the value. + * + * \note It is assumed the value has already been validated using CFE_SB_IsValidRouteId() + * + * \returns The underlying value + */ +static inline CFE_SB_RouteId_Atom_t CFE_SBR_RouteIdToValue(CFE_SBR_RouteId_t RouteId) +{ + return (RouteId.RouteId - 1); +} + +#endif /* CFE_SBR_H_ */ diff --git a/fsw/cfe-core/src/sb/cfe_sb_api.c b/fsw/cfe-core/src/sb/cfe_sb_api.c index 44a7019a6..57dddd61d 100644 --- a/fsw/cfe-core/src/sb/cfe_sb_api.c +++ b/fsw/cfe-core/src/sb/cfe_sb_api.c @@ -75,6 +75,13 @@ */ #define CFE_SB_TLM_PIPEDEPTHSTATS_SIZE (sizeof(CFE_SB.StatTlmMsg.Payload.PipeDepthStats) / sizeof(CFE_SB.StatTlmMsg.Payload.PipeDepthStats[0])) +/* Local structure for remove pipe callbacks */ +typedef struct +{ + const char *FullName; /* Full name (app.task) for error reporting */ + CFE_SB_PipeId_t PipeId; /* Pipe id to remove */ +} CFE_SB_RemovePipeCallback_t; + /* * Function: CFE_SB_CreatePipe - See API and header file for details */ @@ -246,7 +253,23 @@ int32 CFE_SB_DeletePipeWithAppId(CFE_SB_PipeId_t PipeId, CFE_ES_ResourceID_t App }/* end CFE_SB_DeletePipeWithAppId */ +/****************************************************************************** + * Local callback helper for deleting a pipe from a route + */ +void CFE_SB_RemovePipeFromRoute(CFE_SBR_RouteId_t RouteId, void *ArgPtr) +{ + CFE_SB_DestinationD_t *destptr; + CFE_SB_RemovePipeCallback_t *args; + + args = (CFE_SB_RemovePipeCallback_t *)ArgPtr; + destptr = CFE_SB_GetDestPtr(RouteId, args->PipeId); + + if (destptr != NULL) + { + CFE_SB_RemoveDest(RouteId, destptr); + } +} /****************************************************************************** ** Function: CFE_SB_DeletePipeFull() @@ -265,17 +288,18 @@ int32 CFE_SB_DeletePipeWithAppId(CFE_SB_PipeId_t PipeId, CFE_ES_ResourceID_t App */ int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId) { - uint8 PipeTblIdx; - int32 RtnFromVal,Stat; - CFE_ES_ResourceID_t Owner; - uint32 i; - CFE_ES_ResourceID_t TskId; - CFE_SB_Msg_t *PipeMsgPtr; - CFE_SB_DestinationD_t *DestPtr = NULL; - char FullName[(OS_MAX_API_NAME * 2)]; - - /* get TaskId of caller for events */ + uint8 PipeTblIdx; + int32 RtnFromVal; + int32 Stat; + CFE_ES_ResourceID_t Owner; + CFE_ES_ResourceID_t TskId; + CFE_SB_Msg_t *PipeMsgPtr; + char FullName[(OS_MAX_API_NAME * 2)]; + CFE_SB_RemovePipeCallback_t Args; + + /* get TaskId and name of caller for events */ CFE_ES_GetTaskID(&TskId); + CFE_SB_GetAppTskName(TskId, FullName); /* take semaphore to prevent a task switch during this call */ CFE_SB_LockSharedData(__func__,__LINE__); @@ -289,7 +313,7 @@ int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId) CFE_SB_UnlockSharedData(__func__,__LINE__); CFE_EVS_SendEventWithAppID(CFE_SB_DEL_PIPE_ERR1_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId, "Pipe Delete Error:Bad Argument,PipedId %d,Requestor %s,Idx %d,Stat %d", - (int)PipeId,CFE_SB_GetAppTskName(TskId,FullName),(int)PipeTblIdx,(int)RtnFromVal); + (int)PipeId,FullName,(int)PipeTblIdx,(int)RtnFromVal); return CFE_SB_BAD_ARGUMENT; }/* end if */ @@ -301,35 +325,14 @@ int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId) CFE_SB.HKTlmMsg.Payload.CreatePipeErrorCounter++; CFE_SB_UnlockSharedData(__func__,__LINE__); CFE_EVS_SendEventWithAppID(CFE_SB_DEL_PIPE_ERR2_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId, - "Pipe Delete Error:Caller(%s) is not the owner of pipe %d", - CFE_SB_GetAppTskName(TskId,FullName),(int)PipeId); + "Pipe Delete Error:Caller(%s) is not the owner of pipe %d", FullName, (int)PipeId); return CFE_SB_BAD_ARGUMENT; }/* end if */ - /* check destination list of every in-use MsgId, for the given pipeid. */ - /* when found, remove the pipe ID from the destination list via 'unsubscribe' */ - for(i=0;i PipeId == PipeId){ - /* release the semaphore, unsubscribe will need to take it */ - CFE_SB_UnlockSharedData(__func__,__LINE__); - CFE_SB_UnsubscribeWithAppId(CFE_SB.RoutingTbl[i].MsgId, - PipeId,AppId); - CFE_SB_LockSharedData(__func__,__LINE__); - }/* end if */ - - DestPtr = DestPtr -> Next; - - }/* end while */ - - }/* end if */ - }/* end for */ + /* Remove the pipe from all routes */ + Args.PipeId = PipeId; + Args.FullName = FullName; + CFE_SBR_ForEachRouteId(CFE_SB_RemovePipeFromRoute, &Args, NULL); if (CFE_SB.PipeTbl[PipeTblIdx].ToTrashBuff != NULL) { @@ -339,7 +342,6 @@ int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId) }/* end if */ - /* remove any messages that might be on the pipe */ /* this step will free the memory used to store the message */ do{ @@ -728,16 +730,16 @@ int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId, uint16 MsgLim, uint8 Scope) { - CFE_SB_MsgRouteIdx_t RouteIdx; - CFE_SB_RouteEntry_t* RoutePtr; + CFE_SBR_RouteId_t RouteId; int32 Stat; - CFE_SB_MsgKey_t MsgKey; CFE_ES_ResourceID_t TskId; CFE_ES_ResourceID_t AppId; uint8 PipeIdx; - CFE_SB_DestinationD_t *DestBlkPtr = NULL; + CFE_SB_DestinationD_t *DestPtr = NULL; + uint32 DestCount = 0; char FullName[(OS_MAX_API_NAME * 2)]; char PipeName[OS_MAX_API_NAME] = {'\0'}; + uint32 Collisions = 0; CFE_SB_GetPipeName(PipeName, sizeof(PipeName), PipeId); @@ -783,48 +785,44 @@ int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId, return CFE_SB_BAD_ARGUMENT; }/* end if */ - /* Convert the API MsgId into the SB internal representation MsgKey */ - MsgKey = CFE_SB_ConvertMsgIdtoMsgKey(MsgId); - - /* check for duplicate subscription */ - if(CFE_SB_DuplicateSubscribeCheck(MsgKey,PipeId)==CFE_SB_DUPLICATE){ - CFE_SB.HKTlmMsg.Payload.DuplicateSubscriptionsCounter++; - CFE_SB_UnlockSharedData(__func__,__LINE__); - CFE_EVS_SendEventWithAppID(CFE_SB_DUP_SUBSCRIP_EID,CFE_EVS_EventType_INFORMATION,CFE_SB.AppId, - "Duplicate Subscription,MsgId 0x%x on %s pipe,app %s", - (unsigned int)CFE_SB_MsgIdToValue(MsgId), - PipeName,CFE_SB_GetAppTskName(TskId,FullName)); - return CFE_SUCCESS; - }/* end if */ - - /* - ** If there has been a subscription for this message id earlier, - ** get the element number in the routing table. - */ - RouteIdx = CFE_SB_GetRoutingTblIdx(MsgKey); - - /* if not first subscription for this message KEY ... */ - if(CFE_SB_IsValidRouteIdx(RouteIdx)) + RouteId = CFE_SBR_GetRouteId(MsgId); + if (CFE_SBR_IsValidRouteId(RouteId)) { - RoutePtr = CFE_SB_GetRoutePtrFromIdx(RouteIdx); + /* check for duplicate subscription */ + if(CFE_SB_GetDestPtr(RouteId, PipeId) != NULL) + { + CFE_SB.HKTlmMsg.Payload.DuplicateSubscriptionsCounter++; + CFE_SB_UnlockSharedData(__func__,__LINE__); + CFE_EVS_SendEventWithAppID(CFE_SB_DUP_SUBSCRIP_EID,CFE_EVS_EventType_INFORMATION,CFE_SB.AppId, + "Duplicate Subscription,MsgId 0x%x on %s pipe,app %s", + (unsigned int)CFE_SB_MsgIdToValue(MsgId), + PipeName,CFE_SB_GetAppTskName(TskId,FullName)); + return CFE_SUCCESS; + } - /* - * FIXME: If a hash or other conversion is used between MsgId and MsgKey, - * then it is possible that this existing route is for a different MsgId. - * - * The MsgId should be checked against the "MsgId" in the route here. - * - * However it is not possible to have a mismatch in the default case where - * MsgKey == MsgId - */ + /* Check for destination limit */ + for (DestPtr = CFE_SBR_GetDestListHeadPtr(RouteId); DestPtr != NULL; DestPtr = DestPtr->Next) + { + DestCount++; + } + if(DestCount >= CFE_PLATFORM_SB_MAX_DEST_PER_PKT){ + CFE_SB_UnlockSharedData(__func__,__LINE__); + CFE_EVS_SendEventWithAppID(CFE_SB_MAX_DESTS_MET_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId, + "Subscribe Err:Max Dests(%d)In Use For Msg 0x%x,pipe %s,app %s", + CFE_PLATFORM_SB_MAX_DEST_PER_PKT, + (unsigned int)CFE_SB_MsgIdToValue(MsgId), + PipeName, CFE_SB_GetAppTskName(TskId,FullName)); + + return CFE_SB_MAX_DESTS_MET; + } } else { - /* Get the index to the first available element in the routing table */ - RouteIdx = CFE_SB_RouteIdxPop_Unsync(); + /* Add the route */ + RouteId = CFE_SBR_AddRoute(MsgId, &Collisions); /* if all routing table elements are used, send event */ - if(!CFE_SB_IsValidRouteIdx(RouteIdx)){ + if(!CFE_SBR_IsValidRouteId(RouteId)){ CFE_SB_UnlockSharedData(__func__,__LINE__); CFE_EVS_SendEventWithAppID(CFE_SB_MAX_MSGS_MET_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId, "Subscribe Err:Max Msgs(%d)In Use,MsgId 0x%x,pipe %s,app %s", @@ -841,28 +839,10 @@ int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId, CFE_SB.StatTlmMsg.Payload.PeakMsgIdsInUse = CFE_SB.StatTlmMsg.Payload.MsgIdsInUse; }/* end if */ - /* populate the look up table with the routing table index */ - CFE_SB_SetRoutingTblIdx(MsgKey,RouteIdx); - - /* label the new routing block with the message identifier */ - RoutePtr = CFE_SB_GetRoutePtrFromIdx(RouteIdx); - RoutePtr->MsgId = MsgId; - }/* end if */ - if(RoutePtr->Destinations >= CFE_PLATFORM_SB_MAX_DEST_PER_PKT){ - CFE_SB_UnlockSharedData(__func__,__LINE__); - CFE_EVS_SendEventWithAppID(CFE_SB_MAX_DESTS_MET_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId, - "Subscribe Err:Max Dests(%d)In Use For Msg 0x%x,pipe %s,app %s", - CFE_PLATFORM_SB_MAX_DEST_PER_PKT, - (unsigned int)CFE_SB_MsgIdToValue(MsgId), - PipeName, CFE_SB_GetAppTskName(TskId,FullName)); - - return CFE_SB_MAX_DESTS_MET; - }/* end if */ - - DestBlkPtr = CFE_SB_GetDestinationBlk(); - if(DestBlkPtr == NULL){ + DestPtr = CFE_SB_GetDestinationBlk(); + if(DestPtr == NULL){ CFE_SB_UnlockSharedData(__func__,__LINE__); CFE_EVS_SendEventWithAppID(CFE_SB_DEST_BLK_ERR_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId, "Subscribe Err:Request for Destination Blk failed for Msg 0x%x", @@ -871,19 +851,17 @@ int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId, }/* end if */ /* initialize destination block */ - DestBlkPtr -> PipeId = PipeId; - DestBlkPtr -> MsgId2PipeLim = (uint16)MsgLim; - DestBlkPtr -> Active = CFE_SB_ACTIVE; - DestBlkPtr -> BuffCount = 0; - DestBlkPtr -> DestCnt = 0; - DestBlkPtr -> Scope = Scope; - DestBlkPtr -> Prev = NULL; - DestBlkPtr -> Next = NULL; - - /* add destination block to head of list */ - CFE_SB_AddDest(RoutePtr, DestBlkPtr); - - RoutePtr->Destinations++; + DestPtr->PipeId = PipeId; + DestPtr->MsgId2PipeLim = (uint16)MsgLim; + DestPtr->Active = CFE_SB_ACTIVE; + DestPtr->BuffCount = 0; + DestPtr->DestCnt = 0; + DestPtr->Scope = Scope; + DestPtr->Prev = NULL; + DestPtr->Next = NULL; + + /* add destination node */ + CFE_SB_AddDestNode(RouteId, DestPtr); CFE_SB.StatTlmMsg.Payload.SubscriptionsInUse++; if(CFE_SB.StatTlmMsg.Payload.SubscriptionsInUse > CFE_SB.StatTlmMsg.Payload.PeakSubscriptionsInUse) @@ -914,6 +892,13 @@ int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId, (unsigned int)CFE_SB_MsgIdToValue(MsgId), PipeName,(int)PipeId,CFE_SB_GetAppTskName(TskId,FullName)); + if (Collisions != 0) + { + CFE_EVS_SendEventWithAppID(CFE_SB_HASHCOLLISION_EID, CFE_EVS_EventType_DEBUG, CFE_SB.AppId, + "Msg hash collision: MsgId = 0x%x, collisions = %u", + (unsigned int)CFE_SB_MsgIdToValue(MsgId), Collisions); + } + return CFE_SUCCESS; }/* end CFE_SB_SubscribeFull */ @@ -1021,13 +1006,12 @@ int32 CFE_SB_UnsubscribeWithAppId(CFE_SB_MsgId_t MsgId, int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId,CFE_SB_PipeId_t PipeId, uint8 Scope,CFE_ES_ResourceID_t AppId) { - CFE_SB_MsgKey_t MsgKey; - CFE_SB_MsgRouteIdx_t RouteIdx; - CFE_SB_RouteEntry_t* RoutePtr; + CFE_SBR_RouteId_t RouteId; uint32 PipeIdx; CFE_ES_ResourceID_t TskId; CFE_SB_DestinationD_t *DestPtr = NULL; char FullName[(OS_MAX_API_NAME * 2)]; + char PipeName[OS_MAX_API_NAME] = {'\0'}; /* get TaskId of caller for events */ CFE_ES_GetTaskID(&TskId); @@ -1070,15 +1054,12 @@ int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId,CFE_SB_PipeId_t PipeId, return CFE_SB_BAD_ARGUMENT; }/* end if */ - /* get index into routing table */ - MsgKey = CFE_SB_ConvertMsgIdtoMsgKey(MsgId); - RouteIdx = CFE_SB_GetRoutingTblIdx(MsgKey); + /* get routing id */ + RouteId = CFE_SBR_GetRouteId(MsgId); /* if there have never been subscriptions for this message id... */ - if(!CFE_SB_IsValidRouteIdx(RouteIdx)) + if(!CFE_SBR_IsValidRouteId(RouteId)) { - char PipeName[OS_MAX_API_NAME] = {'\0'}; - CFE_SB_UnlockSharedData(__func__,__LINE__); CFE_SB_GetPipeName(PipeName, sizeof(PipeName), PipeId); @@ -1090,22 +1071,13 @@ int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId,CFE_SB_PipeId_t PipeId, return CFE_SUCCESS; }/* end if */ - RoutePtr = CFE_SB_GetRoutePtrFromIdx(RouteIdx); + /* Get the destination pointer */ + DestPtr = CFE_SB_GetDestPtr(RouteId, PipeId); - /* search the list for a matching pipe id */ - for (DestPtr = RoutePtr->ListHeadPtr; DestPtr != NULL && DestPtr->PipeId != PipeId; DestPtr = DestPtr->Next) - ; - - if(DestPtr) + if(DestPtr != NULL) { - /* match found, remove node from list */ - CFE_SB_RemoveDest(RoutePtr,DestPtr); - - /* return node to memory pool */ - CFE_SB_PutDestinationBlk(DestPtr); - - RoutePtr->Destinations--; - CFE_SB.StatTlmMsg.Payload.SubscriptionsInUse--; + /* match found, remove destination */ + CFE_SB_RemoveDest(RouteId,DestPtr); CFE_EVS_SendEventWithAppID(CFE_SB_SUBSCRIPTION_REMOVED_EID,CFE_EVS_EventType_DEBUG,CFE_SB.AppId, "Subscription Removed:Msg 0x%x on pipe %d,app %s", @@ -1114,8 +1086,6 @@ int32 CFE_SB_UnsubscribeFull(CFE_SB_MsgId_t MsgId,CFE_SB_PipeId_t PipeId, } else { - char PipeName[OS_MAX_API_NAME] = {'\0'}; - CFE_SB_GetPipeName(PipeName, sizeof(PipeName), PipeId); CFE_EVS_SendEventWithAppID(CFE_SB_UNSUB_NO_SUBS_EID,CFE_EVS_EventType_INFORMATION,CFE_SB.AppId, @@ -1188,21 +1158,20 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr, uint32 TlmCntIncrements, uint32 CopyMode) { - CFE_SB_MsgKey_t MsgKey; CFE_SB_MsgId_t MsgId; int32 Status; CFE_SB_DestinationD_t *DestPtr = NULL; CFE_SB_PipeD_t *PipeDscPtr; - CFE_SB_RouteEntry_t *RtgTblPtr; + CFE_SBR_RouteId_t RouteId; CFE_SB_BufferD_t *BufDscPtr; uint16 TotalMsgSize; - CFE_SB_MsgRouteIdx_t RtgTblIdx; CFE_ES_ResourceID_t AppId; CFE_ES_ResourceID_t TskId; uint32 i; char FullName[(OS_MAX_API_NAME * 2)]; CFE_SB_EventBuf_t SBSndErr; char PipeName[OS_MAX_API_NAME] = {'\0'}; + CFE_SB_PipeDepthStats_t *StatObj; SBSndErr.EvtsToSnd = 0; @@ -1262,16 +1231,15 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr, return CFE_SB_MSG_TOO_BIG; }/* end if */ - MsgKey = CFE_SB_ConvertMsgIdtoMsgKey(MsgId); - /* take semaphore to prevent a task switch during this call */ CFE_SB_LockSharedData(__func__,__LINE__); - RtgTblIdx = CFE_SB_GetRoutingTblIdx(MsgKey); + /* Get the routing pointer */ + RouteId = CFE_SBR_GetRouteId(MsgId); /* if there have been no subscriptions for this pkt, */ /* increment the dropped pkt cnt, send event and return success */ - if(!CFE_SB_IsValidRouteIdx(RtgTblIdx)){ + if(!CFE_SBR_IsValidRouteId(RouteId)){ CFE_SB.HKTlmMsg.Payload.NoSubscribersCounter++; @@ -1329,30 +1297,16 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr, memcpy( BufDscPtr->Buffer, MsgPtr, (uint16)TotalMsgSize ); } - /* Obtain the actual routing table entry from the selected index */ - RtgTblPtr = CFE_SB_GetRoutePtrFromIdx(RtgTblIdx); - /* For Tlm packets, increment the seq count if requested */ if((CFE_SB_GetPktType(MsgId)==CFE_SB_PKTTYPE_TLM) && (TlmCntIncrements==CFE_SB_INCREMENT_TLM)){ - RtgTblPtr->SeqCnt++; - CFE_SB_SetMsgSeqCnt((CFE_SB_Msg_t *)BufDscPtr->Buffer, - RtgTblPtr->SeqCnt); + CFE_SBR_IncrementSequenceCounter(RouteId); + CFE_SB_SetMsgSeqCnt((CFE_SB_Msg_t *)BufDscPtr->Buffer, CFE_SBR_GetSequenceCounter(RouteId)); }/* end if */ - /* At this point there must be at least one destination for pkt */ - /* Send the packet to all destinations */ - for (i=0, DestPtr = RtgTblPtr -> ListHeadPtr; - i < RtgTblPtr -> Destinations; i++, DestPtr = DestPtr -> Next) + for(DestPtr = CFE_SBR_GetDestListHeadPtr(RouteId); DestPtr != NULL; DestPtr = DestPtr->Next) { - /* The DestPtr should never be NULL in this loop, this is just extra - protection in case of the unforseen */ - if(DestPtr == NULL) - { - break; - } - if (DestPtr->Active == CFE_SB_INACTIVE) /* destination is active */ { continue; @@ -1383,42 +1337,41 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr, ** Write the buffer descriptor to the queue of the pipe. If the write ** failed, log info and increment the pipe's error counter. */ - Status = OS_QueuePut(PipeDscPtr->SysQueueId,(void *)&BufDscPtr, - sizeof(CFE_SB_BufferD_t *),0); + Status = OS_QueuePut(PipeDscPtr->SysQueueId, (void *)&BufDscPtr, sizeof(CFE_SB_BufferD_t *), 0); - if (Status == OS_SUCCESS) { + if (Status == OS_SUCCESS) + { BufDscPtr->UseCount++; /* used for releasing buffer */ DestPtr->BuffCount++; /* used for checking MsgId2PipeLimit */ DestPtr->DestCnt++; /* used for statistics */ if (DestPtr->PipeId < CFE_SB_TLM_PIPEDEPTHSTATS_SIZE) { - CFE_SB_PipeDepthStats_t *StatObj = - &CFE_SB.StatTlmMsg.Payload.PipeDepthStats[DestPtr->PipeId]; + StatObj = &CFE_SB.StatTlmMsg.Payload.PipeDepthStats[DestPtr->PipeId]; StatObj->InUse++; - if(StatObj->InUse > StatObj->PeakInUse){ + if(StatObj->InUse > StatObj->PeakInUse) + { StatObj->PeakInUse = StatObj->InUse; }/* end if */ } - - }else if(Status == OS_QUEUE_FULL) { - + } + else if(Status == OS_QUEUE_FULL) + { SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].PipeId = DestPtr->PipeId; SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].EventId = CFE_SB_Q_FULL_ERR_EID; SBSndErr.EvtsToSnd++; CFE_SB.HKTlmMsg.Payload.PipeOverflowErrorCounter++; PipeDscPtr->SendErrors++; - - - }else{ /* Unexpected error while writing to queue. */ - + } + else + { + /* Unexpected error while writing to queue. */ SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].PipeId = DestPtr->PipeId; SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].EventId = CFE_SB_Q_WR_ERR_EID; SBSndErr.EvtBuf[SBSndErr.EvtsToSnd].ErrStat = Status; SBSndErr.EvtsToSnd++; CFE_SB.HKTlmMsg.Payload.InternalErrorCounter++; PipeDscPtr->SendErrors++; - - }/*end if */ + }/*end if */ } /* end loop over destinations */ @@ -1434,7 +1387,6 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr, /* release the semaphore */ CFE_SB_UnlockSharedData(__func__,__LINE__); - /* send an event for each pipe write error that may have occurred */ for(i=0;i < SBSndErr.EvtsToSnd; i++) { @@ -1451,7 +1403,7 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr, CFE_EVS_SendEventWithAppID(CFE_SB_MSGID_LIM_ERR_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId, "Msg Limit Err,MsgId 0x%x,pipe %s,sender %s", - (unsigned int)CFE_SB_MsgIdToValue(RtgTblPtr->MsgId), + (unsigned int)CFE_SB_MsgIdToValue(MsgId), PipeName, CFE_SB_GetAppTskName(TskId,FullName)); /* clear the bit so the task may send this event again */ @@ -1470,7 +1422,7 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr, CFE_EVS_SendEventWithAppID(CFE_SB_Q_FULL_ERR_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId, "Pipe Overflow,MsgId 0x%x,pipe %s,sender %s", - (unsigned int)CFE_SB_MsgIdToValue(RtgTblPtr->MsgId), + (unsigned int)CFE_SB_MsgIdToValue(MsgId), PipeName, CFE_SB_GetAppTskName(TskId,FullName)); /* clear the bit so the task may send this event again */ @@ -1486,7 +1438,7 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr, CFE_EVS_SendEventWithAppID(CFE_SB_Q_WR_ERR_EID,CFE_EVS_EventType_ERROR,CFE_SB.AppId, "Pipe Write Err,MsgId 0x%x,pipe %s,sender %s,stat 0x%x", - (unsigned int)CFE_SB_MsgIdToValue(RtgTblPtr->MsgId), + (unsigned int)CFE_SB_MsgIdToValue(MsgId), PipeName, CFE_SB_GetAppTskName(TskId,FullName), (unsigned int)SBSndErr.EvtBuf[i].ErrStat); @@ -1497,7 +1449,6 @@ int32 CFE_SB_SendMsgFull(CFE_SB_Msg_t *MsgPtr, }/* end if */ } - return CFE_SUCCESS; }/* end CFE_SB_SendMsgFull */ @@ -1515,6 +1466,7 @@ int32 CFE_SB_RcvMsg(CFE_SB_MsgPtr_t *BufPtr, CFE_SB_BufferD_t *Message; CFE_SB_PipeD_t *PipeDscPtr; CFE_SB_DestinationD_t *DestPtr = NULL; + CFE_SBR_RouteId_t RouteId; CFE_ES_ResourceID_t TskId; char FullName[(OS_MAX_API_NAME * 2)]; @@ -1586,7 +1538,8 @@ int32 CFE_SB_RcvMsg(CFE_SB_MsgPtr_t *BufPtr, *BufPtr = (CFE_SB_MsgPtr_t) Message->Buffer; /* get pointer to destination to be used in decrementing msg limit cnt*/ - DestPtr = CFE_SB_GetDestPtr(CFE_SB_ConvertMsgIdtoMsgKey(PipeDscPtr->CurrentBuff->MsgId), PipeDscPtr->PipeId); + RouteId = CFE_SBR_GetRouteId(PipeDscPtr->CurrentBuff->MsgId); + DestPtr = CFE_SB_GetDestPtr(RouteId, PipeDscPtr->PipeId); /* ** DestPtr would be NULL if the msg is unsubscribed to while it is on @@ -1604,7 +1557,7 @@ int32 CFE_SB_RcvMsg(CFE_SB_MsgPtr_t *BufPtr, if (PipeDscPtr->PipeId < CFE_SB_TLM_PIPEDEPTHSTATS_SIZE) { - CFE_SB.StatTlmMsg.Payload.PipeDepthStats[PipeDscPtr->PipeId].InUse--; + CFE_SB.StatTlmMsg.Payload.PipeDepthStats[PipeDscPtr->PipeId].InUse--; } }else{ diff --git a/fsw/cfe-core/src/sb/cfe_sb_init.c b/fsw/cfe-core/src/sb/cfe_sb_init.c index 3a831269a..5095e1f95 100644 --- a/fsw/cfe-core/src/sb/cfe_sb_init.c +++ b/fsw/cfe-core/src/sb/cfe_sb_init.c @@ -112,15 +112,9 @@ int32 CFE_SB_EarlyInit (void) { /* Initialize the pipe table. */ CFE_SB_InitPipeTbl(); - /* Initialize the routing index look up table */ - CFE_SB_InitMsgMap(); + /* Initialize the routing module */ + CFE_SBR_Init(); - /* Initialize the routing table. */ - CFE_SB_InitRoutingTbl(); - - /* Initialize the APID to routing index map table */ - CFE_SB_InitIdxStack(); - /* Initialize the SB Statistics Pkt */ CFE_SB_InitMsg(&CFE_SB.StatTlmMsg, CFE_SB_ValueToMsgId(CFE_SB_STATS_TLM_MID), @@ -198,63 +192,4 @@ void CFE_SB_InitPipeTbl(void){ }/* end CFE_SB_InitPipeTbl */ - - -/****************************************************************************** -** Function: CFE_SB_InitMsgMap() -** -** Purpose: -** Initialize the Software Bus Message Map. -** -** Arguments: -** -** Notes: -** This function MUST be called before any SB API's are called. -** -** Return: -** none -*/ -void CFE_SB_InitMsgMap(void){ - - CFE_SB_MsgKey_Atom_t KeyVal; - - for (KeyVal=0; KeyVal < CFE_SB_MAX_NUMBER_OF_MSG_KEYS; KeyVal++) - { - CFE_SB.MsgMap[KeyVal] = CFE_SB_INVALID_ROUTE_IDX; - } - -}/* end CFE_SB_InitMsgMap */ - - - -/****************************************************************************** -** Function: CFE_SB_InitRoutingTbl() -** -** Purpose: -** Initialize the Software Bus Routing Table. -** -** Arguments: -** -** Notes: -** This function MUST be called before any SB API's are called. -** -** Return: -** none -*/ -void CFE_SB_InitRoutingTbl(void){ - - uint32 i; - - /* Initialize routing table */ - for(i=0;i -/****************************************************************************** -** Function: CFE_SB_InitIdxStack() -** -** Purpose: Initialize a push/pop stack of routing table indexes. -** On init each must be unique. After system initialization SB_Idx_top -** will always point/index to the next available routing table index -** -** Arguments: -** -** Return: -** None -*/ - -void CFE_SB_InitIdxStack(void) -{ - uint16 i; - - CFE_SB.RouteIdxTop = 0; - for (i=0; i= CFE_PLATFORM_SB_MAX_MSG_IDS) { - retValue = CFE_SB_INVALID_ROUTE_IDX; /* no more Idx remaining, all used */ - } else { - retValue = CFE_SB.RouteIdxStack[CFE_SB.RouteIdxTop]; - ++CFE_SB.RouteIdxTop; - } - - return (retValue); -} /* end CFE_SB_IdxPop_Unsync */ - - -/****************************************************************************** -** Function: CFE_SB_RouteIdxPush_Unsync() -** -** Purpose: -** SB internal function to return a Routing Table element to the available stack -** (CFE_SB_RouteEntry_t). Typically called when an application un-subscribes -** to a message. 0 is a valid idx. -** -** Assumptions, External Events, and Notes: -** Calls to this function assumed to be protected by a semaphore -** -** Arguments: -** None -** -** Return: -** None -*/ -void CFE_SB_RouteIdxPush_Unsync (CFE_SB_MsgRouteIdx_t idx) { - - /* This stack grows from 0 to (CFE_PLATFORM_SB_MAX_MSG_IDS - 1) */ - if (CFE_SB.RouteIdxTop > 0) { - --CFE_SB.RouteIdxTop; - CFE_SB.RouteIdxStack[CFE_SB.RouteIdxTop] = idx; - } -} /* end CFE_SB_IdxPush_Unsync */ /****************************************************************************** ** Function: CFE_SB_GetPipeIdx() @@ -363,176 +280,27 @@ CFE_SB_PipeD_t *CFE_SB_GetPipePtr(CFE_SB_PipeId_t PipeId) { }/* end CFE_SB_GetPipePtr */ - - -/****************************************************************************** -** Function: CFE_SB_GetDestPtr() -** -** Purpose: -** SB internal function to get a pointer to the destination descriptor -** associated with the given message id/pipe id combination. -** -** Arguments: -** MsgId : ID of the message -** PipeId : Pipe ID for the destination. -** -** Return: -** Pointer to the destination descriptor that corresponds to the msg/pipe -** combination. If the destination does not exist, return NULL. -*/ -CFE_SB_DestinationD_t *CFE_SB_GetDestPtr(CFE_SB_MsgKey_t MsgKey, - CFE_SB_PipeId_t PipeId){ - - CFE_SB_MsgRouteIdx_t Idx; - CFE_SB_DestinationD_t *DestPtr; - - Idx = CFE_SB_GetRoutingTblIdx(MsgKey); - - if(!CFE_SB_IsValidRouteIdx(Idx)) - { - return NULL; - }/* end if */ - - DestPtr = CFE_SB_GetRoutePtrFromIdx(Idx)->ListHeadPtr; - - while(DestPtr != NULL){ - - if(DestPtr -> PipeId == PipeId){ - return DestPtr; - }/* end if */ - - DestPtr = DestPtr->Next; - - }/* end while */ - - return NULL; - -}/* end CFE_SB_GetDestPtr */ - - - /****************************************************************************** -** Function: CFE_SB_GetRoutingTblIdx() -** -** Purpose: -** SB internal function to get the index of the routing table element -** associated with the given message id. -** -** Assumptions: -** Calls to this are predicated by a call to CFE_SB_IsValidMsgKey -** which already check the MsgKey argument -** -** Arguments: -** MsgKey : ID of the message -** PipeId : Pipe ID for the destination. -** -** Return: -** Will return the index of the routing table element for the given message ID -*/ -CFE_SB_MsgRouteIdx_t CFE_SB_GetRoutingTblIdx(CFE_SB_MsgKey_t MsgKey){ - - return CFE_SB.MsgMap[CFE_SB_MsgKeyToValue(MsgKey)]; - -}/* end CFE_SB_GetRoutingTblIdx */ - - - -/****************************************************************************** -** Function: CFE_SB_SetRoutingTblIdx() -** -** Purpose: -** SB internal function to set a value in the message map. The "Value" is -** the routing table index of the given message ID. The message map is used -** for quick routing table index lookups of a given message ID. The cost of -** this quick lookup is 8K bytes of memory(for CCSDS). -** -** Assumptions: -** Calls to this are predicated by a call to CFE_SB_IsValidMsgKey -** which already check the MsgKey argument -** -** Arguments: -** MsgKey : ID of the message -** Value : value to set. -** -** Return: -** -*/ -void CFE_SB_SetRoutingTblIdx(CFE_SB_MsgKey_t MsgKey, CFE_SB_MsgRouteIdx_t Value){ - - CFE_SB.MsgMap[CFE_SB_MsgKeyToValue(MsgKey)] = Value; - -}/* end CFE_SB_SetRoutingTblIdx */ - - -/****************************************************************************** -** Function: CFE_SB_GetRoutePtrFromIdx() -** -** Purpose: -** SB internal function to obtain a pointer to a routing table entry -** based on a CFE_SB_MsgRouteIdx_t value. -** -** Assumptions: -** Calls to this are predicated by a call to CFE_SB_IsValidRouteIdx -** which already check the RouteIdx argument -** -** Arguments: -** RouteIdx : ID of the route to get -** -** Return: -** Pointer to route entry -** -*/ -CFE_SB_RouteEntry_t* CFE_SB_GetRoutePtrFromIdx(CFE_SB_MsgRouteIdx_t RouteIdx) + * SB private function to get destination pointer - see description in header + */ +CFE_SB_DestinationD_t *CFE_SB_GetDestPtr(CFE_SBR_RouteId_t RouteId, CFE_SB_PipeId_t PipeId) { - return &CFE_SB.RoutingTbl[CFE_SB_RouteIdxToValue(RouteIdx)]; -} /* end CFE_SB_GetRouteFromIdx */ + CFE_SB_DestinationD_t *destptr; -/****************************************************************************** -** Function: CFE_SB_DuplicateSubscribeCheck() -** -** Purpose: -** SB internal function to check for a duplicate subscription. -** -** Arguments: -** MsgId : ID of the message -** PipeId : ID of the pipe -** -** Return: -** Will return CFE_SB_DUPLICATE if the given MsgId/PipeId subscription -** exists in SB routing tables, otherwise will return CFE_SB_NO_DUPLICATE. -*/ -int32 CFE_SB_DuplicateSubscribeCheck(CFE_SB_MsgKey_t MsgKey, - CFE_SB_PipeId_t PipeId){ + destptr = CFE_SBR_GetDestListHeadPtr(RouteId); - CFE_SB_MsgRouteIdx_t Idx; - CFE_SB_DestinationD_t *DestPtr; - - Idx = CFE_SB_GetRoutingTblIdx(MsgKey); - - if(!CFE_SB_IsValidRouteIdx(Idx)) + /* Check all destinations */ + while(destptr != NULL) { - DestPtr = NULL; + if(destptr->PipeId == PipeId) + { + break; + } + destptr = destptr->Next; } - else - { - DestPtr = CFE_SB_GetRoutePtrFromIdx(Idx)->ListHeadPtr; - }/* end if */ - - while(DestPtr != NULL){ - - if(DestPtr -> PipeId == PipeId){ - return CFE_SB_DUPLICATE; - }/* end if */ - - DestPtr = DestPtr->Next; - - }/* end while */ - - return CFE_SB_NO_DUPLICATE; - -}/* end CFE_SB_DuplicateSubscribeCheck */ - + return destptr; +} /****************************************************************************** ** Function: CFE_SB_SetMsgSeqCnt() @@ -721,38 +489,26 @@ void CFE_SB_FinishSendEvent(CFE_ES_ResourceID_t TaskId, uint32 Bit){ CFE_CLR(CFE_SB.StopRecurseFlags[Indx],Bit); }/* end CFE_SB_RequestToSendEvent */ - - /****************************************************************************** -** Function: CFE_SB_AddDest() -** -** Purpose: -** This function will add the given node to the head of the list. -** -** Arguments: -** RtgTblIdx - Routing table index -** Dest - Pointer to the destination block to add to the list -** -** Return: -** -*/ -int32 CFE_SB_AddDest(CFE_SB_RouteEntry_t *RouteEntry, CFE_SB_DestinationD_t *NewNode){ + * SB private function to add a destination node - see description in header + */ +int32 CFE_SB_AddDestNode(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *NewNode){ CFE_SB_DestinationD_t *WBS;/* Will Be Second (WBS) node */ + CFE_SB_DestinationD_t *listheadptr; - /* if first node in list */ - if(RouteEntry->ListHeadPtr == NULL){ + listheadptr = CFE_SBR_GetDestListHeadPtr(RouteId); + /* if first node in list */ + if(listheadptr == NULL) + { /* initialize the new node */ NewNode->Next = NULL; NewNode->Prev = NULL; - - /* insert the new node */ - RouteEntry->ListHeadPtr = NewNode; - - }else{ - - WBS = RouteEntry->ListHeadPtr; + } + else + { + WBS = listheadptr; /* initialize the new node */ NewNode->Next = WBS; @@ -760,75 +516,63 @@ int32 CFE_SB_AddDest(CFE_SB_RouteEntry_t *RouteEntry, CFE_SB_DestinationD_t *New /* insert the new node */ WBS -> Prev = NewNode; - RouteEntry->ListHeadPtr = NewNode; + } - }/* end if */ + /* Update Head */ + CFE_SBR_SetDestListHeadPtr(RouteId, NewNode); return CFE_SUCCESS; - -}/* CFE_SB_AddDest */ - - +} /****************************************************************************** -** Function: CFE_SB_RemoveDest() -** -** Purpose: -** This function will remove the given node from the list. -** This function assumes there is at least one node in the list. -** -** Arguments: -** RtgTblIdx - Routing table index -** Dest - Pointer to the destination block to remove from the list -** -** Return: -** -*/ -int32 CFE_SB_RemoveDest(CFE_SB_RouteEntry_t *RouteEntry, CFE_SB_DestinationD_t *NodeToRemove){ + * SB private function to remove a destination - see description in header + */ +void CFE_SB_RemoveDest(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *DestPtr) +{ + CFE_SB_RemoveDestNode(RouteId, DestPtr); + CFE_SB_PutDestinationBlk(DestPtr); + CFE_SB.StatTlmMsg.Payload.SubscriptionsInUse--; +} +/****************************************************************************** + * SB private function to remove a destination node - see description in header + */ +void CFE_SB_RemoveDestNode(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *NodeToRemove) +{ CFE_SB_DestinationD_t *PrevNode; CFE_SB_DestinationD_t *NextNode; - /* if this is the only node in the list */ - if((NodeToRemove->Prev == NULL) && (NodeToRemove->Next == NULL)){ - - RouteEntry->ListHeadPtr = NULL; - - /* if first node in the list and list has more than one */ - }else if(NodeToRemove->Prev == NULL){ - + if((NodeToRemove->Prev == NULL) && (NodeToRemove->Next == NULL)) + { + /* Clear destinations if this is the only node in the list */ + CFE_SBR_SetDestListHeadPtr(RouteId, NULL); + } + else if(NodeToRemove->Prev == NULL) + { + /* First in the list, set the next node to list head */ NextNode = NodeToRemove->Next; - NextNode -> Prev = NULL; + CFE_SBR_SetDestListHeadPtr(RouteId, NextNode); + } + else if(NodeToRemove->Next == NULL){ - RouteEntry->ListHeadPtr = NextNode; - - /* if last node in the list and list has more than one */ - }else if(NodeToRemove->Next == NULL){ - + /* Last in the list, remove previous pointer */ PrevNode = NodeToRemove->Prev; - PrevNode -> Next = NULL; - - /* NodeToRemove has node(s) before and node(s) after */ - }else{ - + } + else + { + /* Middle of list, remove */ PrevNode = NodeToRemove->Prev; NextNode = NodeToRemove->Next; - PrevNode -> Next = NextNode; NextNode -> Prev = PrevNode; - - }/* end if */ - + } /* initialize the node before returning it to the heap */ NodeToRemove -> Next = NULL; NodeToRemove -> Prev = NULL; - - return CFE_SUCCESS; - -}/* CFE_SB_RemoveDest */ +} /****************************************************************************** diff --git a/fsw/cfe-core/src/sb/cfe_sb_priv.h b/fsw/cfe-core/src/sb/cfe_sb_priv.h index f0a3bdcfd..efc015f79 100644 --- a/fsw/cfe-core/src/sb/cfe_sb_priv.h +++ b/fsw/cfe-core/src/sb/cfe_sb_priv.h @@ -37,17 +37,17 @@ */ #include "common_types.h" #include "private/cfe_private.h" +#include "private/cfe_sb_destination_typedef.h" #include "cfe_sb.h" #include "cfe_sb_msg.h" #include "cfe_time.h" #include "cfe_es.h" +#include "private/cfe_sbr.h" /* ** Macro Definitions */ -#define CFE_SB_INVALID_ROUTE_IDX ((CFE_SB_MsgRouteIdx_t){ .RouteIdx = 0 }) -#define CFE_SB_INVALID_MSG_KEY ((CFE_SB_MsgKey_t){ .KeyIdx = 0 }) #define CFE_SB_UNUSED_QUEUE OS_OBJECT_ID_UNDEFINED #define CFE_SB_INVALID_PIPE 0xFF #define CFE_SB_NO_DESTINATION 0xFF @@ -98,64 +98,10 @@ #define CFE_SB_Q_FULL_ERR_EID_BIT 3 #define CFE_SB_Q_WR_ERR_EID_BIT 4 -/* - * Using the default configuration where there is a 1:1 mapping between MsgID - * and message key values, the number of keys is equal to the number of MsgIDs. - * - * If using an alternative key function / hash, this may change. - */ -#define CFE_SB_MAX_NUMBER_OF_MSG_KEYS (1+CFE_PLATFORM_SB_HIGHEST_VALID_MSGID) /* ** Type Definitions */ - -/****************************************************************************** -** Typedef: CFE_SB_MsgKey_Atom_t -** -** Purpose: -** Defines the an integer type for the numeric key that is used for routing -** table lookups. This is the "raw value" type and typically should not -** be used directly, except by internal table lookups. -** -*/ -typedef uint32 CFE_SB_MsgKey_Atom_t; - -/****************************************************************************** -** Typedef: CFE_SB_MsgKey_t -** -** Purpose: -** This is a "holding structure" for the related integer CFE_SB_MsgKey_Atom_t values. -** This defines the data type that is stored in other structures and/or passed between -** software bus functions. -** -** It is implemented this way to improve type safety and help ensure that "MsgKey" -** values are not inadvertently exchanged with MsgId or Routing Index values. -** -*/ -typedef struct -{ - CFE_SB_MsgKey_Atom_t KeyIdx; /**< Holding value, do not use directly */ -} CFE_SB_MsgKey_t; - -/******************************************************************************/ -/** - * @brief An wrapper for holding a routing table index - * - * This is intended as a form of "strong typedef" where direct assignments should - * be restricted. Software bus uses numeric indexes into multiple tables to perform - * its duties, and it is important that these index values are distinct and separate - * and not mixed together. - * - * Using this holding structure prevents assignment directly into a different index - * or direct usage as numeric value. - */ -typedef struct -{ - CFE_SB_MsgRouteIdx_Atom_t RouteIdx; /**< Holding value, do not use directly in code */ -} CFE_SB_MsgRouteIdx_t; - - /****************************************************************************** ** Typedef: CFE_SB_BufferD_t ** @@ -174,31 +120,6 @@ typedef struct { void *Buffer; } CFE_SB_BufferD_t; - -/****************************************************************************** -** Typedef: CFE_SB_DestinationD_t -** -** Purpose: -** This structure defines a DESTINATION DESCRIPTOR used to specify -** each destination pipe for a message. -** -** Note: Changing the size of this structure may require the memory pool -** block sizes to change. -*/ - -typedef struct { - CFE_SB_PipeId_t PipeId; - uint8 Active; - uint16 MsgId2PipeLim; - uint16 BuffCount; - uint16 DestCnt; - uint8 Scope; - uint8 Spare[3]; - void *Prev; - void *Next; -} CFE_SB_DestinationD_t; - - /****************************************************************************** ** Typedef: CFE_SB_ZeroCopyD_t ** @@ -218,22 +139,6 @@ typedef struct { void *Prev; } CFE_SB_ZeroCopyD_t; - -/****************************************************************************** -** Typedef: CFE_SB_RouteEntry_t -** -** Purpose: -** This structure defines an entry in the routing table -*/ - -typedef struct { - CFE_SB_MsgId_t MsgId; /**< Original Message Id when the subscription was created */ - uint16 Destinations; - uint32 SeqCnt; - CFE_SB_DestinationD_t *ListHeadPtr; -} CFE_SB_RouteEntry_t; - - /****************************************************************************** ** Typedef: CFE_SB_PipeD_t ** @@ -257,8 +162,6 @@ typedef struct { CFE_SB_BufferD_t *ToTrashBuff; } CFE_SB_PipeD_t; - - /****************************************************************************** ** Typedef: CFE_SB_BufParams_t ** @@ -279,29 +182,24 @@ typedef struct { ** Purpose: ** This structure contains the SB global variables. */ -typedef struct { - osal_id_t SharedDataMutexId; - uint32 SubscriptionReporting; - uint32 SenderReporting; - CFE_ES_ResourceID_t AppId; - uint32 StopRecurseFlags[OS_MAX_TASKS]; - void *ZeroCopyTail; - CFE_SB_PipeD_t PipeTbl[CFE_PLATFORM_SB_MAX_PIPES]; - CFE_SB_HousekeepingTlm_t HKTlmMsg; - CFE_SB_StatsTlm_t StatTlmMsg; - CFE_SB_PipeId_t CmdPipe; - CFE_SB_Msg_t *CmdPipePktPtr; - CFE_SB_MemParams_t Mem; - CFE_SB_MsgRouteIdx_t MsgMap[CFE_SB_MAX_NUMBER_OF_MSG_KEYS]; - CFE_SB_RouteEntry_t RoutingTbl[CFE_PLATFORM_SB_MAX_MSG_IDS]; - CFE_SB_AllSubscriptionsTlm_t PrevSubMsg; - CFE_SB_SingleSubscriptionTlm_t SubRprtMsg; - CFE_EVS_BinFilter_t EventFilters[CFE_SB_MAX_CFG_FILE_EVENTS_TO_FILTER]; - - uint16 RouteIdxTop; - CFE_SB_MsgRouteIdx_t RouteIdxStack[CFE_PLATFORM_SB_MAX_MSG_IDS]; - -}cfe_sb_t; +typedef struct +{ + osal_id_t SharedDataMutexId; + uint32 SubscriptionReporting; + uint32 SenderReporting; + CFE_ES_ResourceID_t AppId; + uint32 StopRecurseFlags[OS_MAX_TASKS]; + void *ZeroCopyTail; + CFE_SB_PipeD_t PipeTbl[CFE_PLATFORM_SB_MAX_PIPES]; + CFE_SB_HousekeepingTlm_t HKTlmMsg; + CFE_SB_StatsTlm_t StatTlmMsg; + CFE_SB_PipeId_t CmdPipe; + CFE_SB_Msg_t *CmdPipePktPtr; + CFE_SB_MemParams_t Mem; + CFE_SB_AllSubscriptionsTlm_t PrevSubMsg; + CFE_SB_SingleSubscriptionTlm_t SubRprtMsg; + CFE_EVS_BinFilter_t EventFilters[CFE_SB_MAX_CFG_FILE_EVENTS_TO_FILTER]; +} cfe_sb_t; /****************************************************************************** @@ -336,13 +234,8 @@ typedef struct{ int32 CFE_SB_AppInit(void); int32 CFE_SB_InitBuffers(void); void CFE_SB_InitPipeTbl(void); -void CFE_SB_InitMsgMap(void); -void CFE_SB_InitRoutingTbl(void); void CFE_SB_InitIdxStack(void); void CFE_SB_ResetCounts(void); -void CFE_SB_RouteIdxPush_Unsync(CFE_SB_MsgRouteIdx_t idx); -CFE_SB_MsgRouteIdx_t CFE_SB_RouteIdxPop_Unsync(void); -CFE_SB_MsgKey_t CFE_SB_ConvertMsgIdtoMsgKey(CFE_SB_MsgId_t MsgId); void CFE_SB_LockSharedData(const char *FuncName, int32 LineNumber); void CFE_SB_UnlockSharedData(const char *FuncName, int32 LineNumber); void CFE_SB_ReleaseBuffer (CFE_SB_BufferD_t *bd, CFE_SB_DestinationD_t *dest); @@ -350,13 +243,9 @@ int32 CFE_SB_ReadQueue(CFE_SB_PipeD_t *PipeDscPtr,CFE_ES_ResourceID_t TskId, CFE_SB_TimeOut_t Time_Out,CFE_SB_BufferD_t **Message ); int32 CFE_SB_WriteQueue(CFE_SB_PipeD_t *pd,uint32 TskId, const CFE_SB_BufferD_t *bd,CFE_SB_MsgId_t MsgId ); -CFE_SB_MsgRouteIdx_t CFE_SB_GetRoutingTblIdx(CFE_SB_MsgKey_t MsgKey); uint8 CFE_SB_GetPipeIdx(CFE_SB_PipeId_t PipeId); int32 CFE_SB_ReturnBufferToPool(CFE_SB_BufferD_t *bd); void CFE_SB_ProcessCmdPipePkt(void); -int32 CFE_SB_DuplicateSubscribeCheck(CFE_SB_MsgKey_t MsgKey,CFE_SB_PipeId_t PipeId); -void CFE_SB_SetRoutingTblIdx(CFE_SB_MsgKey_t MsgKey, CFE_SB_MsgRouteIdx_t Value); -CFE_SB_RouteEntry_t* CFE_SB_GetRoutePtrFromIdx(CFE_SB_MsgRouteIdx_t RouteIdx); void CFE_SB_ResetCounters(void); void CFE_SB_SetMsgSeqCnt(CFE_SB_MsgPtr_t MsgPtr,uint32 Count); char *CFE_SB_GetAppTskName(CFE_ES_ResourceID_t TaskId, char* FullName); @@ -364,7 +253,6 @@ CFE_SB_BufferD_t *CFE_SB_GetBufferFromPool(CFE_SB_MsgId_t MsgId, uint16 Size); CFE_SB_BufferD_t *CFE_SB_GetBufferFromCaller(CFE_SB_MsgId_t MsgId, void *Address); CFE_SB_PipeD_t *CFE_SB_GetPipePtr(CFE_SB_PipeId_t PipeId); CFE_SB_PipeId_t CFE_SB_GetAvailPipeIdx(void); -CFE_SB_DestinationD_t *CFE_SB_GetDestPtr (CFE_SB_MsgKey_t MsgKey, CFE_SB_PipeId_t PipeId); int32 CFE_SB_DeletePipeWithAppId(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId); int32 CFE_SB_DeletePipeFull(CFE_SB_PipeId_t PipeId,CFE_ES_ResourceID_t AppId); int32 CFE_SB_SubscribeFull(CFE_SB_MsgId_t MsgId, @@ -390,14 +278,60 @@ int32 CFE_SB_ValidatePipeId(CFE_SB_PipeId_t PipeId); void CFE_SB_IncrCmdCtr(int32 status); void CFE_SB_FileWriteByteCntErr(const char *Filename,uint32 Requested,uint32 Actual); void CFE_SB_SetSubscriptionReporting(uint32 state); -uint32 CFE_SB_FindGlobalMsgIdCnt(void); uint32 CFE_SB_RequestToSendEvent(CFE_ES_ResourceID_t TaskId, uint32 Bit); void CFE_SB_FinishSendEvent(CFE_ES_ResourceID_t TaskId, uint32 Bit); CFE_SB_DestinationD_t *CFE_SB_GetDestinationBlk(void); int32 CFE_SB_PutDestinationBlk(CFE_SB_DestinationD_t *Dest); -int32 CFE_SB_AddDest(CFE_SB_RouteEntry_t *RouteEntry, CFE_SB_DestinationD_t *NewNode); -int32 CFE_SB_RemoveDest(CFE_SB_RouteEntry_t *RouteEntry, CFE_SB_DestinationD_t *NodeToRemove); +/** + * \brief Add a destination node + * + * Private function that will add a destination node to the linked list + * + * \note Assumes destination pointer is valid + * + * \param[in] RouteId The route ID to add destination node to + * \param[in] DestPtr Pointer to the destination to add + */ +int32 CFE_SB_AddDestNode(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *NewNode); + +/** + * \brief Remove a destination node + * + * Private function that will remove a destination node from the linked list + * + * \note Assumes destination pointer is valid and in route + * + * \param[in] RouteId The route ID to remove destination node from + * \param[in] DestPtr Pointer to the destination to remove + */ +void CFE_SB_RemoveDestNode(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *NodeToRemove); + +/** + * \brief Remove a destination + * + * Private function that will remove a destination by removing the node, + * returning the block, and decrementing counters + * + * \note Assumes destination pointer is valid and in route + * + * \param[in] RouteId The route ID to remove destination from + * \param[in] DestPtr Pointer to the destination to remove + */ +void CFE_SB_RemoveDest(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *DestPtr); + +/** + * \brief Get destination pointer for PipeId from RouteId + * + * Private function that will return the destination pointer related to the + * given PipeId and RouteId if it exists + * + * \param[in] RouteId The route ID to search + * \param[in] PipeId The pipe ID to search for + * + * \returns Then destination pointer for a match, NULL otherwise + */ +CFE_SB_DestinationD_t *CFE_SB_GetDestPtr(CFE_SBR_RouteId_t RouteId, CFE_SB_PipeId_t PipeId); /*****************************************************************************/ /** @@ -452,101 +386,5 @@ int32 CFE_SB_SendPrevSubsCmd(const CFE_SB_SendPrevSubs_t *data); extern cfe_sb_t CFE_SB; - - -/* --------------------------------------------------------- - * HELPER FUNCTIONS FOR TYPE-SAFE WRAPPERS / HOLDING STRUCTS - * - * These functions implement the type conversions between "bare numbers" and - * the holding structures, as well as sanity tests for the holding structures. - * - * The data within the holding structures should never be directly in the app, - * one of these helpers should be used once it is verified that the conversion - * or use case is legitimate. - * --------------------------------------------------------- */ - -/** - * @brief Identifies whether a given CFE_SB_MsgKey_t is valid - * - * Implements a basic sanity check on the value provided - * - * @returns true if sanity checks passed, false otherwise. - */ -static inline bool CFE_SB_IsValidMsgKey(CFE_SB_MsgKey_t MsgKey) -{ - return (MsgKey.KeyIdx != 0 && MsgKey.KeyIdx <= CFE_SB_MAX_NUMBER_OF_MSG_KEYS); -} - -/** - * @brief Identifies whether a given CFE_SB_MsgRouteIdx_t is valid - * - * Implements a basic sanity check on the value provided - * - * @returns true if sanity checks passed, false otherwise. - */ -static inline bool CFE_SB_IsValidRouteIdx(CFE_SB_MsgRouteIdx_t RouteIdx) -{ - return (RouteIdx.RouteIdx != 0 && RouteIdx.RouteIdx <= CFE_PLATFORM_SB_MAX_MSG_IDS); -} - -/** - * @brief Converts between a CFE_SB_MsgKey_t and a raw value - * - * Converts the supplied value into a "bare number" suitable for performing - * array lookups or other tasks for which the holding structure cannot be used directly. - * - * Use with caution, as this removes the type safety information from the value. - * - * @note It is assumed the value has already been validated using CFE_SB_IsValidMsgKey() - * - * @returns The underlying index value - */ -static inline CFE_SB_MsgKey_Atom_t CFE_SB_MsgKeyToValue(CFE_SB_MsgKey_t MsgKey) -{ - return (MsgKey.KeyIdx - 1); -} - -/** - * @brief Converts between a CFE_SB_MsgKey_t and a raw value - * - * Converts the supplied "bare number" into a type-safe CFE_SB_MsgKey_t value - * - * @returns A CFE_SB_MsgKey_t value - */ -static inline CFE_SB_MsgKey_t CFE_SB_ValueToMsgKey(CFE_SB_MsgKey_Atom_t KeyIdx) -{ - return ((CFE_SB_MsgKey_t){ .KeyIdx = 1 + KeyIdx }); -} - -/** - * @brief Converts between a CFE_SB_MsgRouteIdx_t and a raw value - * - * Converts the supplied "bare number" into a type-safe CFE_SB_MsgRouteIdx_t value - * - * @returns A CFE_SB_MsgRouteIdx_t value - */ -static inline CFE_SB_MsgRouteIdx_t CFE_SB_ValueToRouteIdx(CFE_SB_MsgRouteIdx_Atom_t TableIdx) -{ - return ((CFE_SB_MsgRouteIdx_t){ .RouteIdx = 1 + TableIdx }); -} - -/** - * @brief Converts between a CFE_SB_MsgRouteIdx_t and a raw value - * - * Converts the supplied value into a "bare number" suitable for performing - * array lookups or other tasks for which the holding structure cannot be used directly. - * - * Use with caution, as this removes the type safety information from the value. - * - * @note It is assumed the value has already been validated using CFE_SB_IsValidRouteIdx() - * - * @returns The underlying index value - */ -static inline CFE_SB_MsgRouteIdx_Atom_t CFE_SB_RouteIdxToValue(CFE_SB_MsgRouteIdx_t RouteIdx) -{ - return (RouteIdx.RouteIdx - 1); -} - - #endif /* _cfe_sb_priv_ */ /*****************************************************************************/ diff --git a/fsw/cfe-core/src/sb/cfe_sb_task.c b/fsw/cfe-core/src/sb/cfe_sb_task.c index 3ead76756..97c587186 100644 --- a/fsw/cfe-core/src/sb/cfe_sb_task.c +++ b/fsw/cfe-core/src/sb/cfe_sb_task.c @@ -48,6 +48,15 @@ cfe_sb_t CFE_SB; CFE_SB_Qos_t CFE_SB_Default_Qos; +/* Local structure for file writing callbacks */ +typedef struct +{ + const char *Filename; /* File name for error reporting */ + osal_id_t Fd; /* File id for writing */ + uint32 FileSize; /* File size for reporting */ + uint32 EntryCount; /* Entry count for reporting */ + int32 Status; /* File write status */ +} CFE_SB_FileWriteCallback_t; /****************************************************************************** ** Function: CFE_SB_TaskMain() @@ -638,7 +647,7 @@ int32 CFE_SB_EnableRouteCmd(const CFE_SB_EnableRoute_t *data) return CFE_SUCCESS; }/* end if */ - DestPtr = CFE_SB_GetDestPtr(CFE_SB_ConvertMsgIdtoMsgKey(MsgId), PipeId); + DestPtr = CFE_SB_GetDestPtr(CFE_SBR_GetRouteId(MsgId), PipeId); if(DestPtr == NULL){ CFE_EVS_SendEvent(CFE_SB_ENBL_RTE1_EID,CFE_EVS_EventType_ERROR, "Enbl Route Cmd:Route does not exist.Msg 0x%x,Pipe %d", @@ -702,7 +711,7 @@ int32 CFE_SB_DisableRouteCmd(const CFE_SB_DisableRoute_t *data) return CFE_SUCCESS; }/* end if */ - DestPtr = CFE_SB_GetDestPtr(CFE_SB_ConvertMsgIdtoMsgKey(MsgId), PipeId); + DestPtr = CFE_SB_GetDestPtr(CFE_SBR_GetRouteId(MsgId), PipeId); if(DestPtr == NULL){ CFE_EVS_SendEvent(CFE_SB_DSBL_RTE1_EID,CFE_EVS_EventType_ERROR, "Disable Route Cmd:Route does not exist,Msg 0x%x,Pipe %d", @@ -843,6 +852,61 @@ int32 CFE_SB_SendMapInfoCmd(const CFE_SB_SendMapInfo_t *data) return CFE_SUCCESS; }/* end CFE_SB_SendMapInfoCmd */ +/****************************************************************************** + * Local callback helper for writing routing info to a file + */ +void CFE_SB_WriteRouteToFile(CFE_SBR_RouteId_t RouteId, void *ArgPtr) +{ + CFE_SB_FileWriteCallback_t *args; + CFE_SB_DestinationD_t *destptr; + CFE_SB_PipeD_t *pipedptr; + int32 status; + CFE_SB_RoutingFileEntry_t entry; + + /* Cast arguments for local use */ + args = (CFE_SB_FileWriteCallback_t *)ArgPtr; + + destptr = CFE_SBR_GetDestListHeadPtr(RouteId); + + while((destptr != NULL) && (args->Status != CFE_SB_FILE_IO_ERR)) + { + + pipedptr = CFE_SB_GetPipePtr(destptr->PipeId); + + /* If invalid id, continue on to next entry */ + if (pipedptr != NULL) + { + + entry.MsgId = CFE_SBR_GetMsgId(RouteId); + entry.PipeId = destptr->PipeId; + entry.State = destptr->Active; + entry.MsgCnt = destptr->DestCnt; + + entry.AppName[0] = 0; + /* + * NOTE: as long as CFE_ES_GetAppName() returns success, then it + * guarantees null termination of the output. Return code is not + * checked here (bad) but in case of error it does not seem to touch + * the buffer, therefore the initialization above will protect for now + */ + CFE_ES_GetAppName(entry.AppName, pipedptr->AppId, sizeof(entry.AppName)); + CFE_SB_GetPipeName(entry.PipeName, sizeof(entry.PipeName), entry.PipeId); + + status = OS_write (args->Fd, &entry, sizeof(CFE_SB_RoutingFileEntry_t)); + if(status != sizeof(CFE_SB_RoutingFileEntry_t)) + { + CFE_SB_FileWriteByteCntErr(args->Filename, sizeof(CFE_SB_RoutingFileEntry_t), status); + OS_close(args->Fd); + args->Status = CFE_SB_FILE_IO_ERR; + } + + args->FileSize += status; + args->EntryCount++; + } + + destptr = destptr->Next; + } +} /****************************************************************************** ** Function: CFE_SB_SendRoutingInfo() @@ -858,103 +922,49 @@ int32 CFE_SB_SendMapInfoCmd(const CFE_SB_SendMapInfo_t *data) */ int32 CFE_SB_SendRtgInfo(const char *Filename) { - CFE_SB_MsgRouteIdx_t RtgTblIdx; - const CFE_SB_RouteEntry_t* RtgTblPtr; - CFE_SB_MsgKey_Atom_t MsgKeyVal; - osal_id_t fd; + CFE_SB_FileWriteCallback_t args = {0}; int32 Status; - uint32 FileSize = 0; - uint32 EntryCount = 0; - CFE_SB_RoutingFileEntry_t Entry; CFE_FS_Header_t FileHdr; - CFE_SB_PipeD_t *pd; - CFE_SB_DestinationD_t *DestPtr; - Status = OS_OpenCreate(&fd, Filename, - OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY); - if(Status < OS_SUCCESS){ - CFE_EVS_SendEvent(CFE_SB_SND_RTG_ERR1_EID,CFE_EVS_EventType_ERROR, + Status = OS_OpenCreate(&args.Fd, Filename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY); + if(Status < OS_SUCCESS) + { + CFE_EVS_SendEvent(CFE_SB_SND_RTG_ERR1_EID, CFE_EVS_EventType_ERROR, "Error creating file %s, stat=0x%x", - Filename,(unsigned int)Status); + Filename, (unsigned int)Status); return CFE_SB_FILE_IO_ERR; - }/* end if */ + } /* clear out the cfe file header fields, then populate description and subtype */ CFE_FS_InitHeader(&FileHdr, "SB Routing Information", CFE_FS_SubType_SB_ROUTEDATA); - Status = CFE_FS_WriteHeader(fd, &FileHdr); - if(Status != sizeof(CFE_FS_Header_t)){ + Status = CFE_FS_WriteHeader(args.Fd, &FileHdr); + if(Status != sizeof(CFE_FS_Header_t)) + { CFE_SB_FileWriteByteCntErr(Filename,sizeof(CFE_FS_Header_t),Status); - OS_close(fd); + OS_close(args.Fd); return CFE_SB_FILE_IO_ERR; - }/* end if */ - - FileSize = Status; - - /* loop through the entire MsgMap */ - for(MsgKeyVal=0; MsgKeyVal < CFE_SB_MAX_NUMBER_OF_MSG_KEYS; ++MsgKeyVal) - { - RtgTblIdx = CFE_SB.MsgMap[MsgKeyVal]; - - /* Only process table entry if it is used. */ - if(!CFE_SB_IsValidRouteIdx(RtgTblIdx)) - { - DestPtr = NULL; - RtgTblPtr = NULL; - } - else - { - RtgTblPtr = CFE_SB_GetRoutePtrFromIdx(RtgTblIdx); - DestPtr = RtgTblPtr->ListHeadPtr; - } - - while(DestPtr != NULL){ - - pd = CFE_SB_GetPipePtr(DestPtr -> PipeId); - /* If invalid id, continue on to next entry */ - if (pd != NULL) { - - Entry.MsgId = RtgTblPtr->MsgId; - Entry.PipeId = DestPtr -> PipeId; - Entry.State = DestPtr -> Active; - Entry.MsgCnt = DestPtr -> DestCnt; - - Entry.AppName[0] = 0; - /* - * NOTE: as long as CFE_ES_GetAppName() returns success, then it - * guarantees null termination of the output. Return code is not - * checked here (bad) but in case of error it does not seem to touch - * the buffer, therefore the initialization above will protect for now - */ - CFE_ES_GetAppName(&Entry.AppName[0], pd->AppId, sizeof(Entry.AppName)); - CFE_SB_GetPipeName(Entry.PipeName, sizeof(Entry.PipeName), Entry.PipeId); - - Status = OS_write (fd, &Entry, sizeof(CFE_SB_RoutingFileEntry_t)); - if(Status != sizeof(CFE_SB_RoutingFileEntry_t)){ - CFE_SB_FileWriteByteCntErr(Filename, - sizeof(CFE_SB_RoutingFileEntry_t), - Status); - OS_close(fd); - return CFE_SB_FILE_IO_ERR; - }/* end if */ - - FileSize += Status; - EntryCount ++; - } - - DestPtr = DestPtr->Next; - - }/* end while */ - - }/* end for */ + } - OS_close(fd); + /* Initialize the reset of the nonzero callback argument elements */ + args.FileSize = Status; + args.Filename = Filename; - CFE_EVS_SendEvent(CFE_SB_SND_RTG_EID,CFE_EVS_EventType_DEBUG, - "%s written:Size=%d,Entries=%d", - Filename,(int)FileSize,(int)EntryCount); + /* Write route info to file */ + CFE_SBR_ForEachRouteId(CFE_SB_WriteRouteToFile, &args, NULL); - return CFE_SUCCESS; + if (args.Status != 0) + { + return args.Status; + } + else + { + OS_close(args.Fd); + CFE_EVS_SendEvent(CFE_SB_SND_RTG_EID,CFE_EVS_EventType_DEBUG, + "%s written:Size=%d,Entries=%d", + Filename, (int)args.FileSize, (int)args.EntryCount); + return CFE_SUCCESS; + } }/* end CFE_SB_SendRtgInfo */ @@ -1031,6 +1041,36 @@ int32 CFE_SB_SendPipeInfo(const char *Filename) }/* end CFE_SB_SendPipeInfo */ +/****************************************************************************** + * Local callback helper for writing map info to a file + */ +void CFE_SB_WriteMapToFile(CFE_SBR_RouteId_t RouteId, void *ArgPtr) +{ + CFE_SB_FileWriteCallback_t *args; + int32 status; + CFE_SB_MsgMapFileEntry_t entry; + + /* Cast arguments for local use */ + args = (CFE_SB_FileWriteCallback_t *)ArgPtr; + + if(args->Status != CFE_SB_FILE_IO_ERR) + { + entry.MsgId = CFE_SBR_GetMsgId(RouteId); + entry.Index = CFE_SBR_RouteIdToValue(RouteId); + + status = OS_write (args->Fd, &entry, sizeof(CFE_SB_MsgMapFileEntry_t)); + if(status != sizeof(CFE_SB_MsgMapFileEntry_t)) + { + CFE_SB_FileWriteByteCntErr(args->Filename, sizeof(CFE_SB_MsgMapFileEntry_t), status); + OS_close(args->Fd); + args->Status = CFE_SB_FILE_IO_ERR; + } + + args->FileSize += status; + args->EntryCount++; + } +} + /****************************************************************************** ** Function: CFE_SB_SendMapInfo() ** @@ -1045,73 +1085,103 @@ int32 CFE_SB_SendPipeInfo(const char *Filename) */ int32 CFE_SB_SendMapInfo(const char *Filename) { - const CFE_SB_RouteEntry_t* RtgTblPtr; - CFE_SB_MsgRouteIdx_t RtgTblIdx; - CFE_SB_MsgKey_Atom_t MsgKeyVal; - osal_id_t fd; - int32 Status; - uint32 FileSize = 0; - uint32 EntryCount = 0; - CFE_SB_MsgMapFileEntry_t Entry; - CFE_FS_Header_t FileHdr; + CFE_SB_FileWriteCallback_t args = {0}; + int32 Status; + CFE_FS_Header_t FileHdr; - Status = OS_OpenCreate(&fd, Filename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY); + Status = OS_OpenCreate(&args.Fd, Filename, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY); - if (Status < OS_SUCCESS){ - CFE_EVS_SendEvent(CFE_SB_SND_RTG_ERR1_EID,CFE_EVS_EventType_ERROR, + if (Status < OS_SUCCESS) + { + CFE_EVS_SendEvent(CFE_SB_SND_RTG_ERR1_EID, CFE_EVS_EventType_ERROR, "Error creating file %s, stat=0x%x", - Filename,(unsigned int)Status); + Filename, (unsigned int)Status); return CFE_SB_FILE_IO_ERR; - }/* end if */ + } /* clear out the cfe file header fields, then populate description and subtype */ CFE_FS_InitHeader(&FileHdr, "SB Message Map Information", CFE_FS_SubType_SB_MAPDATA); - Status = CFE_FS_WriteHeader(fd, &FileHdr); - if(Status != sizeof(CFE_FS_Header_t)){ - CFE_SB_FileWriteByteCntErr(Filename,sizeof(CFE_FS_Header_t),Status); - OS_close(fd); - return CFE_SB_FILE_IO_ERR; - }/* end if */ - - FileSize = Status; - - /* loop through the entire MsgMap */ - for(MsgKeyVal=0; MsgKeyVal < CFE_SB_MAX_NUMBER_OF_MSG_KEYS; ++MsgKeyVal) + Status = CFE_FS_WriteHeader(args.Fd, &FileHdr); + if(Status != sizeof(CFE_FS_Header_t)) { - RtgTblIdx = CFE_SB_GetRoutingTblIdx(CFE_SB_ValueToMsgKey(MsgKeyVal)); + CFE_SB_FileWriteByteCntErr(Filename, sizeof(CFE_FS_Header_t), Status); + OS_close(args.Fd); + return CFE_SB_FILE_IO_ERR; + } - if(CFE_SB_IsValidRouteIdx(RtgTblIdx)) - { - RtgTblPtr = CFE_SB_GetRoutePtrFromIdx(RtgTblIdx); + /* Initialize the reset of the nonzero callback argument elements */ + args.FileSize = Status; + args.Filename = Filename; - Entry.MsgId = RtgTblPtr->MsgId; - Entry.Index = CFE_SB_RouteIdxToValue(RtgTblIdx); + /* Write route info to file */ + CFE_SBR_ForEachRouteId(CFE_SB_WriteMapToFile, &args, NULL); - Status = OS_write (fd, &Entry, sizeof(CFE_SB_MsgMapFileEntry_t)); - if(Status != sizeof(CFE_SB_MsgMapFileEntry_t)){ - CFE_SB_FileWriteByteCntErr(Filename,sizeof(CFE_SB_MsgMapFileEntry_t),Status); - OS_close(fd); - return CFE_SB_FILE_IO_ERR; - }/* end if */ + if (args.Status != 0) + { + return args.Status; + } + else + { + OS_close(args.Fd); + CFE_EVS_SendEvent(CFE_SB_SND_RTG_EID, CFE_EVS_EventType_DEBUG, + "%s written:Size=%d,Entries=%d", + Filename, (int)args.FileSize, (int)args.EntryCount); + return CFE_SUCCESS; + } +} - FileSize += Status; - EntryCount ++; +/****************************************************************************** + * Local callback helper for sending route subscriptions + */ +void CFE_SB_SendRouteSub(CFE_SBR_RouteId_t RouteId, void *ArgPtr) +{ + CFE_SB_DestinationD_t *destptr; + int32 status; - }/* end for */ - }/* end for */ + destptr = CFE_SBR_GetDestListHeadPtr(RouteId); - OS_close(fd); + /* Loop through destinations */ + while(destptr != NULL) + { - CFE_EVS_SendEvent(CFE_SB_SND_RTG_EID,CFE_EVS_EventType_DEBUG, - "%s written:Size=%d,Entries=%d", - Filename,(int)FileSize,(int)EntryCount); + if(destptr->Scope == CFE_SB_GLOBAL) + { - return CFE_SUCCESS; + /* ...add entry into pkt */ + CFE_SB.PrevSubMsg.Payload.Entry[CFE_SB.PrevSubMsg.Payload.Entries].MsgId = CFE_SBR_GetMsgId(RouteId); + CFE_SB.PrevSubMsg.Payload.Entry[CFE_SB.PrevSubMsg.Payload.Entries].Qos.Priority = 0; + CFE_SB.PrevSubMsg.Payload.Entry[CFE_SB.PrevSubMsg.Payload.Entries].Qos.Reliability = 0; + CFE_SB.PrevSubMsg.Payload.Entries++; + + /* send pkt if full */ + if(CFE_SB.PrevSubMsg.Payload.Entries >= CFE_SB_SUB_ENTRIES_PER_PKT) + { + CFE_SB_UnlockSharedData(__func__,__LINE__); + status = CFE_SB_SendMsg((CFE_SB_Msg_t *)&CFE_SB.PrevSubMsg); + CFE_EVS_SendEvent(CFE_SB_FULL_SUB_PKT_EID, CFE_EVS_EventType_DEBUG, + "Full Sub Pkt %d Sent,Entries=%d,Stat=0x%x\n", + (int)CFE_SB.PrevSubMsg.Payload.PktSegment, + (int)CFE_SB.PrevSubMsg.Payload.Entries, (unsigned int)status); + CFE_SB_LockSharedData(__func__,__LINE__); + CFE_SB.PrevSubMsg.Payload.Entries = 0; + CFE_SB.PrevSubMsg.Payload.PktSegment++; + } -}/* end CFE_SB_SendMapInfo */ + /* + * break while loop through destinations, onto next route + * This is done because we want only one network subscription per msgid + * Later when Qos is used, we may want to take just the highest priority + * subscription if there are more than one + */ + break; + } + /* Advance to next destination */ + destptr = destptr->Next; + } +} /****************************************************************************** ** Function: CFE_SB_SendPrevSubsCmd() @@ -1129,140 +1199,32 @@ int32 CFE_SB_SendMapInfo(const char *Filename) */ int32 CFE_SB_SendPrevSubsCmd(const CFE_SB_SendPrevSubs_t *data) { - CFE_SB_MsgRouteIdx_Atom_t i; - const CFE_SB_RouteEntry_t* RoutePtr; - uint32 EntryNum = 0; - uint32 SegNum = 1; - int32 Stat; - CFE_SB_DestinationD_t *DestPtr = NULL; - - /* Take semaphore to ensure data does not change during this function */ - CFE_SB_LockSharedData(__func__,__LINE__); - - /* seek msgids that are in use */ - for(i=0;iMsgId)) - { - DestPtr = NULL; - } - else - { - DestPtr = CFE_SB.RoutingTbl[i].ListHeadPtr; - } - - while(DestPtr != NULL){ - - if(DestPtr->Scope == CFE_SB_GLOBAL){ - - /* ...add entry into pkt */ - CFE_SB.PrevSubMsg.Payload.Entry[EntryNum].MsgId = RoutePtr->MsgId; - CFE_SB.PrevSubMsg.Payload.Entry[EntryNum].Qos.Priority = 0; - CFE_SB.PrevSubMsg.Payload.Entry[EntryNum].Qos.Reliability = 0; - EntryNum++; - - /* send pkt if full */ - if(EntryNum >= CFE_SB_SUB_ENTRIES_PER_PKT){ - CFE_SB.PrevSubMsg.Payload.PktSegment = SegNum; - CFE_SB.PrevSubMsg.Payload.Entries = EntryNum; - CFE_SB_UnlockSharedData(__func__,__LINE__); - Stat = CFE_SB_SendMsg((CFE_SB_Msg_t *)&CFE_SB.PrevSubMsg); - CFE_SB_LockSharedData(__func__,__LINE__); - CFE_EVS_SendEvent(CFE_SB_FULL_SUB_PKT_EID,CFE_EVS_EventType_DEBUG, - "Full Sub Pkt %d Sent,Entries=%d,Stat=0x%x\n",(int)SegNum,(int)EntryNum,(unsigned int)Stat); - EntryNum = 0; - SegNum++; - }/* end if */ - - /* break while loop through destinations, onto next CFE_SB.RoutingTbl index */ - /* This is done because we want only one network subscription per msgid */ - /* Later when Qos is used, we may want to take just the highest priority */ - /* subscription if there are more than one */ - break; - - }/* end if */ - - /* Check next destination (if another exists) for global scope */ - DestPtr = DestPtr -> Next; - - }/* end while */ - - }/* end for */ - - /* if pkt has any number of entries, send it as a partial pkt */ - if(EntryNum > 0){ - CFE_SB.PrevSubMsg.Payload.PktSegment = SegNum; - CFE_SB.PrevSubMsg.Payload.Entries = EntryNum; - CFE_SB_UnlockSharedData(__func__,__LINE__); - Stat = CFE_SB_SendMsg((CFE_SB_Msg_t *)&CFE_SB.PrevSubMsg); - CFE_SB_LockSharedData(__func__,__LINE__); - CFE_EVS_SendEvent(CFE_SB_PART_SUB_PKT_EID,CFE_EVS_EventType_DEBUG, - "Partial Sub Pkt %d Sent,Entries=%d,Stat=0x%x",(int)SegNum,(int)EntryNum,(unsigned int)Stat); - }/* end if */ + int32 status; - CFE_SB_UnlockSharedData(__func__,__LINE__); + /* Take semaphore to ensure data does not change during this function */ + CFE_SB_LockSharedData(__func__,__LINE__); - return CFE_SUCCESS; -}/* end CFE_SB_SendPrevSubsCmd */ + /* Initialize entry/segment tracking */ + CFE_SB.PrevSubMsg.Payload.PktSegment = 1; + CFE_SB.PrevSubMsg.Payload.Entries = 0; + /* Send subcription for each route */ + CFE_SBR_ForEachRouteId(CFE_SB_SendRouteSub, NULL, NULL); -/****************************************************************************** -** Function: CFE_SB_FindGlobalMsgIdCnt() -** -** Purpose: -** SB internal function to get a count of the global message ids in use. -** -** Notes: -** Subscriptions made with CFE_SB_SubscribeLocal would not be counted. -** Subscription made with a subscribe API other than CFE_SB_SubscribeLocal are -** considerd to be global subscriptions. MsgIds with both global and local -** subscriptions would be counted. -** -** Arguments: -** -** Return: -** None -*/ -uint32 CFE_SB_FindGlobalMsgIdCnt(void){ + CFE_SB_UnlockSharedData(__func__,__LINE__); - CFE_SB_MsgRouteIdx_Atom_t i; - uint32 cnt = 0; - const CFE_SB_RouteEntry_t* RoutePtr; - CFE_SB_DestinationD_t *DestPtr = NULL; - - for(i=0;i 0) { - RoutePtr = CFE_SB_GetRoutePtrFromIdx(CFE_SB_ValueToRouteIdx(i)); - if(!CFE_SB_IsValidMsgId(RoutePtr->MsgId)) - { - DestPtr = NULL; - } - else - { - DestPtr = RoutePtr->ListHeadPtr; - } - - while(DestPtr != NULL){ - - if(DestPtr->Scope == CFE_SB_GLOBAL){ - - cnt++; - break; - - }/* end if */ - - /* Check next destination (if another exists) for global scope */ - DestPtr = DestPtr -> Next; - - }/* end while */ - - }/* end for */ - - return cnt; - -}/* end CFE_SB_FindGlobalMsgIdCnt */ + status = CFE_SB_SendMsg((CFE_SB_Msg_t *)&CFE_SB.PrevSubMsg); + CFE_EVS_SendEvent(CFE_SB_PART_SUB_PKT_EID, CFE_EVS_EventType_DEBUG, + "Partial Sub Pkt %d Sent,Entries=%d,Stat=0x%x", + (int)CFE_SB.PrevSubMsg.Payload.PktSegment, (int)CFE_SB.PrevSubMsg.Payload.Entries, + (unsigned int)status); + } + return CFE_SUCCESS; +}/* end CFE_SB_SendPrevSubsCmd */ diff --git a/fsw/cfe-core/unit-test/CMakeLists.txt b/fsw/cfe-core/unit-test/CMakeLists.txt index a61043a71..7e79e5c69 100644 --- a/fsw/cfe-core/unit-test/CMakeLists.txt +++ b/fsw/cfe-core/unit-test/CMakeLists.txt @@ -71,6 +71,7 @@ foreach(MODULE ${CFE_CORE_MODULES}) ${UT_COVERAGE_LINK_FLAGS} ut_cfe-core_support ut_cfe-core_stubs + sbr # TODO remove this ut_assert) add_test(${UT_TARGET_NAME}_UT ${UT_TARGET_NAME}_UT) diff --git a/fsw/cfe-core/unit-test/es_UT.c b/fsw/cfe-core/unit-test/es_UT.c index fe99f690e..951918a1b 100644 --- a/fsw/cfe-core/unit-test/es_UT.c +++ b/fsw/cfe-core/unit-test/es_UT.c @@ -278,9 +278,9 @@ void ES_UT_SetupSingleAppId(CFE_ES_AppType_Enum_t AppType, CFE_ES_AppState_Enum_ if (AppName) { - strncpy(LocalAppPtr->StartParams.Name, AppName, - sizeof(LocalAppPtr->StartParams.Name)-1); - LocalAppPtr->StartParams.Name[sizeof(LocalAppPtr->StartParams.Name)-1] = 0; + strncpy(LocalAppPtr->StartParams.BasicInfo.Name, AppName, + sizeof(LocalAppPtr->StartParams.BasicInfo.Name)-1); + LocalAppPtr->StartParams.BasicInfo.Name[sizeof(LocalAppPtr->StartParams.BasicInfo.Name)-1] = 0; strncpy(LocalTaskPtr->TaskName, AppName, sizeof(LocalTaskPtr->TaskName)-1); LocalTaskPtr->TaskName[sizeof(LocalTaskPtr->TaskName)-1] = 0; @@ -360,9 +360,9 @@ void ES_UT_SetupSingleLibId(const char *LibName, CFE_ES_LibRecord_t **OutLibRec) if (LibName) { - strncpy(LocalLibPtr->LibName, LibName, - sizeof(LocalLibPtr->LibName)-1); - LocalLibPtr->LibName[sizeof(LocalLibPtr->LibName)-1] = 0; + strncpy(LocalLibPtr->BasicInfo.Name, LibName, + sizeof(LocalLibPtr->BasicInfo.Name)-1); + LocalLibPtr->BasicInfo.Name[sizeof(LocalLibPtr->BasicInfo.Name)-1] = 0; } if (OutLibRec) @@ -986,10 +986,11 @@ void TestStartupErrorPaths(void) ++TaskRecPtr; } + UT_SetHookFunction(UT_KEY(OS_TaskCreate), ES_UT_SetAppStateHook, NULL); CFE_ES_CreateObjects(); UT_Report(__FILE__, __LINE__, UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_RECORD_USED]) && - UT_GetStubCount(UT_KEY(OS_printf)) == 23, + UT_GetStubCount(UT_KEY(OS_printf)) == 13, "CFE_ES_CreateObjects", "Record used error"); @@ -1008,11 +1009,12 @@ void TestStartupErrorPaths(void) } UT_SetDeferredRetcode(UT_KEY(CFE_TBL_EarlyInit), 1, -1); + UT_SetHookFunction(UT_KEY(OS_TaskCreate), ES_UT_SetAppStateHook, NULL); CFE_ES_CreateObjects(); UT_Report(__FILE__, __LINE__, UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_RECORD_USED]) && UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_EARLYINIT]) && - UT_GetStubCount(UT_KEY(OS_printf)) == 24, + UT_GetStubCount(UT_KEY(OS_printf)) == 14, "CFE_ES_CreateObjects", "Error returned when calling function"); @@ -1022,10 +1024,11 @@ void TestStartupErrorPaths(void) ES_ResetUnitTest(); UT_SetForceFail(UT_KEY(OS_TaskCreate), OS_ERROR); UT_SetForceFail(UT_KEY(OS_BinSemCreate), OS_ERROR); + UT_SetHookFunction(UT_KEY(OS_TaskCreate), ES_UT_SetAppStateHook, NULL); CFE_ES_CreateObjects(); UT_Report(__FILE__, __LINE__, UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_CORE_APP_CREATE]) && - UT_GetStubCount(UT_KEY(OS_printf)) == 13, + UT_GetStubCount(UT_KEY(OS_printf)) == 18, "CFE_ES_CreateObjects", "Error creating core application"); @@ -1175,12 +1178,9 @@ void TestApps(void) UT_SetReadBuffer(StartupScript, NumBytes); CFE_ES_StartApplications(CFE_PSP_RST_TYPE_PROCESSOR, CFE_PLATFORM_ES_NONVOL_STARTUP_FILE); - UT_Report(__FILE__, __LINE__, - UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_FILE_LINE_TOO_LONG]) && - UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_ES_APP_STARTUP_OPEN]) && - UT_GetStubCount(UT_KEY(OS_printf)) == 8, - "CFE_ES_StartApplications", - "Line too long"); + UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_FILE_LINE_TOO_LONG])); + UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_ES_APP_STARTUP_OPEN])); + UtAssert_UINT32_EQ(UT_GetStubCount(UT_KEY(OS_printf)), 5); /* Create a valid startup script for subsequent tests */ strncpy(StartupScript, @@ -1232,13 +1232,11 @@ void TestApps(void) /* Test successfully starting an application */ ES_ResetUnitTest(); UT_SetReadBuffer(StartupScript, NumBytes); + UT_SetHookFunction(UT_KEY(OS_TaskCreate), ES_UT_SetAppStateHook, NULL); CFE_ES_StartApplications(CFE_PSP_RST_TYPE_PROCESSOR, CFE_PLATFORM_ES_NONVOL_STARTUP_FILE); - UT_Report(__FILE__, __LINE__, - UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_ES_APP_STARTUP_OPEN]) && - UT_GetStubCount(UT_KEY(OS_printf)) == 8, - "CFE_ES_StartApplications", - "Start application; successful"); + UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_ES_APP_STARTUP_OPEN])); + UtAssert_UINT32_EQ(UT_GetStubCount(UT_KEY(OS_printf)), 5); /* Test parsing the startup script with an unknown entry type */ ES_ResetUnitTest(); @@ -1277,11 +1275,8 @@ void TestApps(void) 170, 4096, 1); - UT_Report(__FILE__, __LINE__, - Return == CFE_ES_ERR_APP_CREATE && - UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_APP_CREATE]), - "CFE_ES_AppCreate", - "Task create failure"); + UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); + UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_APP_CREATE])); /* Test application creation with NULL file name */ ES_ResetUnitTest(); @@ -1350,11 +1345,8 @@ void TestApps(void) 170, 8192, 1); - UT_Report(__FILE__, __LINE__, - Return == CFE_ES_ERR_APP_CREATE && - UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_EXTRACT_FILENAME_UT55]), - "CFE_ES_AppCreate", - "File load failure"); + UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); + UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_EXTRACT_FILENAME_UT55])); /* Test application loading and creation where all app slots are taken */ ES_ResetUnitTest(); @@ -1390,11 +1382,8 @@ void TestApps(void) 170, 8192, 1); - UT_Report(__FILE__, __LINE__, - Return == CFE_ES_ERR_APP_CREATE && - UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_CANNOT_FIND_SYMBOL]), - "CFE_ES_AppCreate", - "Entry point symbol lookup failure"); + UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); + UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_CANNOT_FIND_SYMBOL])); /* Test application loading and creation where the entry point symbol @@ -1410,12 +1399,9 @@ void TestApps(void) 170, 8192, 1); - UT_Report(__FILE__, __LINE__, - Return == CFE_ES_ERR_APP_CREATE && - UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_CANNOT_FIND_SYMBOL]) && - UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_MODULE_UNLOAD_FAILED]), - "CFE_ES_AppCreate", - "Module unload failure after entry point lookup failure"); + UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); + UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_CANNOT_FIND_SYMBOL])); + UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_MODULE_UNLOAD_FAILED])); /* * Set up a situation where attempting to get appID by context, @@ -1437,8 +1423,7 @@ void TestApps(void) CFE_ES_RunAppTableScan(0, &CFE_ES_TaskData.BackgroundAppScanState); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_PCR_ERR2_EID) && - UtAppRecPtr->ControlReq.AppTimerMsec == 0 && - UtAppRecPtr->ControlReq.AppControlRequest == CFE_ES_RunStatus_SYS_DELETE, + UtAppRecPtr->ControlReq.AppTimerMsec == 0, "CFE_ES_RunAppTableScan", "Waiting; process control request"); @@ -1466,7 +1451,6 @@ void TestApps(void) CFE_ES_RunAppTableScan(0, &CFE_ES_TaskData.BackgroundAppScanState); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_PCR_ERR2_EID) && - UtAppRecPtr->ControlReq.AppControlRequest == CFE_ES_RunStatus_SYS_DELETE && UtAppRecPtr->ControlReq.AppTimerMsec == 0, "CFE_ES_RunAppTableScan", "Stopped; process control request"); @@ -1490,7 +1474,8 @@ void TestApps(void) ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppControlRequest = 0x12345; - CFE_ES_ProcessControlRequest(UtAppRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_PCR_ERR2_EID), "CFE_ES_ProcessControlRequest", @@ -1499,20 +1484,21 @@ void TestApps(void) /* Test a successful control action request to exit an application */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy((char *) UtAppRecPtr->StartParams.FileName, + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.FileName, "/ram/Filename", OS_MAX_PATH_LEN); - UtAppRecPtr->StartParams.FileName[OS_MAX_PATH_LEN - 1] = '\0'; - strncpy((char *) UtAppRecPtr->StartParams.EntryPoint, + UtAppRecPtr->StartParams.BasicInfo.FileName[OS_MAX_PATH_LEN - 1] = '\0'; + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.EntryPoint, "NotNULL", OS_MAX_API_NAME); - UtAppRecPtr->StartParams.EntryPoint[OS_MAX_API_NAME - 1] = + UtAppRecPtr->StartParams.BasicInfo.EntryPoint[OS_MAX_API_NAME - 1] = '\0'; UtAppRecPtr->StartParams.Priority = 255; UtAppRecPtr->StartParams.StackSize = 8192; UtAppRecPtr->StartParams.ExceptionAction = 0; - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_EXIT; - CFE_ES_ProcessControlRequest(UtAppRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_EXIT_APP_INF_EID), "CFE_ES_ProcessControlRequest", @@ -1525,8 +1511,9 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_EXIT; UT_SetDeferredRetcode(UT_KEY(CFE_EVS_CleanUpApp), 1, -1); - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_EXIT_APP_ERR_EID), "CFE_ES_ProcessControlRequest", @@ -1540,8 +1527,9 @@ void TestApps(void) UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_DELETE; UT_SetDeferredRetcode(UT_KEY(CFE_EVS_CleanUpApp), 1, -1); - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_STOP_ERR3_EID), "CFE_ES_ProcessControlRequest", @@ -1555,8 +1543,9 @@ void TestApps(void) UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RESTART; UT_SetDeferredRetcode(UT_KEY(CFE_EVS_CleanUpApp), 1, -1); - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_RESTART_APP_ERR4_EID), "CFE_ES_ProcessControlRequest", @@ -1569,9 +1558,10 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RESTART; - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); UT_SetForceFail(UT_KEY(OS_TaskCreate), OS_ERROR); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_RESTART_APP_ERR3_EID), "CFE_ES_ProcessControlRequest", @@ -1584,9 +1574,10 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RELOAD; - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); UT_SetDeferredRetcode(UT_KEY(CFE_EVS_CleanUpApp), 1, -1); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_RELOAD_APP_ERR4_EID), "CFE_ES_ProcessControlRequest", @@ -1599,9 +1590,10 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RELOAD; - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); UT_SetForceFail(UT_KEY(OS_TaskCreate), OS_ERROR); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_RELOAD_APP_ERR3_EID), "CFE_ES_ProcessControlRequest", @@ -1612,20 +1604,21 @@ void TestApps(void) */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy((char *) UtAppRecPtr->StartParams.FileName, + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.FileName, "/ram/FileName", OS_MAX_PATH_LEN); - UtAppRecPtr->StartParams.FileName[OS_MAX_PATH_LEN - 1] = '\0'; - strncpy((char *) UtAppRecPtr->StartParams.EntryPoint, "NULL", + UtAppRecPtr->StartParams.BasicInfo.FileName[OS_MAX_PATH_LEN - 1] = '\0'; + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.EntryPoint, "NULL", OS_MAX_API_NAME); - UtAppRecPtr->StartParams.EntryPoint[OS_MAX_API_NAME - 1] = + UtAppRecPtr->StartParams.BasicInfo.EntryPoint[OS_MAX_API_NAME - 1] = '\0'; UtAppRecPtr->StartParams.Priority = 255; UtAppRecPtr->StartParams.StackSize = 8192; UtAppRecPtr->StartParams.ExceptionAction = 0; - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_ERROR; - CFE_ES_ProcessControlRequest(UtAppRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_ERREXIT_APP_INF_EID), "CFE_ES_ProcessControlRequest", @@ -1639,8 +1632,9 @@ void TestApps(void) UT_SetDeferredRetcode(UT_KEY(CFE_EVS_CleanUpApp), 1, -1); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_ERROR; - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_ERREXIT_APP_ERR_EID), "CFE_ES_ProcessControlRequest", @@ -1649,20 +1643,21 @@ void TestApps(void) /* Test a successful control action request to stop an application */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy((char *) UtAppRecPtr->StartParams.FileName, + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.FileName, "/ram/FileName", OS_MAX_PATH_LEN); - UtAppRecPtr->StartParams.FileName[OS_MAX_PATH_LEN - 1] = '\0'; - strncpy((char *) UtAppRecPtr->StartParams.EntryPoint, "NULL", + UtAppRecPtr->StartParams.BasicInfo.FileName[OS_MAX_PATH_LEN - 1] = '\0'; + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.EntryPoint, "NULL", OS_MAX_API_NAME); - UtAppRecPtr->StartParams.EntryPoint[OS_MAX_API_NAME - 1] = + UtAppRecPtr->StartParams.BasicInfo.EntryPoint[OS_MAX_API_NAME - 1] = '\0'; UtAppRecPtr->StartParams.Priority = 255; UtAppRecPtr->StartParams.StackSize = 8192; UtAppRecPtr->StartParams.ExceptionAction = 0; UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_DELETE; - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_STOP_INF_EID), "CFE_ES_ProcessControlRequest", @@ -1671,20 +1666,21 @@ void TestApps(void) /* Test a successful control action request to restart an application */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy((char *) UtAppRecPtr->StartParams.FileName, + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.FileName, "/ram/FileName", OS_MAX_PATH_LEN); - UtAppRecPtr->StartParams.FileName[OS_MAX_PATH_LEN - 1] = '\0'; - strncpy((char *) UtAppRecPtr->StartParams.EntryPoint, "NULL", + UtAppRecPtr->StartParams.BasicInfo.FileName[OS_MAX_PATH_LEN - 1] = '\0'; + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.EntryPoint, "NULL", OS_MAX_API_NAME); - UtAppRecPtr->StartParams.EntryPoint[OS_MAX_API_NAME - 1] = + UtAppRecPtr->StartParams.BasicInfo.EntryPoint[OS_MAX_API_NAME - 1] = '\0'; UtAppRecPtr->StartParams.Priority = 255; UtAppRecPtr->StartParams.StackSize = 8192; UtAppRecPtr->StartParams.ExceptionAction = 0; UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RESTART; - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_RESTART_APP_INF_EID), "CFE_ES_ProcessControlRequest", @@ -1693,20 +1689,21 @@ void TestApps(void) /* Test a successful control action request to reload an application */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy((char *) UtAppRecPtr->StartParams.FileName, + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.FileName, "/ram/FileName", OS_MAX_PATH_LEN); - UtAppRecPtr->StartParams.FileName[OS_MAX_PATH_LEN - 1] = '\0'; - strncpy((char *) UtAppRecPtr->StartParams.EntryPoint, "NULL", + UtAppRecPtr->StartParams.BasicInfo.FileName[OS_MAX_PATH_LEN - 1] = '\0'; + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.EntryPoint, "NULL", OS_MAX_API_NAME); - UtAppRecPtr->StartParams.EntryPoint[OS_MAX_API_NAME - 1] = + UtAppRecPtr->StartParams.BasicInfo.EntryPoint[OS_MAX_API_NAME - 1] = '\0'; UtAppRecPtr->StartParams.Priority = 255; UtAppRecPtr->StartParams.StackSize = 8192; UtAppRecPtr->StartParams.ExceptionAction = 0; UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RELOAD; - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_RELOAD_APP_INF_EID), "CFE_ES_ProcessControlRequest", @@ -1717,20 +1714,21 @@ void TestApps(void) */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - strncpy((char *) UtAppRecPtr->StartParams.FileName, + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.FileName, "/ram/FileName", OS_MAX_PATH_LEN); - UtAppRecPtr->StartParams.FileName[OS_MAX_PATH_LEN - 1] = '\0'; - strncpy((char *) UtAppRecPtr->StartParams.EntryPoint, "NULL", + UtAppRecPtr->StartParams.BasicInfo.FileName[OS_MAX_PATH_LEN - 1] = '\0'; + strncpy((char *) UtAppRecPtr->StartParams.BasicInfo.EntryPoint, "NULL", OS_MAX_API_NAME); - UtAppRecPtr->StartParams.EntryPoint[OS_MAX_API_NAME - 1] = + UtAppRecPtr->StartParams.BasicInfo.EntryPoint[OS_MAX_API_NAME - 1] = '\0'; UtAppRecPtr->StartParams.Priority = 255; UtAppRecPtr->StartParams.StackSize = 8192; UtAppRecPtr->StartParams.ExceptionAction = 0; UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_EXCEPTION; - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_PCR_ERR1_EID), "CFE_ES_ProcessControlRequest", @@ -1797,11 +1795,12 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); ES_UT_SetupForOSCleanup(); - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); UT_SetForceFail(UT_KEY(OS_TaskDelete), OS_ERROR); UT_SetForceFail(UT_KEY(OS_close), OS_ERROR); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); UT_Report(__FILE__, __LINE__, - CFE_ES_CleanUpApp(UtAppRecPtr) == CFE_ES_APP_CLEANUP_ERR, + CFE_ES_CleanUpApp(Id) == CFE_ES_APP_CLEANUP_ERR, "CFE_ES_CleanUpApp", "Task OS delete and close failure"); @@ -1810,12 +1809,13 @@ void TestApps(void) */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, NULL, NULL); ES_UT_SetupForOSCleanup(); UT_SetDeferredRetcode(UT_KEY(OS_MutSemDelete), 1, OS_ERROR); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); UT_Report(__FILE__, __LINE__, - CFE_ES_CleanUpApp(UtAppRecPtr) == CFE_ES_APP_CLEANUP_ERR, + CFE_ES_CleanUpApp(Id) == CFE_ES_APP_CLEANUP_ERR, "CFE_ES_CleanUpApp", "Task mutex delete failure"); @@ -1824,10 +1824,11 @@ void TestApps(void) */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); UT_SetDeferredRetcode(UT_KEY(OS_ModuleUnload), 1, OS_ERROR); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); UT_Report(__FILE__, __LINE__, - CFE_ES_CleanUpApp(UtAppRecPtr) == CFE_ES_APP_CLEANUP_ERR, + CFE_ES_CleanUpApp(Id) == CFE_ES_APP_CLEANUP_ERR, "CFE_ES_CleanUpApp", "Module unload failure"); @@ -1836,10 +1837,11 @@ void TestApps(void) */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); UT_SetDeferredRetcode(UT_KEY(CFE_EVS_CleanUpApp), 1, -1); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); UT_Report(__FILE__, __LINE__, - CFE_ES_CleanUpApp(UtAppRecPtr) == CFE_ES_APP_CLEANUP_ERR, + CFE_ES_CleanUpApp(Id) == CFE_ES_APP_CLEANUP_ERR, "CFE_ES_CleanUpApp", "EVS application cleanup failure"); @@ -2007,16 +2009,17 @@ void TestApps(void) 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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); /* Associate a child task with the app to be deleted */ ES_UT_SetupChildTaskId(UtAppRecPtr, NULL, NULL); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); UT_Report(__FILE__, __LINE__, - CFE_ES_CleanUpApp(UtAppRecPtr) == CFE_SUCCESS, + CFE_ES_CleanUpApp(Id) == CFE_SUCCESS, "CFE_ES_CleanUpApp", "Main task ID matches task ID, nominal"); UT_Report(__FILE__, __LINE__, @@ -2034,12 +2037,13 @@ void TestApps(void) 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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); ES_UT_SetupMemPoolId(&UtPoolRecPtr); UtPoolRecPtr->OwnerAppID = CFE_ES_AppRecordGetID(UtAppRecPtr); UtPoolRecPtr->PoolID = CFE_ES_ResourceID_FromInteger(99999); /* Mismatch */ + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); UT_Report(__FILE__, __LINE__, - CFE_ES_CleanUpApp(UtAppRecPtr) == CFE_ES_APP_CLEANUP_ERR, + CFE_ES_CleanUpApp(Id) == CFE_ES_APP_CLEANUP_ERR, "CFE_ES_CleanUpApp", "Mem Pool delete error"); UT_Report(__FILE__, __LINE__, @@ -2054,10 +2058,10 @@ void TestApps(void) /* 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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.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); - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); /* Associate a child task with the app to be deleted */ ES_UT_SetupChildTaskId(UtAppRecPtr, NULL, NULL); @@ -2065,12 +2069,13 @@ void TestApps(void) UtAppRecPtr->MainTaskId = CFE_ES_TaskRecordGetID(UtTaskRecPtr); UT_SetForceFail(UT_KEY(OS_TaskDelete), OS_ERROR); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); UT_Report(__FILE__, __LINE__, - CFE_ES_CleanUpApp(UtAppRecPtr) == CFE_ES_APP_CLEANUP_ERR, + CFE_ES_CleanUpApp(Id) == CFE_ES_APP_CLEANUP_ERR, "CFE_ES_CleanUpApp", "Main task ID doesn't match task ID, CFE_ES_APP_CLEANUP_ERR"); UT_Report(__FILE__, __LINE__, - !CFE_ES_TaskRecordIsUsed(UtTaskRecPtr), + CFE_ES_TaskRecordIsUsed(UtTaskRecPtr), "CFE_ES_CleanUpApp", "Main task ID doesn't match task ID, second task unchanged"); @@ -2087,14 +2092,15 @@ void TestApps(void) /* switch the main task association (makes it wrong) */ UtAppRecPtr->MainTaskId = CFE_ES_TaskRecordGetID(UtTaskRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); UT_Report(__FILE__, __LINE__, - CFE_ES_CleanUpApp(UtAppRecPtr) == CFE_SUCCESS, + CFE_ES_CleanUpApp(Id) == CFE_SUCCESS, "CFE_ES_CleanUpApp", "Application ID mismatch; core application"); UT_Report(__FILE__, __LINE__, - !CFE_ES_TaskRecordIsUsed(UtTaskRecPtr), + CFE_ES_TaskRecordIsUsed(UtTaskRecPtr), "CFE_ES_CleanUpApp", "Application ID mismatch; core application"); @@ -2111,10 +2117,11 @@ void TestApps(void) /* Setup an entry which will be deleted */ ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, &UtTaskRecPtr); - OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, "UT", + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, "UT", "ut-module"); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); UT_Report(__FILE__, __LINE__, - CFE_ES_CleanUpApp(UtAppRecPtr) == CFE_SUCCESS && + CFE_ES_CleanUpApp(Id) == CFE_SUCCESS && !CFE_ES_TaskRecordIsUsed(UtTaskRecPtr) && CFE_ES_Global.RegisteredExternalApps == 0, "CFE_ES_CleanUpApp", @@ -2181,7 +2188,7 @@ void TestResourceID(void) void TestLibs(void) { CFE_ES_LibRecord_t *UtLibRecPtr; - char LongLibraryName[sizeof(UtLibRecPtr->LibName)+1]; + char LongLibraryName[sizeof(UtLibRecPtr->BasicInfo.Name)+1]; CFE_ES_ResourceID_t Id; uint32 j; int32 Return; @@ -2195,11 +2202,8 @@ void TestLibs(void) "filename", "EntryPoint", "LibName"); - UT_Report(__FILE__, __LINE__, - Return == -444 && - UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_SHARED_LIBRARY_INIT]), - "CFE_ES_LoadLibrary", - "Load shared library initialization failure"); + UtAssert_INT32_EQ(Return, -444); + UtAssert_NONZERO(UT_PrintfIsInHistory(UT_OSP_MESSAGES[UT_OSP_SHARED_LIBRARY_INIT])); /* Test Load library returning an error on a null pointer argument */ Return = CFE_ES_LoadLibrary(&Id, @@ -2221,8 +2225,8 @@ void TestLibs(void) "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)); - LongLibraryName[sizeof(UtLibRecPtr->LibName)] = '\0'; + memset(&LongLibraryName[0], 'a', sizeof(LongLibraryName)-1); + LongLibraryName[sizeof(LongLibraryName)-1] = '\0'; Return = CFE_ES_LoadLibrary(&Id, "filename", "EntryPoint", @@ -2269,10 +2273,7 @@ void TestLibs(void) "/cf/apps/tst_lib.bundle", "TST_LIB_Init", "TST_LIB"); - UT_Report(__FILE__, __LINE__, - Return == CFE_ES_ERR_LOAD_LIB, - "CFE_ES_LoadLibrary", - "Load shared library failure"); + UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); /* Test shared library loading and initialization where the library * entry point symbol cannot be found @@ -2283,10 +2284,7 @@ void TestLibs(void) "/cf/apps/tst_lib.bundle", "TST_LIB_Init", "TST_LIB"); - UT_Report(__FILE__, __LINE__, - Return == CFE_ES_ERR_LOAD_LIB, - "CFE_ES_LoadLibrary", - "Could not find library initialization symbol"); + UtAssert_INT32_EQ(Return, CFE_STATUS_EXTERNAL_RESOURCE_FAIL); /* Test shared library loading and initialization where the library * initialization function fails and then must be cleaned up diff --git a/fsw/cfe-core/unit-test/sb_UT.c b/fsw/cfe-core/unit-test/sb_UT.c index 76e45c0d9..369ef3233 100644 --- a/fsw/cfe-core/unit-test/sb_UT.c +++ b/fsw/cfe-core/unit-test/sb_UT.c @@ -1287,7 +1287,16 @@ void Test_SB_Cmds_SendPrevSubs(void) CFE_SB_ProcessCmdPipePkt(); NumEvts += 8; /* +2 for the subscribe, +6 for the SEND_PREV_SUBS_CC */ - EVTCNT(NumEvts); + + /* Event count is only exact if there were no collisions */ + if (UT_EventIsInHistory(CFE_SB_HASHCOLLISION_EID)) + { + ASSERT_TRUE(UT_GetNumEventsSent() > NumEvts); + } + else + { + EVTCNT(NumEvts); + } /* Round out the number to three full pkts in order to test branch path * coverage, MSGID 0x0D was skipped in previous subscription loop @@ -1321,7 +1330,15 @@ void Test_SB_Cmds_SendPrevSubs(void) NumEvts += 8; /* +2 for the subscribe, +6 for the SEND_PREV_SUBS_CC */ - EVTCNT(NumEvts); + /* Event count is only exact if there were no collisions */ + if (UT_EventIsInHistory(CFE_SB_HASHCOLLISION_EID)) + { + ASSERT_TRUE(UT_GetNumEventsSent() > NumEvts); + } + else + { + EVTCNT(NumEvts); + } EVTSENT(CFE_SB_SUBSCRIPTION_RCVD_EID); EVTSENT(CFE_SB_SEND_NO_SUBS_EID); @@ -1704,7 +1721,7 @@ void Test_DeletePipe_WithSubs(void) SETUP(CFE_SB_Subscribe(MsgId3, PipedId)); ASSERT(CFE_SB_DeletePipe(PipedId)); - EVTCNT(14); + EVTCNT(10); EVTSENT(CFE_SB_PIPE_ADDED_EID); EVTSENT(CFE_SB_PIPE_DELETED_EID); @@ -1772,7 +1789,7 @@ void Test_DeletePipe_WithAppid(void) ASSERT(CFE_SB_DeletePipeWithAppId(PipedId, AppId)); - EVTCNT(14); + EVTCNT(10); } /* end Test_DeletePipe_WithAppid */ @@ -2030,7 +2047,6 @@ void Test_Subscribe_API(void) SB_UT_ADD_SUBTEST(Test_Subscribe_MaxDestCount); SB_UT_ADD_SUBTEST(Test_Subscribe_MaxMsgIdCount); SB_UT_ADD_SUBTEST(Test_Subscribe_SendPrevSubs); - SB_UT_ADD_SUBTEST(Test_Subscribe_FindGlobalMsgIdCnt); SB_UT_ADD_SUBTEST(Test_Subscribe_PipeNonexistent); SB_UT_ADD_SUBTEST(Test_Subscribe_SubscriptionReporting); SB_UT_ADD_SUBTEST(Test_Subscribe_InvalidPipeOwner); @@ -2274,9 +2290,6 @@ void Test_Subscribe_SendPrevSubs(void) SETUP(CFE_SB_Subscribe(MsgId2, PipeId1)); SETUP(CFE_SB_Subscribe(MsgId0, PipeId2)); - /* Set the last list header pointer to NULL to get branch path coverage */ - CFE_SB.RoutingTbl[2].ListHeadPtr = NULL; - /* For internal SendMsg call */ MsgIdCmd = CFE_SB_ValueToMsgId(CFE_SB_ALLSUBS_TLM_MID); Size = sizeof(CFE_SB.PrevSubMsg); @@ -2295,46 +2308,6 @@ void Test_Subscribe_SendPrevSubs(void) } /* end Test_Subscribe_SendPrevSubs */ -/* -** Test function to get a count of the global message ids in use -*/ -void Test_Subscribe_FindGlobalMsgIdCnt(void) -{ - CFE_SB_PipeId_t PipeId0; - CFE_SB_PipeId_t PipeId1; - CFE_SB_PipeId_t PipeId2; - CFE_SB_MsgId_t MsgId0 = SB_UT_TLM_MID1; - CFE_SB_MsgId_t MsgId1 = SB_UT_TLM_MID2; - CFE_SB_MsgId_t MsgId2 = SB_UT_TLM_MID3; - uint16 PipeDepth = 50; - uint16 MsgLim = 4; - - SETUP(CFE_SB_CreatePipe(&PipeId0, PipeDepth, "TestPipe0")); - SETUP(CFE_SB_CreatePipe(&PipeId1, PipeDepth, "TestPipe1")); - SETUP(CFE_SB_CreatePipe(&PipeId2, PipeDepth, "TestPipe2")); - SETUP(CFE_SB_Subscribe(MsgId0, PipeId0)); - SETUP(CFE_SB_Subscribe(MsgId1, PipeId0)); - SETUP(CFE_SB_Subscribe(MsgId2, PipeId0)); - SETUP(CFE_SB_Subscribe(MsgId0, PipeId1)); - SETUP(CFE_SB_Subscribe(MsgId1, PipeId1)); - SETUP(CFE_SB_Subscribe(MsgId2, PipeId1)); - SETUP(CFE_SB_SubscribeLocal(MsgId0, PipeId2, MsgLim)); - - /* Set the last list head pointer to NULL for branch path coverage */ - CFE_SB.RoutingTbl[2].ListHeadPtr = NULL; - - ASSERT_EQ(CFE_SB_FindGlobalMsgIdCnt(), 2); /* 2 unique msg ids; the third is set to skip */ - - EVTCNT(17); - - EVTSENT(CFE_SB_PIPE_ADDED_EID); - - TEARDOWN(CFE_SB_DeletePipe(PipeId0)); - TEARDOWN(CFE_SB_DeletePipe(PipeId1)); - TEARDOWN(CFE_SB_DeletePipe(PipeId2)); - -} /* end Test_Subscribe_FindGlobalMsgIdCnt */ - /* ** Test message subscription response to nonexistent pipe */ @@ -2366,7 +2339,7 @@ void Test_Subscribe_SubscriptionReporting(void) SETUP(CFE_SB_CreatePipe(&PipeId, PipeDepth, "TestPipe")); /* Enable subscription reporting */ - CFE_SB_SetSubscriptionReporting(CFE_SB_ENABLE); + CFE_SB_SetSubscriptionReporting(CFE_SB_ENABLE); /* For internal SendMsg call that will report subscription */ MsgIdRpt = CFE_SB_ValueToMsgId(CFE_SB_ONESUB_TLM_MID); @@ -2374,21 +2347,21 @@ void Test_Subscribe_SubscriptionReporting(void) UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgIdRpt, sizeof(MsgIdRpt), false); UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); - /* Subscribe to message: GLOBAL */ - SETUP(CFE_SB_Subscribe(MsgId, PipeId)); + /* Subscribe to message: GLOBAL */ + SETUP(CFE_SB_Subscribe(MsgId, PipeId)); - /* Unsubscribe so that a local subscription can be tested */ - SETUP(CFE_SB_Unsubscribe(MsgId, PipeId)); + /* Unsubscribe so that a local subscription can be tested */ + SETUP(CFE_SB_Unsubscribe(MsgId, PipeId)); - /* Subscribe to message: LOCAL */ - ASSERT(CFE_SB_SubscribeFull(MsgId, PipeId, Quality, CFE_PLATFORM_SB_DEFAULT_MSG_LIMIT, CFE_SB_LOCAL)); + /* Subscribe to message: LOCAL */ + ASSERT(CFE_SB_SubscribeFull(MsgId, PipeId, Quality, CFE_PLATFORM_SB_DEFAULT_MSG_LIMIT, CFE_SB_LOCAL)); - EVTCNT(8); + EVTCNT(8); - EVTSENT(CFE_SB_SUBSCRIPTION_RPT_EID); + EVTSENT(CFE_SB_SUBSCRIPTION_RPT_EID); - /* Disable subscription reporting */ - CFE_SB_SetSubscriptionReporting(CFE_SB_DISABLE); + /* Disable subscription reporting */ + CFE_SB_SetSubscriptionReporting(CFE_SB_DISABLE); TEARDOWN(CFE_SB_DeletePipe(PipeId)); @@ -2538,22 +2511,21 @@ void Test_Unsubscribe_NoMatch(void) { CFE_SB_PipeId_t TestPipe; CFE_SB_MsgId_t MsgId = SB_UT_TLM_MID; - CFE_SB_MsgRouteIdx_t Idx; uint16 PipeDepth = 50; + /* Create pipe, subscribe, unsubscribe */ SETUP(CFE_SB_CreatePipe(&TestPipe, PipeDepth, "TestPipe")); SETUP(CFE_SB_Subscribe(MsgId, TestPipe)); + SETUP(CFE_SB_Unsubscribe(MsgId, TestPipe)); + UT_ClearEventHistory(); + /* Check that unsubscribe to msgid that was never subscribed reports error */ ASSERT(CFE_SB_Unsubscribe(SB_UT_TLM_MID1, TestPipe)); + EVTSENT(CFE_SB_UNSUB_NO_SUBS_EID); + UT_ClearEventHistory(); - /* Get index into routing table */ - Idx = CFE_SB_GetRoutingTblIdx(CFE_SB_ConvertMsgIdtoMsgKey(MsgId)); - CFE_SB.RoutingTbl[CFE_SB_RouteIdxToValue(Idx)].ListHeadPtr->PipeId = 1; - CFE_SB.RoutingTbl[CFE_SB_RouteIdxToValue(Idx)].ListHeadPtr->Next = NULL; + /* Check that repeated unsubscribe to msgid that was subscribted reports error */ ASSERT(CFE_SB_Unsubscribe(MsgId, TestPipe)); - - EVTCNT(7); - EVTSENT(CFE_SB_UNSUB_NO_SUBS_EID); TEARDOWN(CFE_SB_DeletePipe(TestPipe)); @@ -2681,10 +2653,11 @@ void Test_Unsubscribe_MiddleDestWithMany(void) */ void Test_Unsubscribe_GetDestPtr(void) { - CFE_SB_MsgId_t MsgId = SB_UT_CMD_MID; - CFE_SB_PipeId_t TestPipe1; - CFE_SB_PipeId_t TestPipe2; - uint16 PipeDepth = 50; + CFE_SB_MsgId_t MsgId = SB_UT_CMD_MID; + CFE_SB_PipeId_t TestPipe1; + CFE_SB_PipeId_t TestPipe2; + uint16 PipeDepth = 50; + CFE_SBR_RouteId_t RouteId; SETUP(CFE_SB_CreatePipe(&TestPipe1, PipeDepth, "TestPipe1")); SETUP(CFE_SB_CreatePipe(&TestPipe2, PipeDepth, "TestPipe2")); @@ -2692,7 +2665,9 @@ void Test_Unsubscribe_GetDestPtr(void) SETUP(CFE_SB_Subscribe(MsgId, TestPipe2)); SETUP(CFE_SB_Unsubscribe(MsgId, TestPipe2)); - ASSERT_TRUE(CFE_SB_GetDestPtr(CFE_SB_ConvertMsgIdtoMsgKey(MsgId), TestPipe2) == NULL); + /* TODO for now just get route id and use it, will need update when stubbed */ + RouteId = CFE_SBR_GetRouteId(MsgId); + ASSERT_TRUE(CFE_SB_GetDestPtr(RouteId, TestPipe2) == NULL); EVTCNT(7); @@ -3252,12 +3227,15 @@ void Test_SendMsg_DisabledDestination(void) int32 PipeDepth; CFE_MSG_Type_t Type = CFE_MSG_Type_Tlm; CFE_MSG_Size_t Size = sizeof(TlmPkt); + CFE_SBR_RouteId_t RouteId; PipeDepth = 2; SETUP(CFE_SB_CreatePipe(&PipeId, PipeDepth, "TestPipe")); SETUP(CFE_SB_Subscribe(MsgId, PipeId)); - DestPtr = CFE_SB_GetDestPtr(CFE_SB_ConvertMsgIdtoMsgKey(MsgId), PipeId); + + RouteId = CFE_SBR_GetRouteId(MsgId); + DestPtr = CFE_SB_GetDestPtr(RouteId, PipeId); DestPtr->Active = CFE_SB_INACTIVE; UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); @@ -3857,41 +3835,8 @@ void Test_SB_SpecialCases(void) SB_UT_ADD_SUBTEST(Test_SB_SendMsgPaths_IgnoreOpt); SB_UT_ADD_SUBTEST(Test_RcvMsg_UnsubResubPath); SB_UT_ADD_SUBTEST(Test_MessageString); - SB_UT_ADD_SUBTEST(Test_SB_IdxPushPop); } /* end Test_SB_SpecialCases */ -/* -** Test msg key idx push pop -*/ -void Test_SB_IdxPushPop() -{ - int32 i; - CFE_SB_MsgRouteIdx_t Idx; - - CFE_SB_InitIdxStack(); - - for (i = 0; i < CFE_PLATFORM_SB_MAX_MSG_IDS; i++) - { - /* Subscribe to maximum number of messages */ - Idx = CFE_SB_RouteIdxPop_Unsync(); - ASSERT_EQ(CFE_SB_RouteIdxToValue(Idx), i); - } - - - Idx = CFE_SB_RouteIdxPop_Unsync(); - ASSERT_EQ(CFE_SB_RouteIdxToValue(Idx), CFE_SB_RouteIdxToValue(CFE_SB_INVALID_ROUTE_IDX)); - - for (i = 0; i < CFE_PLATFORM_SB_MAX_MSG_IDS; i++) - { - /* Un-subscribe from all messages */ - CFE_SB_RouteIdxPush_Unsync(CFE_SB_ValueToRouteIdx(i)); - } - - CFE_SB_RouteIdxPush_Unsync(CFE_SB_ValueToRouteIdx(i)); - - -} /* end Test_SB_IdxPushPop */ - /* ** Test pipe creation with semaphore take and give failures */ @@ -4037,10 +3982,10 @@ void Test_CFE_SB_BadPipeInfo(void) } /* end Test_CFE_SB_BadPipeInfo */ + /* ** Test send housekeeping information command */ - void Test_SB_SendMsgPaths_Nominal(void) { CFE_SB_CmdHdr_t NoParamCmd; @@ -4062,12 +4007,17 @@ void Test_SB_SendMsgPaths_Nominal(void) MsgId = CFE_SB_ValueToMsgId(CFE_SB_SEND_HK_MID); UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + /* Repress sending the no subscriptions event and process request */ + CFE_SB.HKTlmMsg.Payload.NoSubscribersCounter = 0; CFE_SB.CmdPipePktPtr = (CFE_SB_MsgPtr_t) &NoParamCmd; CFE_SB.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_SEND_NO_SUBS_EID_BIT); CFE_SB_ProcessCmdPipePkt(); + /* The no subs event should not be in history but count should increment */ ASSERT_TRUE(!UT_EventIsInHistory(CFE_SB_SEND_NO_SUBS_EID)); + ASSERT_EQ(CFE_SB.HKTlmMsg.Payload.NoSubscribersCounter, 1); + /* Repress get buffer error */ CFE_SB.HKTlmMsg.Payload.MsgSendErrorCounter = 0; CFE_SB.StopRecurseFlags[1] |= CFE_BIT(CFE_SB_GET_BUF_ERR_EID_BIT); @@ -4081,7 +4031,6 @@ void Test_SB_SendMsgPaths_Nominal(void) MsgId = CFE_SB_ValueToMsgId(CFE_SB_SEND_HK_MID); UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); - CFE_SB.MsgMap[CFE_SB_MsgKeyToValue(CFE_SB_ConvertMsgIdtoMsgKey(CFE_SB_HK_TLM_MID))] = CFE_SB_INVALID_ROUTE_IDX; UT_SetDeferredRetcode(UT_KEY(CFE_ES_GetPoolBuf), 1, CFE_ES_ERR_MEM_BLOCK_SIZE); CFE_SB_ProcessCmdPipePkt(); ASSERT_EQ(CFE_SB.HKTlmMsg.Payload.MsgSendErrorCounter, 0); diff --git a/fsw/cfe-core/unit-test/ut_osprintf_stubs.c b/fsw/cfe-core/unit-test/ut_osprintf_stubs.c index 6face1351..facd86a3c 100644 --- a/fsw/cfe-core/unit-test/ut_osprintf_stubs.c +++ b/fsw/cfe-core/unit-test/ut_osprintf_stubs.c @@ -93,7 +93,7 @@ const char *UT_OSP_MESSAGES[] = /* ES Startup: Error Re-Formating Volatile(RAM) Volume. EC = 0x~ */ [UT_OSP_REFORMAT_VOLATILE] = "ES Startup: Error Re-Formating Volatile(RAM) Volume. EC = 0x%08X\n", /* ES Startup: Could not load cFE application file:ut/filename.x. EC = 0x~ */ - [UT_OSP_EXTRACT_FILENAME_UT55] = "ES Startup: Could not load cFE application file:%s. EC = 0x%08X\n", + [UT_OSP_EXTRACT_FILENAME_UT55] = "ES Startup: Could not load file:%s. EC = 0x%08X\n", /* ES Startup: Unable to extract filename from path: ut46/ */ [UT_OSP_EXTRACT_FILENAME_UT46] = "ES Startup: Unable to extract filename from path: %s.\n", /* ES Startup: No free application slots available */ @@ -123,7 +123,7 @@ const char *UT_OSP_MESSAGES[] = /* ES Startup: Error Creating Volatile(RAM) Volume. EC = 0x~ */ [UT_OSP_CREATE_VOLATILE] = "ES Startup: Error Creating Volatile(RAM) Volume. EC = 0x%08X\n", /* ES Startup: Failed to unload APP: AppName. EC = 0x~ */ - [UT_OSP_MODULE_UNLOAD_FAILED] = "ES Startup: Failed to unload APP: %s. EC = 0x%08X\n", + [UT_OSP_MODULE_UNLOAD_FAILED] = "ES Startup: Failed to unload: %s. EC = 0x%08X\n", /* POWERON RESET called from CFE_ES_ResetCFE (Commanded). */ [UT_OSP_POR_COMMANDED] = "POWERON RESET called from CFE_ES_ResetCFE (Commanded).\n", /* ES Startup: Error Re-Mounting Volatile(RAM) Volume. EC = 0x~ */ @@ -159,7 +159,7 @@ const char *UT_OSP_MESSAGES[] = /* ES Startup: Error, No free application slots available for CORE App! */ [UT_OSP_NO_FREE_CORE_APP_SLOTS] = "ES Startup: Error, No free application slots available for CORE App!\n", /* ES Startup: CFE_ES_Global.TaskTable record used error for App: CFE_EVS, continuing. */ - [UT_OSP_RECORD_USED] = "ES Startup: CFE_ES_Global.TaskTable record used error for App: %s, continuing.\n", + [UT_OSP_RECORD_USED] = "ES Startup: Error: ES_TaskTable slot for ID %lx in use at task creation!\n", /* CFE_ES_ExitChildTask called from invalid task context */ [UT_OSP_TASKEXIT_BAD_CONTEXT] = "CFE_ES_ExitChildTask called from invalid task context\n", }; diff --git a/modules/sbr/CMakeLists.txt b/modules/sbr/CMakeLists.txt new file mode 100644 index 000000000..615589ca3 --- /dev/null +++ b/modules/sbr/CMakeLists.txt @@ -0,0 +1,43 @@ +################################################################## +# +# cFE software bus routing module CMake build recipe +# +# This CMakeLists.txt adds source files for the +# SBR module included in the cFE distribution. Selected +# files are built into a static library that in turn +# is linked into the final executable. +# +# Note this is different than applications which are dynamically +# linked to support runtime loading. The core applications all +# use static linkage. +# +################################################################## + +if (NOT MISSION_MSGMAP_IMPLEMENTATION) + set(MISSION_MSGMAP_IMPLEMENTATION "DIRECT") +endif (NOT MISSION_MSGMAP_IMPLEMENTATION) + +if (MISSION_MSGMAP_IMPLEMENTATION STREQUAL "DIRECT") + message(STATUS "Using direct map software bus routing implementation") + set(${DEP}_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/src/cfe_sbr_map_direct.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/cfe_sbr_route_unsorted.c) +elseif (MISSION_MSGMAP_IMPLEMENTATION STREQUAL "HASH") + message(STATUS "Using hashed map software bus routing implementation") + set(${DEP}_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/src/cfe_sbr_map_hash.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/cfe_sbr_route_unsorted.c) +else() + message(ERROR "Invalid software bush routing implementation selected:" MISSION_MSGMAP_IMPLEMENTATION) +endif() + +# Module library +add_library(${DEP} STATIC ${${DEP}_SRC}) + +# Add private include +target_include_directories(${DEP} PRIVATE private_inc) + +# Add unit test coverage subdirectory +if(ENABLE_UNIT_TESTS) + add_subdirectory(unit-test-coverage) +endif(ENABLE_UNIT_TESTS) diff --git a/modules/sbr/private_inc/cfe_sbr_priv.h b/modules/sbr/private_inc/cfe_sbr_priv.h new file mode 100644 index 000000000..3d0fcce59 --- /dev/null +++ b/modules/sbr/private_inc/cfe_sbr_priv.h @@ -0,0 +1,66 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/****************************************************************************** + * Prototypes for private functions and type definitions for SB + * routing internal use. + *****************************************************************************/ + +#ifndef CFE_SBR_PRIV_H_ +#define CFE_SBR_PRIV_H_ + +/* + * Includes + */ +#include "private/cfe_sbr.h" + +/* + * Macro Definitions + */ + +/** \brief Invalid route id */ +#define CFE_SBR_INVALID_ROUTE_ID ((CFE_SBR_RouteId_t) {.RouteId = 0}) + +/****************************************************************************** + * Function prototypes + */ + +/** + * \brief Routing map initialization + */ +void CFE_SBR_Init_Map(void); + +/** + * \brief Associates the given route ID with the given message ID + * + * Used for implementations that use a mapping table (typically hash or direct) + * and need this information to later get the route id from the message id. + * + * \note Typically not needed for a search implementation. Assumes + * message ID is valid + * + * \param[in] MsgId Message id to associate with route id + * \param[in] RouteId Route id to associate with message id + * + * \returns Number of collisions + */ +uint32 CFE_SBR_SetRouteId(CFE_SB_MsgId_t MsgId, CFE_SBR_RouteId_t RouteId); + +#endif /* CFE_SBR_PRIV_H_ */ diff --git a/modules/sbr/src/cfe_sbr_map_direct.c b/modules/sbr/src/cfe_sbr_map_direct.c new file mode 100644 index 000000000..1545bf4ef --- /dev/null +++ b/modules/sbr/src/cfe_sbr_map_direct.c @@ -0,0 +1,93 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/****************************************************************************** + * Direct routing map implementation + * + * Notes: + * These functions manipulate/access global variables and need + * to be protected by the SB Shared data lock. + * + */ + +/* + * Include Files + */ + +#include "common_types.h" +#include "private/cfe_sbr.h" +#include "cfe_sbr_priv.h" +#include + +/* + * Macro Definitions + */ + +/** + * \brief Message map size + * + * For direct mapping, map size is maximum valid MsgId value + 1 (since MsgId 0 is valid) + */ +#define CFE_SBR_MSG_MAP_SIZE (CFE_PLATFORM_SB_HIGHEST_VALID_MSGID + 1) + +/****************************************************************************** + * Shared data + */ + +/** \brief Message map shared data */ +CFE_SBR_RouteId_t CFE_SBR_MSGMAP[CFE_SBR_MSG_MAP_SIZE]; + +/****************************************************************************** + * Interface function - see header for description + */ +void CFE_SBR_Init_Map(void) +{ + /* Clear the shared data */ + memset(&CFE_SBR_MSGMAP, 0, sizeof(CFE_SBR_MSGMAP)); +} + +/****************************************************************************** + * Interface function - see header for description + */ +uint32 CFE_SBR_SetRouteId(CFE_SB_MsgId_t MsgId, CFE_SBR_RouteId_t RouteId) +{ + if (CFE_SB_IsValidMsgId(MsgId)) + { + CFE_SBR_MSGMAP[CFE_SB_MsgIdToValue(MsgId)] = RouteId; + } + + /* Direct lookup never collides, always return 0 */ + return 0; +} + +/****************************************************************************** + * Interface function - see API for description + */ +CFE_SBR_RouteId_t CFE_SBR_GetRouteId(CFE_SB_MsgId_t MsgId) +{ + CFE_SBR_RouteId_t routeid = CFE_SBR_INVALID_ROUTE_ID; + + if (CFE_SB_IsValidMsgId(MsgId)) + { + routeid = CFE_SBR_MSGMAP[CFE_SB_MsgIdToValue(MsgId)]; + } + + return routeid; +} diff --git a/modules/sbr/src/cfe_sbr_map_hash.c b/modules/sbr/src/cfe_sbr_map_hash.c new file mode 100644 index 000000000..dd9b8bd5c --- /dev/null +++ b/modules/sbr/src/cfe_sbr_map_hash.c @@ -0,0 +1,163 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/****************************************************************************** + * Hash routing map implementation + * + * Notes: + * These functions manipulate/access global variables and need + * to be protected by the SB Shared data lock. + * + */ + +/* + * Include Files + */ + +#include "common_types.h" +#include "private/cfe_sbr.h" +#include "cfe_sbr_priv.h" +#include +#include + +/* + * Macro Definitions + */ + +/** + * \brief Message map size + * + * For hash mapping, map size is a multiple of maximum number of routes. + * The multiple impacts the number of collisions when the routes fill up. + * 4 was initially chosen to provide for plenty of holes in the map, while + * still remaining much smaller than the routing table. Note the + * multiple must be a factor of 2 to use the efficient shift logic, and + * can't be bigger than what can be indexed by CFE_SB_MsgId_Atom_t + */ +#define CFE_SBR_MSG_MAP_SIZE (4 * CFE_PLATFORM_SB_MAX_MSG_IDS) + +/* Verify power of two */ +#if ((CFE_SBR_MSG_MAP_SIZE & (CFE_SBR_MSG_MAP_SIZE - 1)) != 0) +#error CFE_SBR_MSG_MAP_SIZE must be a power of 2 for hash algorithm to work +#endif + +/** \brief Hash algorithm magic number + * + * Ref: + * https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key/12996028#12996028 + */ +#define CFE_SBR_HASH_MAGIC (0x45d9f3b) + +/****************************************************************************** + * Shared data + */ + +/** \brief Message map shared data */ +CFE_SBR_RouteId_t CFE_SBR_MSGMAP[CFE_SBR_MSG_MAP_SIZE]; + +/****************************************************************************** + * Internal helper function to hash the message id + * + * Note: algorithm designed for a 32 bit int, changing the size of + * CFE_SB_MsgId_Atom_t may require an update to this impelementation + */ +CFE_SB_MsgId_Atom_t CFE_SBR_MsgIdHash(CFE_SB_MsgId_t MsgId) +{ + CFE_SB_MsgId_Atom_t hash; + + hash = CFE_SB_MsgIdToValue(MsgId); + + hash = ((hash >> 16) ^ hash) * CFE_SBR_HASH_MAGIC; + hash = ((hash >> 16) ^ hash) * CFE_SBR_HASH_MAGIC; + hash = (hash >> 16) ^ hash; + + /* Reduce to fit in map */ + hash &= CFE_SBR_MSG_MAP_SIZE - 1; + + return hash; +} + +/****************************************************************************** + * Interface function - see header for description + */ +void CFE_SBR_Init_Map(void) +{ + /* Clear the shared data */ + memset(&CFE_SBR_MSGMAP, 0, sizeof(CFE_SBR_MSGMAP)); +} + +/****************************************************************************** + * Interface function - see header for description + */ +uint32 CFE_SBR_SetRouteId(CFE_SB_MsgId_t MsgId, CFE_SBR_RouteId_t RouteId) +{ + CFE_SB_MsgId_Atom_t hash; + uint32 collisions = 0; + + if (CFE_SB_IsValidMsgId(MsgId)) + { + hash = CFE_SBR_MsgIdHash(MsgId); + + /* + * Increment from original hash to find the next open slot. + * Since map is larger than possible routes this will + * never deadlock + */ + while (CFE_SBR_IsValidRouteId(CFE_SBR_MSGMAP[hash])) + { + /* Increment or loop to start of array */ + hash = (hash + 1) & (CFE_SBR_MSG_MAP_SIZE - 1); + collisions++; + } + + CFE_SBR_MSGMAP[hash] = RouteId; + } + + return collisions; +} + +/****************************************************************************** + * Interface function - see API for description + */ +CFE_SBR_RouteId_t CFE_SBR_GetRouteId(CFE_SB_MsgId_t MsgId) +{ + CFE_SB_MsgId_Atom_t hash; + CFE_SBR_RouteId_t routeid = CFE_SBR_INVALID_ROUTE_ID; + + if (CFE_SB_IsValidMsgId(MsgId)) + { + hash = CFE_SBR_MsgIdHash(MsgId); + routeid = CFE_SBR_MSGMAP[hash]; + + /* + * Increment from original hash to find matching route. + * Since map is larger than possible routes this will + * never deadlock + */ + while (CFE_SBR_IsValidRouteId(routeid) && !CFE_SB_MsgId_Equal(CFE_SBR_GetMsgId(routeid), MsgId)) + { + /* Increment or loop to start of array */ + hash = (hash + 1) & (CFE_SBR_MSG_MAP_SIZE - 1); + routeid = CFE_SBR_MSGMAP[hash]; + } + } + + return routeid; +} diff --git a/modules/sbr/src/cfe_sbr_route_unsorted.c b/modules/sbr/src/cfe_sbr_route_unsorted.c new file mode 100644 index 000000000..716cd50e4 --- /dev/null +++ b/modules/sbr/src/cfe_sbr_route_unsorted.c @@ -0,0 +1,219 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/****************************************************************************** + * Purpose: + * Unsorted routing implemenation + * Used with route map implementations where order of routes doesn't matter + * + * Notes: + * These functions manipulate/access global variables and need + * to be protected by the SB Shared data lock. + */ + +/* + * Include Files + */ + +#include "common_types.h" +#include "private/cfe_sbr.h" +#include "cfe_sbr_priv.h" +#include + +/****************************************************************************** + * Type Definitions + */ + +/** \brief Routing table entry */ +typedef struct +{ + CFE_SB_DestinationD_t * ListHeadPtr; /**< \brief Destination list head */ + CFE_SB_MsgId_t MsgId; /**< \brief Message ID associated with route */ + CFE_MSG_SequenceCount_t SeqCnt; /**< \brief Message sequence counter */ +} CFE_SBR_RouteEntry_t; + +/** \brief Module data */ +typedef struct +{ + CFE_SBR_RouteEntry_t RoutingTbl[CFE_PLATFORM_SB_MAX_MSG_IDS]; /**< \brief Routing table */ + CFE_SB_RouteId_Atom_t RouteIdxTop; /**< \brief First unused entry in RoutingTbl */ +} cfe_sbr_route_data_t; + +/****************************************************************************** + * Shared data + */ + +/** \brief Routing module shared data */ +cfe_sbr_route_data_t CFE_SBR_RDATA; + +/****************************************************************************** + * Interface function - see API for description + */ +void CFE_SBR_Init(void) +{ + CFE_SB_RouteId_Atom_t routeidx; + + /* Clear the shared data */ + memset(&CFE_SBR_RDATA, 0, sizeof(CFE_SBR_RDATA)); + + /* Only non-zero value for shared data initialization is the invalid MsgId */ + for (routeidx = 0; routeidx < CFE_PLATFORM_SB_MAX_MSG_IDS; routeidx++) + { + CFE_SBR_RDATA.RoutingTbl[routeidx].MsgId = CFE_SB_INVALID_MSG_ID; + } + + /* Initialize map */ + CFE_SBR_Init_Map(); +} + +/****************************************************************************** + * Interface function - see API for description + */ +CFE_SBR_RouteId_t CFE_SBR_AddRoute(CFE_SB_MsgId_t MsgId, uint32 *CollisionsPtr) +{ + CFE_SBR_RouteId_t routeid = CFE_SBR_INVALID_ROUTE_ID; + uint32 collisions = 0; + + if (CFE_SB_IsValidMsgId(MsgId) && (CFE_SBR_RDATA.RouteIdxTop < CFE_PLATFORM_SB_MAX_MSG_IDS)) + { + routeid = CFE_SBR_ValueToRouteId(CFE_SBR_RDATA.RouteIdxTop); + collisions = CFE_SBR_SetRouteId(MsgId, routeid); + + CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RDATA.RouteIdxTop].MsgId = MsgId; + CFE_SBR_RDATA.RouteIdxTop++; + } + + if (CollisionsPtr != NULL) + { + *CollisionsPtr = collisions; + } + + return routeid; +} + +/****************************************************************************** + * Interface function - see API for description + */ +CFE_SB_MsgId_t CFE_SBR_GetMsgId(CFE_SBR_RouteId_t RouteId) +{ + CFE_SB_MsgId_t msgid = CFE_SB_INVALID_MSG_ID; + + if (CFE_SBR_IsValidRouteId(RouteId)) + { + msgid = CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RouteIdToValue(RouteId)].MsgId; + } + + return msgid; +} + +/****************************************************************************** + * Interface function - see API for description + */ +CFE_SB_DestinationD_t *CFE_SBR_GetDestListHeadPtr(CFE_SBR_RouteId_t RouteId) +{ + + CFE_SB_DestinationD_t *destptr = NULL; + + if (CFE_SBR_IsValidRouteId(RouteId)) + { + destptr = CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RouteIdToValue(RouteId)].ListHeadPtr; + } + + return destptr; +} + +/****************************************************************************** + * Interface function - see API for description + */ +void CFE_SBR_SetDestListHeadPtr(CFE_SBR_RouteId_t RouteId, CFE_SB_DestinationD_t *DestPtr) +{ + + if (CFE_SBR_IsValidRouteId(RouteId)) + { + CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RouteIdToValue(RouteId)].ListHeadPtr = DestPtr; + } +} + +/****************************************************************************** + * Interface function - see API for description + */ +void CFE_SBR_IncrementSequenceCounter(CFE_SBR_RouteId_t RouteId) +{ + if (CFE_SBR_IsValidRouteId(RouteId)) + { + CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RouteIdToValue(RouteId)].SeqCnt++; + } +} + +/****************************************************************************** + * Interface function - see API for description + */ +CFE_MSG_SequenceCount_t CFE_SBR_GetSequenceCounter(CFE_SBR_RouteId_t RouteId) +{ + uint32 seqcnt = 0; + + if (CFE_SBR_IsValidRouteId(RouteId)) + { + seqcnt = CFE_SBR_RDATA.RoutingTbl[CFE_SBR_RouteIdToValue(RouteId)].SeqCnt; + } + + return seqcnt; +} + +/****************************************************************************** + * Local helper function for throttling foreach routines + * + * Updates StartIdxPtr, EndIdxPtr and ThrottlePtr.NextIndex. Note EndIdxPtr + * must be set to maximum prior to calling. + */ +void CFE_SBR_Throttle(uint32 *StartIdxPtr, uint32 *EndIdxPtr, CFE_SBR_Throttle_t *ThrottlePtr) +{ + if (ThrottlePtr != NULL) + { + *StartIdxPtr = ThrottlePtr->StartIndex; + + /* Return next index of zero if full range is processed */ + ThrottlePtr->NextIndex = 0; + + if ((*StartIdxPtr + ThrottlePtr->MaxLoop) < *EndIdxPtr) + { + *EndIdxPtr = *StartIdxPtr + ThrottlePtr->MaxLoop; + ThrottlePtr->NextIndex = *EndIdxPtr; + } + } +} + +/****************************************************************************** + * Interface function - see API for description + */ +void CFE_SBR_ForEachRouteId(CFE_SBR_CallbackPtr_t CallbackPtr, void *ArgPtr, CFE_SBR_Throttle_t *ThrottlePtr) +{ + CFE_SB_RouteId_Atom_t routeidx; + CFE_SB_MsgId_Atom_t startidx = 0; + CFE_SB_MsgId_Atom_t endidx = CFE_SBR_RDATA.RouteIdxTop; + + /* Update throttle settings if needed */ + CFE_SBR_Throttle(&startidx, &endidx, ThrottlePtr); + + for (routeidx = startidx; routeidx < endidx; routeidx++) + { + (*CallbackPtr)(CFE_SBR_ValueToRouteId(routeidx), ArgPtr); + } +} diff --git a/modules/sbr/unit-test-coverage/CMakeLists.txt b/modules/sbr/unit-test-coverage/CMakeLists.txt new file mode 100644 index 000000000..95b22232e --- /dev/null +++ b/modules/sbr/unit-test-coverage/CMakeLists.txt @@ -0,0 +1,59 @@ +################################################################## +# +# cFE unit test build recipe +# +# This CMake file contains the recipe for building the cFE unit tests. +# It is invoked from the parent directory when unit tests are enabled. +# +################################################################## + +# Set tests once so name changes are in one location +set(SBR_TEST_MAP_DIRECT "sbr_map_direct") +set(SBR_TEST_MAP_HASH "sbr_map_hash") +set(SBR_TEST_ROUTE_UNSORTED "sbr_route_unsorted") + +# All coverage tests always built +set(SBR_TEST_SET ${SBR_TEST_MAP_DIRECT} ${SBR_TEST_MAP_HASH} ${SBR_TEST_ROUTE_UNSORTED}) + +# Add configured map implementation to routing test source +if (MISSION_MSGMAP_IMPLEMENTATION STREQUAL "DIRECT") + set(${SBR_TEST_ROUTE_UNSORTED}_SRC ../src/cfe_sbr_map_direct.c) +elseif (MISSION_MSGMAP_IMPLEMENTATION STREQUAL "HASH") + set(${SBR_TEST_ROUTE_UNSORTED}_SRC ../src/cfe_sbr_map_hash.c) +endif() + +# Add route implementation to map hash +set(${SBR_TEST_MAP_HASH}_SRC ../src/cfe_sbr_route_unsorted.c) + +foreach(SBR_TEST ${SBR_TEST_SET}) + + # Unit test object library sources, options, and includes + add_library(ut_${SBR_TEST}_objs OBJECT ${${SBR_TEST}_SRC} ../src/cfe_${SBR_TEST}.c) + target_compile_options(ut_${SBR_TEST}_objs PRIVATE ${UT_COVERAGE_COMPILE_FLAGS}) + target_include_directories(ut_${SBR_TEST}_objs PRIVATE + $) + + set (ut_${SBR_TEST}_tests + test_cfe_${SBR_TEST}.c + $) + + # Add executable + add_executable(${SBR_TEST}_UT ${ut_${SBR_TEST}_tests}) + + # Add include to get private defaults + target_include_directories(${SBR_TEST}_UT PRIVATE ../private_inc) + + # Also add the UT_COVERAGE_LINK_FLAGS to the link command + # This should enable coverage analysis on platforms that support this + target_link_libraries(${SBR_TEST}_UT + ${UT_COVERAGE_LINK_FLAGS} + ut_cfe-core_support + ut_cfe-core_stubs + ut_assert) + + add_test(${SBR_TEST}_UT ${SBR_TEST}_UT) + foreach(TGT ${INSTALL_TARGET_LIST}) + install(TARGETS ${SBR_TEST}_UT DESTINATION ${TGT}/${UT_INSTALL_SUBDIR}) + endforeach() + +endforeach(SBR_TEST ${SBR_TEST_SET}) diff --git a/modules/sbr/unit-test-coverage/test_cfe_sbr_map_direct.c b/modules/sbr/unit-test-coverage/test_cfe_sbr_map_direct.c new file mode 100644 index 000000000..a47c3e388 --- /dev/null +++ b/modules/sbr/unit-test-coverage/test_cfe_sbr_map_direct.c @@ -0,0 +1,112 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/* + * Test SBR direct message map implementation + */ + +/* + * Includes + */ +#include "utassert.h" +#include "ut_support.h" +#include "private/cfe_sbr.h" +#include "cfe_sbr_priv.h" +#include + +void Test_SBR_Map_Direct(void) +{ + + CFE_SB_MsgId_Atom_t msgidx; + CFE_SBR_RouteId_t routeid; + CFE_SB_MsgId_t msgid; + uint32 count; + uint32 i; + + UtPrintf("Invalid msg checks"); + ASSERT_EQ(CFE_SBR_SetRouteId(CFE_SB_ValueToMsgId(0), CFE_SBR_ValueToRouteId(0)), 0); + ASSERT_EQ(CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(0))), false); + + UtPrintf("Initialize map"); + CFE_SBR_Init_Map(); + + /* Force valid msgid responses */ + UT_SetForceFail(UT_KEY(CFE_SB_IsValidMsgId), true); + + UtPrintf("Check that all entries are set invalid"); + count = 0; + for (msgidx = 0; msgidx <= CFE_PLATFORM_SB_HIGHEST_VALID_MSGID; msgidx++) + { + if (!CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(msgidx)))) + { + count++; + } + } + ASSERT_EQ(count, CFE_PLATFORM_SB_HIGHEST_VALID_MSGID + 1); + + UtPrintf("Set/Get a range of ids "); + routeid = CFE_SBR_ValueToRouteId(CFE_PLATFORM_SB_MAX_MSG_IDS + 1); + msgid = CFE_SB_ValueToMsgId(0); + ASSERT_EQ(CFE_SBR_SetRouteId(msgid, routeid), 0); + ASSERT_EQ(CFE_SBR_GetRouteId(msgid).RouteId, routeid.RouteId); + + routeid = CFE_SBR_ValueToRouteId(0); + msgid = CFE_SB_ValueToMsgId(CFE_PLATFORM_SB_HIGHEST_VALID_MSGID); + ASSERT_EQ(CFE_SBR_SetRouteId(msgid, routeid), 0); + ASSERT_EQ(CFE_SBR_GetRouteId(msgid).RouteId, routeid.RouteId); + + UtPrintf("Check there is now 1 valid entry in map"); + count = 0; + for (msgidx = 0; msgidx <= CFE_PLATFORM_SB_HIGHEST_VALID_MSGID; msgidx++) + { + if (!CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(msgidx)))) + { + count++; + } + } + ASSERT_EQ(count, CFE_PLATFORM_SB_HIGHEST_VALID_MSGID); + + UtPrintf("Set back to invalid and check again"); + routeid = CFE_SBR_INVALID_ROUTE_ID; + ASSERT_EQ(CFE_SBR_SetRouteId(msgid, routeid), 0); + ASSERT_EQ(CFE_SBR_GetRouteId(msgid).RouteId, routeid.RouteId); + ASSERT_EQ(CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(msgid)), false); + + /* Performance check, 0xFFFFFF on 3.2GHz linux box is around 8-9 seconds */ + count = 0; + for (i = 0; i <= 0xFFFF; i++) + { + msgidx = rand() % CFE_PLATFORM_SB_HIGHEST_VALID_MSGID; + if (CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(msgidx)))) + { + count++; + } + } + UtPrintf("Valid route id's encountered in performance loop: %u", count); +} + +/* Main unit test routine */ +void UtTest_Setup(void) +{ + UT_Init("map_direct"); + UtPrintf("Software Bus Routing direct map coverage test..."); + + UT_ADD_TEST(Test_SBR_Map_Direct); +} diff --git a/modules/sbr/unit-test-coverage/test_cfe_sbr_map_hash.c b/modules/sbr/unit-test-coverage/test_cfe_sbr_map_hash.c new file mode 100644 index 000000000..6e93d257b --- /dev/null +++ b/modules/sbr/unit-test-coverage/test_cfe_sbr_map_hash.c @@ -0,0 +1,118 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/* + * Test SBR direct message map implementation + */ + +/* + * Includes + */ +#include "utassert.h" +#include "ut_support.h" +#include "private/cfe_sbr.h" +#include "cfe_sbr_priv.h" + +/* + * Defines + */ + +/* Unhash magic number */ +#define CFE_SBR_UNHASH_MAGIC (0x119de1f3) + +/****************************************************************************** + * Local helper to unhash + */ +CFE_SB_MsgId_t Test_SBR_Unhash(CFE_SB_MsgId_Atom_t Hash) +{ + + Hash = ((Hash >> 16) ^ Hash) * CFE_SBR_UNHASH_MAGIC; + Hash = ((Hash >> 16) ^ Hash) * CFE_SBR_UNHASH_MAGIC; + Hash = (Hash >> 16) ^ Hash; + + return CFE_SB_ValueToMsgId(Hash); +} + +void Test_SBR_Map_Hash(void) +{ + + CFE_SB_MsgId_Atom_t msgidx; + CFE_SBR_RouteId_t routeid[3]; + CFE_SB_MsgId_t msgid[3]; + uint32 count; + uint32 collisions; + + UtPrintf("Invalid msg checks"); + ASSERT_EQ(CFE_SBR_SetRouteId(CFE_SB_ValueToMsgId(0), CFE_SBR_ValueToRouteId(0)), 0); + ASSERT_EQ(CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(0))), false); + + UtPrintf("Initialize routing and map"); + CFE_SBR_Init(); + + /* Force valid msgid responses */ + UT_SetForceFail(UT_KEY(CFE_SB_IsValidMsgId), true); + + UtPrintf("Check that all entries are set invalid"); + count = 0; + for (msgidx = 0; msgidx <= CFE_PLATFORM_SB_HIGHEST_VALID_MSGID; msgidx++) + { + if (!CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(msgidx)))) + { + count++; + } + } + ASSERT_EQ(count, CFE_PLATFORM_SB_HIGHEST_VALID_MSGID + 1); + + /* Note AddRoute required for hash logic to work since it depends on MsgId in routing table */ + UtPrintf("Add routes and check with a rollover and a skip"); + msgid[0] = CFE_SB_ValueToMsgId(0); + msgid[1] = Test_SBR_Unhash(0xFFFFFFFF); + msgid[2] = Test_SBR_Unhash(0x7FFFFFFF); + routeid[0] = CFE_SBR_AddRoute(msgid[0], &collisions); + ASSERT_EQ(collisions, 0); + routeid[1] = CFE_SBR_AddRoute(msgid[1], &collisions); + ASSERT_EQ(collisions, 0); + routeid[2] = CFE_SBR_AddRoute(msgid[2], &collisions); + ASSERT_EQ(collisions, 2); + + ASSERT_EQ(CFE_SBR_RouteIdToValue(CFE_SBR_GetRouteId(msgid[0])), CFE_SBR_RouteIdToValue(routeid[0])); + ASSERT_EQ(CFE_SBR_RouteIdToValue(CFE_SBR_GetRouteId(msgid[1])), CFE_SBR_RouteIdToValue(routeid[1])); + ASSERT_EQ(CFE_SBR_RouteIdToValue(CFE_SBR_GetRouteId(msgid[2])), CFE_SBR_RouteIdToValue(routeid[2])); + + /* Performance check, 0xFFFFFF on 3.2GHz linux box is around 8-9 seconds */ + count = 0; + for (msgidx = 0; msgidx <= 0xFFFF; msgidx++) + { + if (CFE_SBR_IsValidRouteId(CFE_SBR_GetRouteId(CFE_SB_ValueToMsgId(msgidx)))) + { + count++; + } + } + UtPrintf("Valid route id's encountered in performance loop: %u", count); +} + +/* Main unit test routine */ +void UtTest_Setup(void) +{ + UT_Init("map_hash"); + UtPrintf("Software Bus Routing hash map coverage test..."); + + UT_ADD_TEST(Test_SBR_Map_Hash); +} diff --git a/modules/sbr/unit-test-coverage/test_cfe_sbr_route_unsorted.c b/modules/sbr/unit-test-coverage/test_cfe_sbr_route_unsorted.c new file mode 100644 index 000000000..ac44c2ec7 --- /dev/null +++ b/modules/sbr/unit-test-coverage/test_cfe_sbr_route_unsorted.c @@ -0,0 +1,198 @@ +/* +** GSC-18128-1, "Core Flight Executive Version 6.7" +** +** Copyright (c) 2006-2019 United States Government as represented by +** the Administrator of the National Aeronautics and Space Administration. +** All Rights Reserved. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +/* + * Test SBR unsorted route implementation + */ + +/* + * Includes + */ +#include "utassert.h" +#include "ut_support.h" +#include "private/cfe_sbr.h" +#include "cfe_sbr_priv.h" + +/* Callback function for testing */ +void Test_SBR_Callback(CFE_SBR_RouteId_t RouteId, void *ArgPtr) +{ + uint32 *count = ArgPtr; + + (*count)++; +} + +void Test_SBR_Route_Unsort_General(void) +{ + + CFE_SBR_RouteId_t routeid; + CFE_SB_MsgId_t msgid; + uint32 collisions; + uint32 count; + CFE_SBR_Throttle_t throttle; + + UtPrintf("Initialize map and route"); + CFE_SBR_Init(); + + UtPrintf("Invalid msg checks"); + ASSERT_TRUE(!CFE_SBR_IsValidRouteId(CFE_SBR_AddRoute(CFE_SB_ValueToMsgId(0), NULL))); + ASSERT_TRUE(!CFE_SBR_IsValidRouteId(CFE_SBR_AddRoute(CFE_SB_ValueToMsgId(0), &collisions))); + ASSERT_EQ(collisions, 0); + + /* + * Force valid msgid responses + * Note from here on msgids must be in the valid range since validation is forced true + * and if the underlying map implentation is direct it needs to be a valid array index + */ + UT_SetForceFail(UT_KEY(CFE_SB_IsValidMsgId), true); + + UtPrintf("Callback test with no routes"); + count = 0; + CFE_SBR_ForEachRouteId(Test_SBR_Callback, &count, NULL); + ASSERT_EQ(count, 0); + + UtPrintf("Add maximum mesage id value"); + msgid = CFE_SB_ValueToMsgId(CFE_PLATFORM_SB_HIGHEST_VALID_MSGID); + routeid = CFE_SBR_AddRoute(msgid, &collisions); + ASSERT_EQ(collisions, 0); + ASSERT_TRUE(CFE_SBR_IsValidRouteId(routeid)); + + UtPrintf("Callback test with one route"); + count = 0; + CFE_SBR_ForEachRouteId(Test_SBR_Callback, &count, NULL); + ASSERT_EQ(count, 1); + + UtPrintf("Fill routing table"); + count = 0; + while (CFE_SBR_IsValidRouteId(CFE_SBR_AddRoute(CFE_SB_ValueToMsgId(count), NULL))) + { + count++; + } + + /* Check for expected count indicating full routing table */ + ASSERT_EQ(count + 1, CFE_PLATFORM_SB_MAX_MSG_IDS); + + /* Try one more for good luck */ + ASSERT_TRUE(!CFE_SBR_IsValidRouteId(CFE_SBR_AddRoute(CFE_SB_ValueToMsgId(count), NULL))); + + /* Check that maximum msgid is still in the table */ + ASSERT_EQ(CFE_SB_MsgIdToValue(CFE_SBR_GetMsgId(routeid)), CFE_PLATFORM_SB_HIGHEST_VALID_MSGID); + ASSERT_EQ(CFE_SBR_GetRouteId(msgid).RouteId, routeid.RouteId); + + UtPrintf("Callback test with full route"); + count = 0; + CFE_SBR_ForEachRouteId(Test_SBR_Callback, &count, NULL); + ASSERT_EQ(count, CFE_PLATFORM_SB_MAX_MSG_IDS); + + UtPrintf("Callback test throttled"); + throttle.MaxLoop = CFE_PLATFORM_SB_MAX_MSG_IDS - 1; + throttle.StartIndex = 0; + count = 0; + CFE_SBR_ForEachRouteId(Test_SBR_Callback, &count, &throttle); + ASSERT_EQ(count, CFE_PLATFORM_SB_MAX_MSG_IDS - 1); + count = 0; + throttle.StartIndex = throttle.NextIndex; + CFE_SBR_ForEachRouteId(Test_SBR_Callback, &count, &throttle); + ASSERT_EQ(count, 1); +} + +void Test_SBR_Route_Unsort_GetSet(void) +{ + + CFE_SB_RouteId_Atom_t routeidx; + CFE_SB_MsgId_t msgid[3]; + CFE_SBR_RouteId_t routeid[3]; + CFE_SB_DestinationD_t dest[2]; + uint32 count; + uint32 i; + + UtPrintf("Invalid route ID checks"); + routeid[0] = CFE_SBR_INVALID_ROUTE_ID; + routeid[1] = CFE_SBR_ValueToRouteId(CFE_PLATFORM_SB_MAX_MSG_IDS); + for (i = 0; i < 2; i++) + { + ASSERT_TRUE(CFE_SB_MsgId_Equal(CFE_SBR_GetMsgId(routeid[i]), CFE_SB_INVALID_MSG_ID)); + UtAssert_ADDRESS_EQ(CFE_SBR_GetDestListHeadPtr(routeid[i]), NULL); + ASSERT_EQ(CFE_SBR_GetSequenceCounter(routeid[i]), 0); + } + + /* + * Force valid msgid responses + * Note from here on msgids must be in the valid range since validation is forced true + * and if the underlying map implentation is direct it needs to be a valid array index + */ + UT_SetForceFail(UT_KEY(CFE_SB_IsValidMsgId), true); + + UtPrintf("Initialize map and route"); + CFE_SBR_Init(); + + UtPrintf("Confirm values initialized for all routes"); + count = 0; + for (routeidx = 0; routeidx < CFE_PLATFORM_SB_MAX_MSG_IDS; routeidx++) + { + routeid[0] = CFE_SBR_ValueToRouteId(routeidx); + if (!CFE_SB_MsgId_Equal(CFE_SBR_GetMsgId(routeid[0]), CFE_SB_INVALID_MSG_ID) || + (CFE_SBR_GetDestListHeadPtr(routeid[0]) != NULL) || (CFE_SBR_GetSequenceCounter(routeid[0]) != 0)) + { + count++; + } + } + ASSERT_EQ(count, 0); + + UtPrintf("Add routes and initialize values for testing"); + msgid[0] = CFE_SB_ValueToMsgId(0); + msgid[1] = CFE_SB_ValueToMsgId(1); + msgid[2] = CFE_SB_ValueToMsgId(CFE_PLATFORM_SB_HIGHEST_VALID_MSGID); + + /* Add routes */ + for (i = 0; i < 3; i++) + { + routeid[i] = CFE_SBR_AddRoute(msgid[i], NULL); + } + + /* Check the msgid matches and increment a sequence counter */ + for (i = 0; i < 3; i++) + { + ASSERT_TRUE(CFE_SB_MsgId_Equal(msgid[i], CFE_SBR_GetMsgId(routeid[i]))); + CFE_SBR_IncrementSequenceCounter(routeid[0]); + } + + /* Increment route 1 once and set dest pointers */ + CFE_SBR_IncrementSequenceCounter(routeid[1]); + CFE_SBR_SetDestListHeadPtr(routeid[1], &dest[1]); + CFE_SBR_SetDestListHeadPtr(routeid[2], &dest[0]); + + UtPrintf("Verify remaining set values"); + ASSERT_EQ(CFE_SBR_GetSequenceCounter(routeid[0]), 3); + ASSERT_EQ(CFE_SBR_GetSequenceCounter(routeid[1]), 1); + ASSERT_EQ(CFE_SBR_GetSequenceCounter(routeid[2]), 0); + UtAssert_ADDRESS_EQ(CFE_SBR_GetDestListHeadPtr(routeid[0]), NULL); + UtAssert_ADDRESS_EQ(CFE_SBR_GetDestListHeadPtr(routeid[1]), &dest[1]); + UtAssert_ADDRESS_EQ(CFE_SBR_GetDestListHeadPtr(routeid[2]), &dest[0]); +} + +/* Main unit test routine */ +void UtTest_Setup(void) +{ + UT_Init("route_unsort"); + UtPrintf("Software Bus Routing unsorted coverage test..."); + + UT_ADD_TEST(Test_SBR_Route_Unsort_General); + UT_ADD_TEST(Test_SBR_Route_Unsort_GetSet); +}