From bf24986542b6e729c04f0d2d374a7cdbd2b886a6 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Thu, 9 Apr 2020 16:33:43 -0400 Subject: [PATCH] Fix #295, Move app table management to background task Create a new background job to handle the maintenance tasks that had been performed in the ES main task as part of the CFE_ES_ScanAppTable() routine. All app state changes, including those invoked by messages, are now handled by this job. This also slightly changes the semantics of CFE_ES_RunLoop and CFE_ES_ExitApp. Now, the CFE_ES_RunLoop routine no longer requires a RunStatus buffer. Instead, the only thing that matters is the RunStatus value that is eventually passed to CFE_ES_ExitApp after the shutdown is complete. This should be mostly backward compatible, as the recommended app pattern would pass the same value to both functions. This commit also fixes #480, as the value passed to CFE_ES_ExitApp will not override a request that was already pending. --- fsw/cfe-core/src/es/cfe_es_api.c | 462 ++++++++---------- fsw/cfe-core/src/es/cfe_es_apps.c | 338 +++++++------ fsw/cfe-core/src/es/cfe_es_apps.h | 40 +- fsw/cfe-core/src/es/cfe_es_backgroundtask.c | 6 + fsw/cfe-core/src/es/cfe_es_task.c | 19 +- fsw/cfe-core/src/es/cfe_es_task.h | 5 + fsw/cfe-core/src/inc/cfe_es_extern_typedefs.h | 19 +- fsw/cfe-core/unit-test/es_UT.c | 75 ++- 8 files changed, 509 insertions(+), 455 deletions(-) diff --git a/fsw/cfe-core/src/es/cfe_es_api.c b/fsw/cfe-core/src/es/cfe_es_api.c index 44e528037..b863f1f69 100644 --- a/fsw/cfe-core/src/es/cfe_es_api.c +++ b/fsw/cfe-core/src/es/cfe_es_api.c @@ -19,10 +19,10 @@ */ /* -** File: +** File: ** cfe_es_api.c ** -** Purpose: +** Purpose: ** This file implements the cFE Executive Services API functions. ** ** References: @@ -73,7 +73,7 @@ int32 CFE_ES_GetResetType(uint32 *ResetSubtypePtr) int32 CFE_ES_ResetCFE(uint32 ResetType) { int32 ReturnCode; - + if ( ResetType == CFE_PSP_RST_TYPE_PROCESSOR ) { /* @@ -82,10 +82,10 @@ int32 CFE_ES_ResetCFE(uint32 ResetType) CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount++; /* - ** Before doing a Processor reset, check to see + ** Before doing a Processor reset, check to see ** if the maximum number has been exceeded */ - if ( CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount > + if ( CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount > CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount ) { CFE_ES_WriteToSysLog("POWER ON RESET due to max proc resets (Commanded).\n"); @@ -98,7 +98,7 @@ int32 CFE_ES_ResetCFE(uint32 ResetType) CFE_PSP_RST_SUBTYPE_RESET_COMMAND, "POWER ON RESET due to max proc resets (Commanded).", NULL,0 ); /* - ** Call the BSP reset routine + ** Call the BSP reset routine */ CFE_PSP_Restart(CFE_PSP_RST_TYPE_POWERON); } @@ -121,12 +121,12 @@ int32 CFE_ES_ResetCFE(uint32 ResetType) ** Call the BSP reset routine */ CFE_PSP_Restart(CFE_PSP_RST_TYPE_PROCESSOR); - + } /* end if */ - - /* - ** If the BSP routine is not implemented, - ** it will return. + + /* + ** If the BSP routine is not implemented, + ** it will return. */ ReturnCode = CFE_ES_NOT_IMPLEMENTED; } @@ -146,10 +146,10 @@ int32 CFE_ES_ResetCFE(uint32 ResetType) ** Call the BSP reset routine */ CFE_PSP_Restart(CFE_PSP_RST_TYPE_POWERON); - - /* - ** If the BSP routine is not implemented, - ** it will return. + + /* + ** If the BSP routine is not implemented, + ** it will return. */ ReturnCode = CFE_ES_NOT_IMPLEMENTED; } @@ -160,49 +160,8 @@ int32 CFE_ES_ResetCFE(uint32 ResetType) } return(ReturnCode); - -} /* End of CFE_ES_ResetCFE() */ - -/* - * Function: CFE_ES_SetAppState - * - * Purpose: Internal ES function to set the state of an app. This performs - * any necessary internal housekeeping related to the state change, - * and provides a single place to keep logic for state entry/exit. - * - * The typical progression of APP states: - * - * UNDEFINED -> EARLY_INIT -> LATE_INIT -> RUNNING -> WAITING - * - * State can go to "STOPPED" (the last state) from any state. This is used for error conditions. - * - * NOTE: This is an ES internal function and must only be called when the ES global state is already locked. - * - */ -void CFE_ES_SetAppState(uint32 AppID, uint32 TargetState) -{ - CFE_ES_AppRecord_t *AppState = &CFE_ES_Global.AppTable[AppID]; - - if (TargetState >= CFE_ES_AppState_MAX) - { - /* Caller error - invalid state */ - return; - } - - /* - * States should not move backward under normal circumstances. - * - * This relational comparison depends on the app states being defined in logical order - * (they should be) - */ - if (TargetState != CFE_ES_AppState_UNDEFINED && AppState->AppState >= TargetState) - { - /* Do nothing */ - return; - } - AppState->AppState = TargetState; -} +} /* End of CFE_ES_ResetCFE() */ /* ** Function: CFE_ES_RestartApp - See API and header file for details @@ -215,7 +174,7 @@ int32 CFE_ES_RestartApp(uint32 AppID) { CFE_ES_LockSharedData(__func__,__LINE__); - + /* ** Check to see if the App is an external cFE App. */ @@ -223,23 +182,21 @@ int32 CFE_ES_RestartApp(uint32 AppID) { CFE_ES_SysLogWrite_Unsync ("CFE_ES_DeleteApp: Cannot Restart a CORE Application: %s.\n", CFE_ES_Global.AppTable[AppID].StartParams.Name ); - ReturnCode = CFE_ES_ERR_APPID; + ReturnCode = CFE_ES_ERR_APPID; } else if ( CFE_ES_Global.AppTable[AppID].AppState != CFE_ES_AppState_RUNNING ) { CFE_ES_SysLogWrite_Unsync ("CFE_ES_RestartApp: Cannot Restart Application %s, It is not running.\n", CFE_ES_Global.AppTable[AppID].StartParams.Name); - ReturnCode = CFE_ES_ERR_APPID; + ReturnCode = CFE_ES_ERR_APPID; } else { CFE_ES_SysLogWrite_Unsync("CFE_ES_RestartApp: Restart Application %s Initiated\n", CFE_ES_Global.AppTable[AppID].StartParams.Name); CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RESTART; - CFE_ES_SetAppState(AppID, CFE_ES_AppState_WAITING); - CFE_ES_Global.AppTable[AppID].ControlReq.AppTimer = CFE_PLATFORM_ES_APP_KILL_TIMEOUT; } - + CFE_ES_UnlockSharedData(__func__,__LINE__); } else /* App ID is not valid */ @@ -264,22 +221,22 @@ int32 CFE_ES_ReloadApp(uint32 AppID, const char *AppFileName) os_fstat_t FileStatus; CFE_ES_LockSharedData(__func__,__LINE__); - + /* ** Check to see if the App is an external cFE App. */ if ( CFE_ES_Global.AppTable[AppID].Type == CFE_ES_AppType_CORE ) { - CFE_ES_SysLogWrite_Unsync ("CFE_ES_DeleteApp: Cannot Reload a CORE Application: %s.\n", + CFE_ES_SysLogWrite_Unsync ("CFE_ES_DeleteApp: Cannot Reload a CORE Application: %s.\n", CFE_ES_Global.AppTable[AppID].StartParams.Name ); - ReturnCode = CFE_ES_ERR_APPID; + ReturnCode = CFE_ES_ERR_APPID; } else if ( CFE_ES_Global.AppTable[AppID].AppState != CFE_ES_AppState_RUNNING ) { CFE_ES_SysLogWrite_Unsync ("CFE_ES_ReloadApp: Cannot Reload Application %s, It is not running.\n", CFE_ES_Global.AppTable[AppID].StartParams.Name); - ReturnCode = CFE_ES_ERR_APPID; - } + ReturnCode = CFE_ES_ERR_APPID; + } else { /* @@ -287,12 +244,10 @@ int32 CFE_ES_ReloadApp(uint32 AppID, const char *AppFileName) */ if (OS_stat(AppFileName, &FileStatus) == OS_SUCCESS) { - CFE_ES_SysLogWrite_Unsync("CFE_ES_ReloadApp: Reload Application %s Initiated. New filename = %s\n", + CFE_ES_SysLogWrite_Unsync("CFE_ES_ReloadApp: Reload Application %s Initiated. New filename = %s\n", CFE_ES_Global.AppTable[AppID].StartParams.Name, AppFileName); strncpy((char *)CFE_ES_Global.AppTable[AppID].StartParams.FileName, AppFileName, OS_MAX_PATH_LEN); CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RELOAD; - CFE_ES_SetAppState(AppID, CFE_ES_AppState_WAITING); - CFE_ES_Global.AppTable[AppID].ControlReq.AppTimer = CFE_PLATFORM_ES_APP_KILL_TIMEOUT; } else { @@ -302,9 +257,9 @@ int32 CFE_ES_ReloadApp(uint32 AppID, const char *AppFileName) ReturnCode = CFE_ES_FILE_IO_ERR; } } - + CFE_ES_UnlockSharedData(__func__,__LINE__); - + return(ReturnCode); } /* End of CFE_ES_ReloadApp() */ @@ -317,33 +272,31 @@ int32 CFE_ES_DeleteApp(uint32 AppID) int32 ReturnCode = CFE_SUCCESS; CFE_ES_LockSharedData(__func__,__LINE__); - + /* ** Check to see if the App is an external cFE App. */ if ( CFE_ES_Global.AppTable[AppID].Type == CFE_ES_AppType_CORE ) { - CFE_ES_SysLogWrite_Unsync ("CFE_ES_DeleteApp: Cannot Delete a CORE Application: %s.\n", + CFE_ES_SysLogWrite_Unsync ("CFE_ES_DeleteApp: Cannot Delete a CORE Application: %s.\n", CFE_ES_Global.AppTable[AppID].StartParams.Name ); - ReturnCode = CFE_ES_ERR_APPID; + ReturnCode = CFE_ES_ERR_APPID; } else if ( CFE_ES_Global.AppTable[AppID].AppState != CFE_ES_AppState_RUNNING ) { CFE_ES_SysLogWrite_Unsync ("CFE_ES_DeleteApp: Cannot Delete Application %s, It is not running.\n", CFE_ES_Global.AppTable[AppID].StartParams.Name); - ReturnCode = CFE_ES_ERR_APPID; + ReturnCode = CFE_ES_ERR_APPID; } else { CFE_ES_SysLogWrite_Unsync("CFE_ES_DeleteApp: Delete Application %s Initiated\n", - CFE_ES_Global.AppTable[AppID].StartParams.Name); + CFE_ES_Global.AppTable[AppID].StartParams.Name); CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_DELETE; - CFE_ES_SetAppState(AppID, CFE_ES_AppState_WAITING); - CFE_ES_Global.AppTable[AppID].ControlReq.AppTimer = CFE_PLATFORM_ES_APP_KILL_TIMEOUT; } - + CFE_ES_UnlockSharedData(__func__,__LINE__); - + return(ReturnCode); } /* End of CFE_ES_DeleteApp() */ @@ -359,15 +312,12 @@ void CFE_ES_ExitApp(uint32 ExitStatus) CFE_ES_LockSharedData(__func__,__LINE__); /* - * This should only be called with an ExitStatus of either APP_EXIT or APP_ERROR. - * Anything else is invalid and indicates a bug in the caller. In particular, - * if called with APP_RUN then this creates an invalid state (see bug #58). + * This should only be called with a valid ExitStatus, anything else is invalid + * and indicates a bug in the caller. */ - if (ExitStatus != CFE_ES_RunStatus_APP_EXIT && - ExitStatus != CFE_ES_RunStatus_APP_ERROR && - ExitStatus != CFE_ES_RunStatus_CORE_APP_INIT_ERROR && - ExitStatus != CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR) + if (ExitStatus == CFE_ES_RunStatus_UNDEFINED || + ExitStatus >= CFE_ES_RunStatus_MAX) { CFE_ES_SysLogWrite_Unsync ("CFE_ES_ExitApp: Called with invalid status (%u).\n", (unsigned int)ExitStatus); @@ -379,8 +329,20 @@ void CFE_ES_ExitApp(uint32 ExitStatus) ReturnCode = CFE_ES_GetAppIDInternal(&AppID); if ( ReturnCode == CFE_SUCCESS ) { - /* Set the status in the global table */ - CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest = ExitStatus; + /* + * Set the status in the global table. + * + * The passed-in status should only be stored if there was no already-pending + * request from a ground command or other source, such as an exception, etc. + * + * If a control request is already pending, it is assumed that this exit is + * part of an orderly shutdown caused by that request, and therefore it + * should not be overwritten here. + */ + if (CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest == CFE_ES_RunStatus_APP_RUN) + { + CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest = ExitStatus; + } /* ** Check to see if the App is an external cFE App. @@ -394,16 +356,16 @@ void CFE_ES_ExitApp(uint32 ExitStatus) { CFE_ES_SysLogWrite_Unsync ("CFE_ES_ExitApp: CORE Application %s Had an Init Error.\n", CFE_ES_Global.AppTable[AppID].StartParams.Name ); - + /* - ** Unlock the ES Shared data before calling ResetCFE + ** Unlock the ES Shared data before calling ResetCFE */ CFE_ES_UnlockSharedData(__func__,__LINE__); - - + + /* ** Do a Processor Reset the cFE - */ + */ ReturnCode = CFE_ES_ResetCFE(CFE_PSP_RST_TYPE_PROCESSOR); /* @@ -415,44 +377,45 @@ void CFE_ES_ExitApp(uint32 ExitStatus) (unsigned int) ReturnCode); return; - + } else if ( ExitStatus == CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR ) { CFE_ES_SysLogWrite_Unsync ("CFE_ES_ExitApp: CORE Application %s Had a Runtime Error.\n", - CFE_ES_Global.AppTable[AppID].StartParams.Name ); - + CFE_ES_Global.AppTable[AppID].StartParams.Name ); + /* ** Unlock the ES Shared data before killing the main task */ CFE_ES_UnlockSharedData(__func__,__LINE__); - + /* ** Exit this task */ - OS_TaskExit(); - + OS_TaskExit(); + /* ** Code will not return, except under unit test */ return; } - else + else { CFE_ES_SysLogWrite_Unsync ("CFE_ES_ExitApp, Cannot Exit CORE Application %s\n", - CFE_ES_Global.AppTable[AppID].StartParams.Name ); + CFE_ES_Global.AppTable[AppID].StartParams.Name ); } - + } else /* It is an external App */ { - + CFE_ES_SysLogWrite_Unsync ("Application %s called CFE_ES_ExitApp\n", CFE_ES_Global.AppTable[AppID].StartParams.Name); - CFE_ES_SetAppState(AppID, CFE_ES_AppState_STOPPED); + + CFE_ES_Global.AppTable[AppID].AppState = CFE_ES_AppState_STOPPED; /* - ** Unlock the ES Shared data before suspending the app + ** Unlock the ES Shared data before suspending the app */ CFE_ES_UnlockSharedData(__func__,__LINE__); @@ -466,11 +429,11 @@ void CFE_ES_ExitApp(uint32 ExitStatus) } } /* end if */ - + } /* end if ReturnCode == CFE_SUCCESS */ CFE_ES_UnlockSharedData(__func__,__LINE__); - + } /* End of CFE_ES_ExitApp() */ /* @@ -481,8 +444,35 @@ bool CFE_ES_RunLoop(uint32 *RunStatus) bool ReturnCode; int32 Status; uint32 AppID; - uint32 TaskID; - + CFE_ES_AppRecord_t *AppRecPtr; + + /* + * call CFE_ES_IncrementTaskCounter() so this is + * recorded as task activity for outgoing telemetry. + * + * This will update the counter for whatever task context + * is calling this API, which is expected to be the main + * task of the app. This can be done outside of any lock + * because each task has its own counter which is only updated + * by itself. + */ + CFE_ES_IncrementTaskCounter(); + + /* + * This API should generally only be called with the status as CFE_ES_RunStatus_APP_RUN. + * Anything else gets an immediate "false" return which should cause the caller to + * break out of its main loop. There is no need to take the lock or do any other + * accounting in that case. + * + * Note that the RunStatus really doesn't add much value here, so this also allows + * this function to be called with NULL, with the possibility of phasing this out + * entirely. + */ + if ( RunStatus != NULL && *RunStatus != CFE_ES_RunStatus_APP_RUN ) + { + return false; + } + CFE_ES_LockSharedData(__func__,__LINE__); /* @@ -492,77 +482,44 @@ bool CFE_ES_RunLoop(uint32 *RunStatus) if ( Status == CFE_SUCCESS ) { - - /* - ** Get the Task ID for the main task - */ - OS_ConvertToArrayIndex(CFE_ES_Global.AppTable[AppID].TaskInfo.MainTaskId, &TaskID); - - /* - ** Increment the execution counter for the main task - */ - CFE_ES_Global.TaskTable[TaskID].ExecutionCounter++; - - /* - ** Validate RunStatus - */ - if ( *RunStatus == CFE_ES_RunStatus_APP_RUN || *RunStatus == CFE_ES_RunStatus_APP_EXIT || *RunStatus == CFE_ES_RunStatus_APP_ERROR ) - { - /* - ** Look up the system control request - */ - if ( *RunStatus == CFE_ES_RunStatus_APP_RUN ) - { - /* - ** App state must be RUNNING (no-op if already set to running) - */ - CFE_ES_SetAppState(AppID, CFE_ES_AppState_RUNNING); - - if ( CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest != CFE_ES_RunStatus_APP_RUN ) - { - /* - ** We have an external request to stop - */ - ReturnCode = false; - - } - else - { - /* - ** Everything is OK - */ - ReturnCode = true; - } - } - else - { - /* - ** Application wants to exit, so let it + AppRecPtr = &CFE_ES_Global.AppTable[AppID]; + + /* + ** App state must be RUNNING (no-op if already set to running) + */ + if (AppRecPtr->AppState < CFE_ES_AppState_RUNNING) + { + AppRecPtr->AppState = CFE_ES_AppState_RUNNING; + } + + /* + * Check if the control request is also set to "RUN" + * Anything else should also return false, so the the loop will exit. + */ + if ( AppRecPtr->ControlReq.AppControlRequest == CFE_ES_RunStatus_APP_RUN ) + { + ReturnCode = true; + } + else + { + /* + * Just in case, also output the status, just in case the app looks at this. */ - CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest = *RunStatus; - ReturnCode = false; - } - } - else - { - /* - ** Not a supported RunStatus code, the app will abort - */ - CFE_ES_SysLogWrite_Unsync("CFE_ES_RunLoop Error: Invalid RunStatus:%d!\n",(int)(*RunStatus)); - CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_ERROR; - ReturnCode = false; - - } /* End if *RunStatus == CFE_ES_RunStatus_APP_RUN .. */ - + if (RunStatus != NULL) + { + *RunStatus = AppRecPtr->ControlReq.AppControlRequest; + } + ReturnCode = false; + } } else { - /* - ** Cannot do anything without the AppID - */ - CFE_ES_SysLogWrite_Unsync("CFE_ES_RunLoop Error: Cannot get AppID for the caller: RC = %08X\n",(unsigned int)Status); - ReturnCode = false; - + /* + * Cannot do anything without the AppID + */ + CFE_ES_SysLogWrite_Unsync("CFE_ES_RunLoop Error: Cannot get AppID for the caller: RC = %08X\n",(unsigned int)Status); + ReturnCode = false; + } /* end if Status == CFE_SUCCESS */ CFE_ES_UnlockSharedData(__func__,__LINE__); @@ -627,7 +584,10 @@ int32 CFE_ES_WaitForSystemState(uint32 MinSystemState, uint32 TimeOutMillisecond * apps to add an explicit state change call, but it makes sense because if this was not done an app could * be waiting for itself (which will always time out). */ - CFE_ES_SetAppState(AppID, RequiredAppState); + if (CFE_ES_Global.AppTable[AppID].AppState < RequiredAppState) + { + CFE_ES_Global.AppTable[AppID].AppState = RequiredAppState; + } } CFE_ES_UnlockSharedData(__func__,__LINE__); @@ -683,7 +643,7 @@ int32 CFE_ES_RegisterApp(void) CFE_ES_LockSharedData(__func__,__LINE__); /* - ** Register the task + ** Register the task */ Result = OS_TaskRegister(); @@ -693,8 +653,8 @@ int32 CFE_ES_RegisterApp(void) } else { - /* - ** Cannot create a syslog entry here because it requires the task to + /* + ** Cannot create a syslog entry here because it requires the task to ** be registered */ Result = CFE_ES_ERR_APP_REGISTER; @@ -704,11 +664,11 @@ int32 CFE_ES_RegisterApp(void) ** Set the default exception environment */ CFE_PSP_SetDefaultExceptionEnvironment(); - + CFE_ES_UnlockSharedData(__func__,__LINE__); return(Result); - + } /* End of CFE_ES_RegisterApp() */ @@ -737,9 +697,9 @@ int32 CFE_ES_GetAppIDByName(uint32 *AppIdPtr, const char *AppName) } } } /* end for */ - + CFE_ES_UnlockSharedData(__func__,__LINE__); - + return(Result); } /* End of CFE_ES_GetAppIDByName() */ @@ -757,7 +717,7 @@ int32 CFE_ES_GetAppID(uint32 *AppIdPtr) Result = CFE_ES_GetAppIDInternal(AppIdPtr); CFE_ES_UnlockSharedData(__func__,__LINE__); - + return(Result); } /* End of CFE_ES_GetAppID() */ @@ -788,7 +748,7 @@ int32 CFE_ES_GetAppName(char *AppName, uint32 AppId, uint32 BufferLength) { Result = CFE_ES_ERR_APPID; } - + CFE_ES_UnlockSharedData(__func__,__LINE__); /* @@ -803,7 +763,7 @@ int32 CFE_ES_GetAppName(char *AppName, uint32 AppId, uint32 BufferLength) { AppName[0] = 0; } - + return(Result); } /* End of CFE_ES_GetAppName() */ @@ -908,7 +868,7 @@ int32 CFE_ES_GetTaskInfo(CFE_ES_TaskInfo_t *TaskInfo, uint32 OSTaskId) CFE_ES_SysLogWrite_Unsync("CFE_ES_GetTaskInfo: Task ID Not Active: %u\n",(unsigned int)OSTaskId); ReturnCode = CFE_ES_ERR_TASKID; } - + CFE_ES_UnlockSharedData(__func__,__LINE__); return(ReturnCode); @@ -960,11 +920,11 @@ int32 CFE_ES_CreateChildTask(uint32 *TaskIdPtr, CFE_ES_WriteToSysLog("CFE_ES_CreateChildTask: Function Pointer Parameter is NULL for Task '%s' (ID %d).\n",TaskName,(int)(*TaskIdPtr)); ReturnCode = CFE_ES_BAD_ARGUMENT; } - else + else { - + CFE_ES_LockSharedData(__func__,__LINE__); - + /* ** Get the AppID of the calling Application */ @@ -986,7 +946,7 @@ int32 CFE_ES_CreateChildTask(uint32 *TaskIdPtr, { /* ** Truncate the priority if needed - */ + */ if ( Priority > 255 ) { Priority = 255; @@ -1011,7 +971,7 @@ int32 CFE_ES_CreateChildTask(uint32 *TaskIdPtr, strncpy((char *)CFE_ES_Global.TaskTable[TaskId].TaskName,TaskName,OS_MAX_API_NAME); CFE_ES_Global.TaskTable[TaskId].TaskName[OS_MAX_API_NAME - 1] = '\0'; CFE_ES_Global.RegisteredTasks++; - + ReturnCode = CFE_SUCCESS; } else @@ -1019,20 +979,20 @@ int32 CFE_ES_CreateChildTask(uint32 *TaskIdPtr, CFE_ES_SysLogWrite_Unsync("CFE_ES_CreateChildTask: Error calling OS_TaskCreate for Task '%s' RC = 0x%08X\n",TaskName,(unsigned int)Result); ReturnCode = CFE_ES_ERR_CHILD_TASK_CREATE; } - } + } else { CFE_ES_SysLogWrite_Unsync("CFE_ES_CreateChildTask: Error: Cannot call from a Child Task (for Task '%s').\n",TaskName); ReturnCode = CFE_ES_ERR_CHILD_TASK_CREATE; - + } /* end if Calling task is a main task */ - + }/* end If AppID is valid */ - + CFE_ES_UnlockSharedData(__func__,__LINE__); } /* end if parameter checking */ - + return(ReturnCode); } /* End of CFE_ES_CreateChildTask() */ @@ -1049,23 +1009,23 @@ int32 CFE_ES_RegisterChildTask(void) CFE_ES_LockSharedData(__func__,__LINE__); /* - ** Register the task with the OS + ** Register the task with the OS */ Result = OS_TaskRegister(); if (Result != OS_SUCCESS) { - /* - ** Cannot create a syslog entry here because it requires the task to + /* + ** Cannot create a syslog entry here because it requires the task to ** be registered */ ReturnCode = CFE_ES_ERR_CHILD_TASK_REGISTER; } else - { + { ReturnCode = CFE_SUCCESS; } - + /* ** Set the default exception environment */ @@ -1088,7 +1048,7 @@ void CFE_ES_IncrementTaskCounter(void) { CFE_ES_Global.TaskTable[TaskId].ExecutionCounter++; } - + } /* End of CFE_ES_ExitChildTask() */ @@ -1111,7 +1071,7 @@ int32 CFE_ES_DeleteChildTask(uint32 OSTaskId) if (OS_ConvertToArrayIndex(OSTaskId, &TaskId) == OS_SUCCESS) { CFE_ES_LockSharedData(__func__,__LINE__); - + /* ** Make sure the task is active/valid */ @@ -1132,11 +1092,11 @@ int32 CFE_ES_DeleteChildTask(uint32 OSTaskId) ** Error, the task Id is an App Main Task ID */ TaskIsMain = true; - break; + break; } /* end if */ } /* end if */ } /* end for */ - + if ( TaskIsMain == false ) { /* @@ -1180,11 +1140,11 @@ int32 CFE_ES_DeleteChildTask(uint32 OSTaskId) */ CFE_ES_SysLogWrite_Unsync("CFE_ES_DeleteChildTask Error: Task ID is not active: %u\n",(unsigned int)OSTaskId ); ReturnCode = CFE_ES_ERR_TASKID; - + } /* end if */ - + CFE_ES_UnlockSharedData(__func__,__LINE__); - + } else { @@ -1193,7 +1153,7 @@ int32 CFE_ES_DeleteChildTask(uint32 OSTaskId) */ CFE_ES_WriteToSysLog("CFE_ES_DeleteChildTask Error: Invalid Task ID: %u\n",(unsigned int)OSTaskId ); ReturnCode = CFE_ES_ERR_TASKID; - + } return(ReturnCode); @@ -1209,17 +1169,17 @@ void CFE_ES_ExitChildTask(void) { uint32 TaskId; uint32 ParentTaskId; - uint32 AppId; + uint32 AppId; uint32 ReturnCode; CFE_ES_LockSharedData(__func__,__LINE__); /* - ** Check to see if this is being called from a cFE Application's + ** Check to see if this is being called from a cFE Application's ** main task. */ TaskId = OS_TaskGetId(); - + ReturnCode = CFE_ES_GetAppIDInternal(&AppId); if ( ReturnCode == CFE_SUCCESS ) { @@ -1247,7 +1207,7 @@ void CFE_ES_ExitChildTask(void) */ return; } - + } else { @@ -1255,13 +1215,13 @@ void CFE_ES_ExitChildTask(void) } } else - { + { CFE_ES_SysLogWrite_Unsync("CFE_ES_ExitChildTask Error Calling CFE_ES_GetAppID. Task ID = %d, RC = 0x%08X\n", (int)TaskId, (unsigned int)ReturnCode ); } /* end if GetAppId */ CFE_ES_UnlockSharedData(__func__,__LINE__); - + } /* End of CFE_ES_ExitChildTask() */ @@ -1355,9 +1315,9 @@ uint32 CFE_ES_CalculateCRC(const void *DataPtr, uint32 DataLength, uint32 InputC for ( i = 0 ; i < DataLength ; i++, BufPtr++) { - /* - * It is assumed that the supplied buffer is in a - * directly-accessible memory space that does not + /* + * It is assumed that the supplied buffer is in a + * directly-accessible memory space that does not * require special logic to access */ ByteValue = *BufPtr; @@ -1389,13 +1349,13 @@ int32 CFE_ES_RegisterCDS(CFE_ES_CDSHandle_t *CDSHandlePtr, int32 BlockSize, cons int32 Status; size_t NameLen = 0; uint32 ThisAppId = 0; - + char AppName[OS_MAX_API_NAME] = {"UNKNOWN"}; char CDSName[CFE_ES_CDS_MAX_FULL_NAME_LEN] = {""}; /* Check to make sure calling application is legit */ Status = CFE_ES_CDS_ValidateAppID(&ThisAppId); - + if ( Status != CFE_SUCCESS ) /* Application ID was invalid */ { CFE_ES_WriteToSysLog("CFE_CDS:Register-Bad AppId(%d)\n", (int)ThisAppId); @@ -1454,7 +1414,7 @@ int32 CFE_ES_RegisterCDS(CFE_ES_CDSHandle_t *CDSHandlePtr, int32 BlockSize, cons "%s Failed to Register CDS '%s', Status=0x%08X", AppName, Name, (unsigned int)Status); } - + return Status; } /* End of CFE_ES_RegisterCDS */ @@ -1467,9 +1427,9 @@ int32 CFE_ES_RegisterCDS(CFE_ES_CDSHandle_t *CDSHandlePtr, int32 BlockSize, cons int32 CFE_ES_CopyToCDS(CFE_ES_CDSHandle_t Handle, void *DataToCopy) { int32 Status; - + Status = CFE_ES_CDSBlockWrite(CFE_ES_Global.CDSVars.Registry[Handle].MemHandle, DataToCopy); - + return Status; } /* End of CFE_ES_CopyToCDS() */ @@ -1482,9 +1442,9 @@ int32 CFE_ES_CopyToCDS(CFE_ES_CDSHandle_t Handle, void *DataToCopy) int32 CFE_ES_RestoreFromCDS(void *RestoreToMemory, CFE_ES_CDSHandle_t Handle) { int32 Status; - + Status = CFE_ES_CDSBlockRead(RestoreToMemory, CFE_ES_Global.CDSVars.Registry[Handle].MemHandle); - + return Status; } /* End of CFE_ES_RestoreFromCDS() */ @@ -1535,7 +1495,7 @@ int32 CFE_ES_DeleteGenCounter(uint32 CounterId) int32 Status = CFE_ES_BAD_ARGUMENT; - if(CounterId < CFE_PLATFORM_ES_MAX_GEN_COUNTERS) + if(CounterId < CFE_PLATFORM_ES_MAX_GEN_COUNTERS) { CFE_ES_Global.CounterTable[CounterId].RecordUsed = false; CFE_ES_Global.CounterTable[CounterId].Counter = 0; @@ -1563,7 +1523,7 @@ int32 CFE_ES_IncrementGenCounter(uint32 CounterId) Status = CFE_SUCCESS; } return Status; - + } /* End of CFE_ES_IncrementGenCounter() */ /* @@ -1629,7 +1589,7 @@ int32 CFE_ES_GetGenCounterIDByName(uint32 *CounterIdPtr, const char *CounterName } } } /* end for */ - + return(Result); } /* End of CFE_ES_GetGenCounterIDByName() */ @@ -1700,7 +1660,7 @@ void CFE_ES_LockSharedData(const char *FunctionName, int32 LineNumber) uint32 AppId; Status = OS_MutSemTake(CFE_ES_Global.SharedDataMutex); - if (Status != OS_SUCCESS) + if (Status != OS_SUCCESS) { CFE_ES_GetAppIDInternal(&AppId); @@ -1737,7 +1697,7 @@ void CFE_ES_UnlockSharedData(const char *FunctionName, int32 LineNumber) uint32 AppId; Status = OS_MutSemGive(CFE_ES_Global.SharedDataMutex); - if (Status != OS_SUCCESS) + if (Status != OS_SUCCESS) { CFE_ES_GetAppIDInternal(&AppId); @@ -1767,7 +1727,7 @@ void CFE_ES_ProcessCoreException(uint32 HostTaskId, const char *ReasonStrin CFE_ES_TaskInfo_t EsTaskInfo; uint32 FoundExceptionTask = 0; uint32 ExceptionTaskID = 0; - + /* ** If a loadable cFE Application caused the reset and it's ** exception action is set to Restart the App rather than cause a @@ -1777,7 +1737,7 @@ void CFE_ES_ProcessCoreException(uint32 HostTaskId, const char *ReasonStrin /* ** We have the Host Task Id ( vxWorks, RTEMS, etc ). Search ** the OSAPI to see if a match can be found. - */ + */ for ( i = 0; i < OS_MAX_TASKS; i++ ) { if (CFE_ES_Global.TaskTable[i].RecordUsed == true) @@ -1801,14 +1761,14 @@ void CFE_ES_ProcessCoreException(uint32 HostTaskId, const char *ReasonStrin Status = CFE_ES_GetTaskInfo( &EsTaskInfo, ExceptionTaskID ); /* ** The App ID was found, now see if the ExceptionAction is set for a reset - */ + */ if ( Status == CFE_SUCCESS ) { if ( CFE_ES_Global.AppTable[EsTaskInfo.AppId].StartParams.ExceptionAction == CFE_ES_ExceptionAction_RESTART_APP ) { /* - ** Log the Application reset + ** Log the Application reset */ CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_ES_APP_RESTART, CFE_PSP_RST_SUBTYPE_EXCEPTION, (char *)ReasonString, @@ -1817,41 +1777,41 @@ void CFE_ES_ProcessCoreException(uint32 HostTaskId, const char *ReasonStrin /* ** Finally restart the App! This call is just a request ** to ES. - */ + */ CFE_ES_RestartApp(EsTaskInfo.AppId ); - + /* ** Return to avoid the Processor Restart Logic */ return; } /* end if ExceptionAction */ - + } /* end if */ - + } /* End if FoundExceptionTask */ - + /* ** If we made it here, which means that we need to do a processor reset */ /* - ** Before doing a Processor reset, check to see + ** Before doing a Processor reset, check to see ** if the maximum number has been exceeded */ - if ( CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount >= + if ( CFE_ES_ResetDataPtr->ResetVars.ProcessorResetCount >= CFE_ES_ResetDataPtr->ResetVars.MaxProcessorResetCount ) { /* ** Log the reset in the ER Log. The log will be wiped out, but it's good to have ** the entry just in case something fails. */ - CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, + CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, CFE_PSP_RST_SUBTYPE_EXCEPTION, (char *)ReasonString, ContextPointer, ContextSize ); /* - ** Call the BSP reset routine to do a Poweron Reset + ** Call the BSP reset routine to do a Poweron Reset */ CFE_PSP_Restart(CFE_PSP_RST_TYPE_POWERON); @@ -1867,15 +1827,15 @@ void CFE_ES_ProcessCoreException(uint32 HostTaskId, const char *ReasonStrin /* ** Log the reset in the ER Log */ - CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_PROCESSOR, + CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_PROCESSOR, CFE_PSP_RST_SUBTYPE_EXCEPTION, (char *)ReasonString, ContextPointer, ContextSize ); /* ** Need to do a processor reset - */ + */ CFE_PSP_Restart(CFE_PSP_RST_TYPE_PROCESSOR); } /* end if */ - + } /* End of CFE_ES_ProcessCoreException */ diff --git a/fsw/cfe-core/src/es/cfe_es_apps.c b/fsw/cfe-core/src/es/cfe_es_apps.c index 579d50eeb..0fe030b50 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.c +++ b/fsw/cfe-core/src/es/cfe_es_apps.c @@ -19,10 +19,10 @@ */ /* -** File: +** File: ** cfe_es_apps.c -** -** Purpose: +** +** Purpose: ** This file contains functions for starting cFE applications from a filesystem. ** ** References: @@ -33,13 +33,14 @@ ** */ -/* +/* ** Includes */ #include "private/cfe_private.h" #include "cfe_es.h" -#include "cfe_psp.h" +#include "cfe_psp.h" #include "cfe_es_global.h" +#include "cfe_es_task.h" #include "cfe_es_apps.h" #include "cfe_es_log.h" @@ -68,16 +69,16 @@ */ /* -** Name: +** Name: ** CFE_ES_StartApplications ** -** Purpose: +** Purpose: ** This routine loads/starts cFE applications. ** */ void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath ) { - char ES_AppLoadBuffer[ES_START_BUFF_SIZE]; /* A buffer of for a line in a file */ + char ES_AppLoadBuffer[ES_START_BUFF_SIZE]; /* A buffer of for a line in a file */ const char *TokenList[CFE_ES_STARTSCRIPT_MAX_TOKENS_PER_LINE]; uint32 NumTokens; uint32 BuffLen = 0; /* Length of the current buffer */ @@ -100,18 +101,18 @@ void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath ) if ( AppFile >= 0 ) { - CFE_ES_WriteToSysLog ("ES Startup: Opened ES App Startup file: %s\n", + CFE_ES_WriteToSysLog ("ES Startup: Opened ES App Startup file: %s\n", CFE_PLATFORM_ES_VOLATILE_STARTUP_FILE); FileOpened = true; } - else + else { CFE_ES_WriteToSysLog ("ES Startup: Cannot Open Volatile Startup file, Trying Nonvolatile.\n"); FileOpened = false; } } /* end if */ - + /* ** This if block covers two cases: A Power on reset, and a Processor reset when ** the startup file on the volatile file system could not be opened. @@ -128,25 +129,25 @@ void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath ) CFE_ES_WriteToSysLog ("ES Startup: Opened ES App Startup file: %s\n",StartFilePath); FileOpened = true; } - else + else { CFE_ES_WriteToSysLog ("ES Startup: Error, Can't Open ES App Startup file: %s EC = 0x%08X\n", StartFilePath, (unsigned int)AppFile ); FileOpened = false; } - + } - + /* ** If the file is opened in either the Nonvolatile or the Volatile disk, process it. */ if ( FileOpened == true) { memset(ES_AppLoadBuffer,0x0,ES_START_BUFF_SIZE); - BuffLen = 0; + BuffLen = 0; NumTokens = 0; TokenList[0] = ES_AppLoadBuffer; - + /* ** Parse the lines from the file. If it has an error ** or reaches EOF, then abort the loop. @@ -188,7 +189,7 @@ void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath ) else { LineTooLong = true; - } + } BuffLen++; if ( NumTokens < (CFE_ES_STARTSCRIPT_MAX_TOKENS_PER_LINE-1)) @@ -218,7 +219,7 @@ void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath ) else { if ( LineTooLong == true ) - { + { /* ** The was too big for the buffer */ @@ -250,7 +251,7 @@ void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath ) ** close the file */ OS_close(AppFile); - + } } @@ -308,30 +309,30 @@ int32 CFE_ES_ParseFileEntry(const char **TokenList, uint32 NumTokens) { CFE_ES_WriteToSysLog("ES Startup: Loading file: %s, APP: %s\n", FileName, AppName); - + /* ** Validate Some parameters ** Exception action should be 0 ( Restart App ) or ** 1 ( Processor reset ). If it's non-zero, assume it means ** reset CPU. */ - if ( ExceptionAction > CFE_ES_ExceptionAction_RESTART_APP ) + if ( ExceptionAction > CFE_ES_ExceptionAction_RESTART_APP ) ExceptionAction = CFE_ES_ExceptionAction_PROC_RESTART; /* - ** Now create the application + ** Now create the application */ - CreateStatus = CFE_ES_AppCreate(&ApplicationId, FileName, - EntryPoint, AppName, (uint32) Priority, + CreateStatus = CFE_ES_AppCreate(&ApplicationId, FileName, + EntryPoint, AppName, (uint32) Priority, (uint32) StackSize, (uint32) ExceptionAction ); } else if(strcmp(EntryType,"CFE_LIB")==0) - { + { CFE_ES_WriteToSysLog("ES Startup: Loading shared library: %s\n",FileName); - + /* ** Now load the library */ - CreateStatus = CFE_ES_LoadLibrary(&ApplicationId, FileName, + CreateStatus = CFE_ES_LoadLibrary(&ApplicationId, FileName, EntryPoint, AppName); } @@ -573,7 +574,7 @@ int32 CFE_ES_AppCreate(uint32 *ApplicationIdPtr, ** Fill out the Task State info */ CFE_ES_Global.AppTable[i].ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; - CFE_ES_Global.AppTable[i].ControlReq.AppTimer = 0; + CFE_ES_Global.AppTable[i].ControlReq.AppTimerMsec = 0; /* ** Create the primary task for the newly loaded task @@ -642,7 +643,7 @@ int32 CFE_ES_AppCreate(uint32 *ApplicationIdPtr, (unsigned int) ReturnCode); } } - + return(CFE_SUCCESS); } /* End If OS_TaskCreate */ @@ -928,67 +929,114 @@ int32 CFE_ES_LoadLibrary(uint32 *LibraryIdPtr, /* **--------------------------------------------------------------------------------------- -** Name: CFE_ES_ScanAppTable +** Name: CFE_ES_RunAppTableScan ** ** Purpose: This function scans the ES Application table and acts on the changes ** in application states. This is where the external cFE Applications are ** restarted, reloaded, or deleted. **--------------------------------------------------------------------------------------- */ -void CFE_ES_ScanAppTable(void) +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; + + if (State->PendingAppStateChanges == 0) + { + /* + * If the command count changes, then a scan becomes due immediately. + */ + if (State->LastScanCommandCount == CFE_ES_TaskData.CommandCounter && + State->BackgroundScanTimer > ElapsedTime) + { + /* no action at this time, background scan is not due yet */ + State->BackgroundScanTimer -= ElapsedTime; + return false; + } + } + + /* + * Every time a scan is initiated (for any reason) + * reset the background scan timer to the full value, + * and take a snapshot of the the command counter. + */ + State->BackgroundScanTimer = CFE_PLATFORM_ES_APP_SCAN_RATE; + State->LastScanCommandCount = CFE_ES_TaskData.CommandCounter; + State->PendingAppStateChanges = 0; + + /* + * Scan needs to be done with the table locked, + * as these state changes need to be done atomically + * with respect to other tasks that also access/update + * the state. + */ + CFE_ES_LockSharedData(__func__,__LINE__); + /* ** Scan the ES Application table. Skip entries that are: - ** - Not in use, or + ** - Not in use, or ** - cFE Core apps, or ** - Currently running */ for ( i = 0; i < CFE_PLATFORM_ES_MAX_APPLICATIONS; i++ ) { - /* - * NOTE: The table is *NOT* locked at the time of this call. - * This is a race condition bug. - */ - if (CFE_ES_Global.AppTable[i].Type == CFE_ES_AppType_EXTERNAL) - { - - /* - ** Process the External cFE App according to it's state. - */ - if ( CFE_ES_Global.AppTable[i].AppState == CFE_ES_AppState_WAITING ) - { - /* - ** If the timeout value is zero, take the action to delete/restart/reload the app - */ - if ( CFE_ES_Global.AppTable[i].ControlReq.AppTimer <= 0 ) - { - CFE_ES_ProcessControlRequest(i); - } - else - { - #ifdef ES_APP_DEBUG - OS_printf("%d..\n",(int)CFE_ES_Global.AppTable[i].ControlReq.AppTimer); - #endif - CFE_ES_Global.AppTable[i].ControlReq.AppTimer --; - - } - - } - else if ( CFE_ES_Global.AppTable[i].AppState == CFE_ES_AppState_STOPPED ) - { - /* - ** The App is stopped and ready to get deleted/restarted/reloaded - */ - CFE_ES_ProcessControlRequest(i); - - } /* end if */ - - } /* end if */ + AppPtr = &CFE_ES_Global.AppTable[i]; + + if (AppPtr->Type == CFE_ES_AppType_EXTERNAL) + { + if (AppPtr->AppState > CFE_ES_AppState_RUNNING) + { + /* + * Increment the "pending" counter which reflects + * the number of apps that are in some phase of clean up. + */ + ++State->PendingAppStateChanges; + + /* + * Decrement the wait timer, if active. + * When the timeout value becomes zero, take the action to delete/restart/reload the app + */ + if ( AppPtr->ControlReq.AppTimerMsec > ElapsedTime ) + { + AppPtr->ControlReq.AppTimerMsec -= ElapsedTime; + } + else + { + 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(i); + CFE_ES_LockSharedData(__func__,__LINE__); + } /* end if */ + } + else if (AppPtr->AppState == CFE_ES_AppState_RUNNING && + AppPtr->ControlReq.AppControlRequest > CFE_ES_RunStatus_APP_RUN) + { + /* this happens after a command arrives to restart/reload/delete an app */ + /* switch to WAITING state, and set the timer for transition */ + AppPtr->AppState = CFE_ES_AppState_WAITING; + AppPtr->ControlReq.AppTimerMsec = CFE_PLATFORM_ES_APP_KILL_TIMEOUT * CFE_PLATFORM_ES_APP_SCAN_RATE; + } + + + } /* end if */ } /* end for loop */ + CFE_ES_UnlockSharedData(__func__,__LINE__); + + /* + * This state machine is considered active if there are any + * pending app state changes. Returning "true" will cause this job + * to be called from the background task at a faster interval. + */ + return (State->PendingAppStateChanges != 0); + } /* End Function */ @@ -1001,22 +1049,22 @@ void CFE_ES_ScanAppTable(void) */ void CFE_ES_ProcessControlRequest(uint32 AppID) { - + int32 Status; CFE_ES_AppStartParams_t AppStartParams; uint32 NewAppId; - + /* ** First get a copy of the Apps Start Parameters */ memcpy(&AppStartParams, &(CFE_ES_Global.AppTable[AppID].StartParams), sizeof(CFE_ES_AppStartParams_t)); - + /* ** Now, find out what kind of Application control is being requested */ switch ( CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest ) { - + case CFE_ES_RunStatus_APP_EXIT: /* ** Kill the app, and dont restart it @@ -1025,16 +1073,16 @@ void CFE_ES_ProcessControlRequest(uint32 AppID) if ( Status == CFE_SUCCESS ) { - CFE_EVS_SendEvent(CFE_ES_EXIT_APP_INF_EID, CFE_EVS_EventType_INFORMATION, + 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, + 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; - + case CFE_ES_RunStatus_APP_ERROR: /* ** Kill the app, and dont restart it @@ -1042,17 +1090,17 @@ void CFE_ES_ProcessControlRequest(uint32 AppID) Status = CFE_ES_CleanUpApp(AppID); if ( Status == CFE_SUCCESS ) - { - CFE_EVS_SendEvent(CFE_ES_ERREXIT_APP_INF_EID, CFE_EVS_EventType_INFORMATION, + { + 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, + 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; - + case CFE_ES_RunStatus_SYS_DELETE: /* ** Kill the app, and dont restart it @@ -1060,17 +1108,17 @@ void CFE_ES_ProcessControlRequest(uint32 AppID) Status = CFE_ES_CleanUpApp(AppID); if ( Status == CFE_SUCCESS ) - { - CFE_EVS_SendEvent(CFE_ES_STOP_INF_EID, CFE_EVS_EventType_INFORMATION, + { + 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, + 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_RESTART: /* ** Kill the app @@ -1082,31 +1130,31 @@ void CFE_ES_ProcessControlRequest(uint32 AppID) /* ** And start it back up again */ - Status = CFE_ES_AppCreate(&NewAppId, (char *)AppStartParams.FileName, - (char *)AppStartParams.EntryPoint, - (char *)AppStartParams.Name, - AppStartParams.Priority, - AppStartParams.StackSize, + 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, + 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, + 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, + 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: /* ** Kill the app @@ -1118,36 +1166,36 @@ void CFE_ES_ProcessControlRequest(uint32 AppID) /* ** And start it back up again */ - Status = CFE_ES_AppCreate(&NewAppId, (char *)AppStartParams.FileName, - (char *)AppStartParams.EntryPoint, - (char *)AppStartParams.Name, - AppStartParams.Priority, - AppStartParams.StackSize, + 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, + 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, + 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, + 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); } - + break; - + case CFE_ES_RunStatus_SYS_EXCEPTION: - - CFE_EVS_SendEvent(CFE_ES_PCR_ERR1_EID, CFE_EVS_EventType_ERROR, + + CFE_EVS_SendEvent(CFE_ES_PCR_ERR1_EID, CFE_EVS_EventType_ERROR, "ES_ProcControlReq: Invalid State (EXCEPTION) Application %s.", - AppStartParams.Name); + AppStartParams.Name); /* * Bug #58: This message/event keeps repeating itself indefinitely. * @@ -1156,10 +1204,10 @@ void CFE_ES_ProcessControlRequest(uint32 AppID) */ CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_DELETE; break; - + default: - - CFE_EVS_SendEvent(CFE_ES_PCR_ERR2_EID, CFE_EVS_EventType_ERROR, + + CFE_EVS_SendEvent(CFE_ES_PCR_ERR2_EID, CFE_EVS_EventType_ERROR, "ES_ProcControlReq: Unknown State ( %d ) Application %s.", (int)CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest, AppStartParams.Name); @@ -1171,9 +1219,9 @@ void CFE_ES_ProcessControlRequest(uint32 AppID) */ CFE_ES_Global.AppTable[AppID].ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_DELETE; break; - - } - + + } + } /* End Function */ /* @@ -1194,23 +1242,23 @@ int32 CFE_ES_CleanUpApp(uint32 AppId) OS_printf("------------- Starting App Cleanup: AppID = %d -----------\n",AppId); CFE_ES_ListResourcesDebug(); #endif - + /* ** Call the Table Clean up function */ #ifndef EXCLUDE_CFE_TBL CFE_TBL_CleanUpApp(AppId); -#endif +#endif /* ** 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 */ @@ -1220,17 +1268,17 @@ int32 CFE_ES_CleanUpApp(uint32 AppId) 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 the ES Resources */ CFE_ES_LockSharedData(__func__,__LINE__); - + /* ** Get Main Task ID */ - MainTaskId = CFE_ES_Global.AppTable[AppId].TaskInfo.MainTaskId; + MainTaskId = CFE_ES_Global.AppTable[AppId].TaskInfo.MainTaskId; /* ** Delete all of the OS resources, close files, and delete the main task @@ -1241,7 +1289,7 @@ int32 CFE_ES_CleanUpApp(uint32 AppId) CFE_ES_SysLogWrite_Unsync("CFE_ES_CleanUpApp: CleanUpTaskResources for Task ID:%d returned Error: 0x%08X\n", (int)MainTaskId, (unsigned int)Status); ReturnCode = CFE_ES_APP_CLEANUP_ERR; - + } /* @@ -1253,7 +1301,7 @@ int32 CFE_ES_CleanUpApp(uint32 AppId) if ((CFE_ES_Global.TaskTable[i].RecordUsed == true) && (CFE_ES_Global.TaskTable[i].AppId == AppId) && (CFE_ES_Global.TaskTable[i].TaskId != MainTaskId)) - { + { Status = CFE_ES_CleanupTaskResources(CFE_ES_Global.TaskTable[i].TaskId); if ( Status != CFE_SUCCESS ) { @@ -1281,19 +1329,19 @@ int32 CFE_ES_CleanUpApp(uint32 AppId) } CFE_ES_Global.RegisteredExternalApps--; } - + CFE_ES_Global.AppTable[AppId].AppState = CFE_ES_AppState_UNDEFINED; - #ifdef ES_APP_DEBUG - OS_TaskDelay(1000); + #ifdef ES_APP_DEBUG + OS_TaskDelay(1000); CFE_ES_ListResourcesDebug(); printf("--------- Finished CFE_ES_CleanUpApp-------------\n"); - #endif + #endif CFE_ES_UnlockSharedData(__func__,__LINE__); - + return(ReturnCode); - + } /* end function */ @@ -1540,9 +1588,9 @@ void CFE_ES_GetAppInfoInternal(uint32 AppId, CFE_ES_AppInfo_t *AppInfoPtr ) int32 ReturnCode; OS_module_prop_t ModuleInfo; uint32 TaskIndex; - uint32 i; - - + uint32 i; + + CFE_ES_LockSharedData(__func__,__LINE__); AppInfoPtr->AppId = AppId; @@ -1556,29 +1604,29 @@ void CFE_ES_GetAppInfoInternal(uint32 AppId, CFE_ES_AppInfo_t *AppInfoPtr ) CFE_ES_Global.AppTable[AppId].StartParams.EntryPoint, sizeof(AppInfoPtr->EntryPoint) - 1); AppInfoPtr->EntryPoint[sizeof(AppInfoPtr->EntryPoint) - 1] = '\0'; - + strncpy((char *)AppInfoPtr->FileName, (char *)CFE_ES_Global.AppTable[AppId].StartParams.FileName, sizeof(AppInfoPtr->FileName) - 1); AppInfoPtr->FileName[sizeof(AppInfoPtr->FileName) - 1] = '\0'; - + AppInfoPtr->ModuleId = CFE_ES_Global.AppTable[AppId].StartParams.ModuleId; AppInfoPtr->StackSize = CFE_ES_Global.AppTable[AppId].StartParams.StackSize; CFE_SB_SET_MEMADDR(AppInfoPtr->StartAddress, CFE_ES_Global.AppTable[AppId].StartParams.StartAddress); AppInfoPtr->ExceptionAction = CFE_ES_Global.AppTable[AppId].StartParams.ExceptionAction; AppInfoPtr->Priority = CFE_ES_Global.AppTable[AppId].StartParams.Priority; - - AppInfoPtr->MainTaskId = CFE_ES_Global.AppTable[AppId].TaskInfo.MainTaskId; + + AppInfoPtr->MainTaskId = CFE_ES_Global.AppTable[AppId].TaskInfo.MainTaskId; strncpy((char *)AppInfoPtr->MainTaskName, (char *)CFE_ES_Global.AppTable[AppId].TaskInfo.MainTaskName, sizeof(AppInfoPtr->MainTaskName) - 1); AppInfoPtr->MainTaskName[sizeof(AppInfoPtr->MainTaskName) - 1] = '\0'; - + /* ** Calculate the number of child tasks */ - AppInfoPtr->NumOfChildTasks = 0; + AppInfoPtr->NumOfChildTasks = 0; for (i=0; iMainTaskId ) { AppInfoPtr->NumOfChildTasks++; @@ -1593,7 +1641,7 @@ void CFE_ES_GetAppInfoInternal(uint32 AppId, CFE_ES_AppInfo_t *AppInfoPtr ) AppInfoPtr->ExecutionCounter = CFE_ES_Global.TaskTable[TaskIndex].ExecutionCounter; } - /* + /* ** Get the address information from the OSAL */ ReturnCode = OS_ModuleInfo ( AppInfoPtr->ModuleId, &ModuleInfo ); @@ -1608,7 +1656,7 @@ void CFE_ES_GetAppInfoInternal(uint32 AppId, CFE_ES_AppInfo_t *AppInfoPtr ) 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; @@ -1619,7 +1667,7 @@ void CFE_ES_GetAppInfoInternal(uint32 AppId, CFE_ES_AppInfo_t *AppInfoPtr ) AppInfoPtr->BSSAddress = 0; AppInfoPtr->BSSSize = 0; } - + CFE_ES_UnlockSharedData(__func__,__LINE__); diff --git a/fsw/cfe-core/src/es/cfe_es_apps.h b/fsw/cfe-core/src/es/cfe_es_apps.h index fe1715c84..b9a2254c4 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.h +++ b/fsw/cfe-core/src/es/cfe_es_apps.h @@ -19,7 +19,7 @@ */ /* -** File: +** File: ** cfe_es_apps.h ** ** Purpose: @@ -58,8 +58,8 @@ */ typedef struct { - uint32 AppControlRequest; /* What the App should be doing next */ - int32 AppTimer; /* Countdown timer for killing an app */ + uint32 AppControlRequest; /* What the App should be doing next */ + int32 AppTimerMsec; /* Countdown timer for killing an app, in milliseconds */ } CFE_ES_ControlReq_t; @@ -80,13 +80,13 @@ typedef struct uint16 ExceptionAction; uint16 Priority; - + } CFE_ES_AppStartParams_t; /* ** CFE_ES_MainTaskInfo_t is a structure of information about the main ** task and child tasks in a cFE application. This structure is just used in the -** cFE_ES_AppRecord_t structure. +** cFE_ES_AppRecord_t structure. */ typedef struct { @@ -106,7 +106,7 @@ typedef struct 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_MainTaskInfo_t TaskInfo; /* Information about the Tasks */ - + } CFE_ES_AppRecord_t; @@ -121,8 +121,8 @@ typedef struct uint32 TaskId; /* Task ID */ uint32 ExecutionCounter; /* The execution counter for the Child task */ char TaskName[OS_MAX_API_NAME]; /* Task Name */ - - + + } CFE_ES_TaskRecord_t; /* @@ -135,6 +135,19 @@ typedef struct char LibName[OS_MAX_API_NAME]; /* Library Name */ } CFE_ES_LibRecord_t; +/* +** CFE_ES_AppTableScanState_t is an internal structure used to keep state of +** the background app table scan/cleanup process +*/ +typedef struct +{ + uint32 PendingAppStateChanges; + uint32 BackgroundScanTimer; + uint8 LastScanCommandCount; +} CFE_ES_AppTableScanState_t; + + + /*****************************************************************************/ /* ** Function prototypes @@ -150,13 +163,6 @@ void CFE_ES_StartApplications(uint32 ResetType, const char *StartFilePath ); */ int32 CFE_ES_ParseFileEntry(const char **TokenList, uint32 NumTokens); -/* - * Internal function to set the state of an app - * All state changes should go through this function rather than directly writing to the control block - */ -void CFE_ES_SetAppState(uint32 AppID, uint32 TargetState); - - /* ** Internal function to create/start a new cFE app ** based on the parameters passed in @@ -190,7 +196,7 @@ int32 CFE_ES_AppDumpAllInfo(void); /* ** Scan the Application Table for actions to take */ -void CFE_ES_ScanAppTable(void); +bool CFE_ES_RunAppTableScan(uint32 ElapsedTime, void *Arg); /* ** Perform the requested control action for an application @@ -208,7 +214,7 @@ int32 CFE_ES_CleanUpApp(uint32 AppId); int32 CFE_ES_CleanupTaskResources(uint32 TaskId); /* -** Debug function to print out resource utilization +** Debug function to print out resource utilization */ int32 CFE_ES_ListResourcesDebug(void); diff --git a/fsw/cfe-core/src/es/cfe_es_backgroundtask.c b/fsw/cfe-core/src/es/cfe_es_backgroundtask.c index 174c2952c..5582fa8da 100644 --- a/fsw/cfe-core/src/es/cfe_es_backgroundtask.c +++ b/fsw/cfe-core/src/es/cfe_es_backgroundtask.c @@ -71,6 +71,12 @@ typedef struct */ const CFE_ES_BackgroundJobEntry_t CFE_ES_BACKGROUND_JOB_TABLE[] = { + { /* ES app table background scan */ + .RunFunc = CFE_ES_RunAppTableScan, + .JobArg = &CFE_ES_TaskData.BackgroundAppScanState, + .ActivePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE / 4, + .IdlePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE + }, { /* Performance Log Data Dump to file */ .RunFunc = CFE_ES_RunPerfLogDump, .JobArg = &CFE_ES_TaskData.BackgroundPerfDumpState, diff --git a/fsw/cfe-core/src/es/cfe_es_task.c b/fsw/cfe-core/src/es/cfe_es_task.c index bb5dc5fdf..ce216dad1 100644 --- a/fsw/cfe-core/src/es/cfe_es_task.c +++ b/fsw/cfe-core/src/es/cfe_es_task.c @@ -80,7 +80,6 @@ CFE_ES_TaskData_t CFE_ES_TaskData; void CFE_ES_TaskMain(void) { int32 Status; - uint32 TimeOut = CFE_PLATFORM_ES_APP_SCAN_RATE; uint32 AppRunStatus = CFE_ES_RunStatus_APP_RUN; @@ -139,21 +138,14 @@ void CFE_ES_TaskMain(void) */ Status = CFE_SB_RcvMsg(&CFE_ES_TaskData.MsgPtr, CFE_ES_TaskData.CmdPipe, - TimeOut); + CFE_SB_PEND_FOREVER); /* ** Performance Time Stamp Entry */ CFE_ES_PerfLogEntry(CFE_MISSION_ES_MAIN_PERF_ID); - /* - ** Scan the App table for Application Deletion requests - */ - if ( Status == CFE_SB_TIME_OUT ) - { - CFE_ES_ScanAppTable(); - } - else if (Status == CFE_SUCCESS) + if (Status == CFE_SUCCESS) { /* ** Process Software Bus message. @@ -161,9 +153,10 @@ void CFE_ES_TaskMain(void) CFE_ES_TaskPipe(CFE_ES_TaskData.MsgPtr); /* - ** Scan the App Table for changes after processing a command - */ - CFE_ES_ScanAppTable(); + * Wake up the background task, which includes the + * scanning of the ES app table for entries that may need cleanup + */ + CFE_ES_BackgroundWakeup(); } else { diff --git a/fsw/cfe-core/src/es/cfe_es_task.h b/fsw/cfe-core/src/es/cfe_es_task.h index 78b933261..d90a11a42 100644 --- a/fsw/cfe-core/src/es/cfe_es_task.h +++ b/fsw/cfe-core/src/es/cfe_es_task.h @@ -113,6 +113,11 @@ typedef struct */ CFE_ES_PerfDumpGlobal_t BackgroundPerfDumpState; + /* + * Persistent state data associated with background app table scans + */ + CFE_ES_AppTableScanState_t BackgroundAppScanState; + } CFE_ES_TaskData_t; /* 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 b84f3a143..2a5ce3f28 100644 --- a/fsw/cfe-core/src/inc/cfe_es_extern_typedefs.h +++ b/fsw/cfe-core/src/inc/cfe_es_extern_typedefs.h @@ -116,6 +116,10 @@ typedef uint8 CFE_ES_AppType_Enum_t; */ enum CFE_ES_RunStatus { + /** + * @brief Reserved value, should not be used + */ + CFE_ES_RunStatus_UNDEFINED = 0, /** * @brief Indicates that the Application should continue to run @@ -160,7 +164,13 @@ enum CFE_ES_RunStatus /** * @brief Indicates that the Core Application had a runtime failure */ - CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR = 9 + CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR = 9, + + /** + * @brief Reserved value, marker for the maximum state + */ + CFE_ES_RunStatus_MAX + }; /** @@ -211,7 +221,12 @@ enum CFE_ES_SystemState /** * @brief reserved for future use, all apps would be STOPPED */ - CFE_ES_SystemState_SHUTDOWN = 6 + CFE_ES_SystemState_SHUTDOWN = 6, + + /** + * @brief Reserved value, marker for the maximum state + */ + CFE_ES_SystemState_MAX }; /** diff --git a/fsw/cfe-core/unit-test/es_UT.c b/fsw/cfe-core/unit-test/es_UT.c index 065f3a061..b8a765330 100644 --- a/fsw/cfe-core/unit-test/es_UT.c +++ b/fsw/cfe-core/unit-test/es_UT.c @@ -1324,13 +1324,14 @@ void TestApps(void) CFE_ES_Global.AppTable[Id].Type = CFE_ES_AppType_EXTERNAL; CFE_ES_Global.AppTable[Id].AppState = CFE_ES_AppState_WAITING; CFE_ES_Global.AppTable[Id].ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer = 0; - CFE_ES_ScanAppTable(); + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec = 0; + memset(&CFE_ES_TaskData.BackgroundAppScanState, 0, sizeof(CFE_ES_TaskData.BackgroundAppScanState)); + CFE_ES_RunAppTableScan(0, &CFE_ES_TaskData.BackgroundAppScanState); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_PCR_ERR2_EID) && - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer == 0 && + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec == 0 && CFE_ES_Global.AppTable[Id].ControlReq.AppControlRequest == CFE_ES_RunStatus_SYS_DELETE, - "CFE_ES_ScanAppTable", + "CFE_ES_RunAppTableScan", "Waiting; process control request"); /* Test scanning and acting on the application table where the timer @@ -1342,12 +1343,12 @@ void TestApps(void) CFE_ES_Global.AppTable[Id].Type = CFE_ES_AppType_EXTERNAL; CFE_ES_Global.AppTable[Id].AppState = CFE_ES_AppState_WAITING; CFE_ES_Global.AppTable[Id].ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_EXIT; - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer = 5; - CFE_ES_ScanAppTable(); + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec = 5000; + CFE_ES_RunAppTableScan(1000, &CFE_ES_TaskData.BackgroundAppScanState); UT_Report(__FILE__, __LINE__, - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer == 4 && + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec == 4000 && CFE_ES_Global.AppTable[Id].ControlReq.AppControlRequest == CFE_ES_RunStatus_APP_EXIT, - "CFE_ES_ScanAppTable", + "CFE_ES_RunAppTableScan", "Decrement timer"); /* Test scanning and acting on the application table where the application @@ -1359,13 +1360,13 @@ void TestApps(void) CFE_ES_Global.AppTable[Id].Type = CFE_ES_AppType_EXTERNAL; CFE_ES_Global.AppTable[Id].AppState = CFE_ES_AppState_STOPPED; CFE_ES_Global.AppTable[Id].ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer = 0; - CFE_ES_ScanAppTable(); + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec = 0; + CFE_ES_RunAppTableScan(0, &CFE_ES_TaskData.BackgroundAppScanState); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_PCR_ERR2_EID) && CFE_ES_Global.AppTable[Id].ControlReq.AppControlRequest == CFE_ES_RunStatus_SYS_DELETE && - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer == 0, - "CFE_ES_ScanAppTable", + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec == 0, + "CFE_ES_RunAppTableScan", "Stopped; process control request"); /* Test scanning and acting on the application table where the application @@ -1376,13 +1377,13 @@ void TestApps(void) Id = ES_UT_OSALID_TO_ARRAYIDX(TestObjId); CFE_ES_Global.AppTable[Id].Type = CFE_ES_AppType_EXTERNAL; CFE_ES_Global.AppTable[Id].AppState = CFE_ES_AppState_EARLY_INIT; - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer = 5; + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec = 5000; - CFE_ES_ScanAppTable(); + CFE_ES_RunAppTableScan(0, &CFE_ES_TaskData.BackgroundAppScanState); UT_Report(__FILE__, __LINE__, UT_GetNumEventsSent() == 0 && - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer == 5, - "CFE_ES_ScanAppTable", + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec == 5000, + "CFE_ES_RunAppTableScan", "Initializing; process control request"); /* Test a control action request on an application with an @@ -1968,12 +1969,12 @@ void TestApps(void) Id = ES_UT_OSALID_TO_ARRAYIDX(TestObjId); CFE_ES_Global.AppTable[Id].Type = CFE_ES_AppType_CORE; CFE_ES_Global.AppTable[Id].AppState = CFE_ES_AppState_WAITING; - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer = 0; - CFE_ES_ScanAppTable(); + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec = 0; + CFE_ES_RunAppTableScan(0, &CFE_ES_TaskData.BackgroundAppScanState); UT_Report(__FILE__, __LINE__, UT_GetNumEventsSent() == 0 && - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer == 0, - "CFE_ES_ScanAppTable", + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec == 0, + "CFE_ES_RunAppTableScan", "Waiting; process control request"); CFE_ES_Global.TaskTable[Id].RecordUsed = false; @@ -1985,12 +1986,12 @@ void TestApps(void) Id = ES_UT_OSALID_TO_ARRAYIDX(TestObjId); CFE_ES_Global.AppTable[Id].Type = CFE_ES_AppType_EXTERNAL; CFE_ES_Global.AppTable[Id].AppState = CFE_ES_AppState_RUNNING; - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer = 0; - CFE_ES_ScanAppTable(); + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec = 0; + CFE_ES_RunAppTableScan(0, &CFE_ES_TaskData.BackgroundAppScanState); UT_Report(__FILE__, __LINE__, UT_GetNumEventsSent() == 0 && - CFE_ES_Global.AppTable[Id].ControlReq.AppTimer == 0, - "CFE_ES_ScanAppTable", + CFE_ES_Global.AppTable[Id].ControlReq.AppTimerMsec == 0, + "CFE_ES_RunAppTableScan", "Running; process control request"); CFE_ES_Global.TaskTable[Id].RecordUsed = false; @@ -4467,12 +4468,14 @@ void TestAPI(void) /* Test exiting an app with an exit error */ /* Note - this exit code of 1000 is invalid, which causes - * an extra message to be logged in syslog about this */ + * an extra message to be logged in syslog about this. This + * should also be stored in the AppControlRequest as APP_ERROR. */ ES_ResetUnitTest(); OS_TaskCreate(&TestObjId, "UT", NULL, NULL, 0, 0, 0); Id = ES_UT_OSALID_TO_ARRAYIDX(TestObjId); CFE_ES_Global.TaskTable[Id].AppId = Id; CFE_ES_Global.TaskTable[Id].RecordUsed = true; + CFE_ES_Global.AppTable[Id].ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; CFE_ES_Global.AppTable[Id].Type = CFE_ES_AppType_EXTERNAL; CFE_ES_Global.AppTable[Id].AppState = CFE_ES_AppState_STOPPED; CFE_ES_Global.AppTable[Id].Type = CFE_ES_AppType_CORE; @@ -4482,6 +4485,10 @@ void TestAPI(void) UT_GetStubCount(UT_KEY(OS_printf)) == 2, "CFE_ES_ExitApp", "Application exit error"); + UtAssert_True(CFE_ES_Global.AppTable[Id].ControlReq.AppControlRequest == CFE_ES_RunStatus_APP_ERROR, + "CFE_ES_ExitApp - AppControlRequest (%u) == CFE_ES_RunStatus_APP_ERROR (%u)", + (unsigned int)CFE_ES_Global.AppTable[Id].ControlReq.AppControlRequest, + (unsigned int)CFE_ES_RunStatus_APP_ERROR); #if 0 /* Can't cover this path since it contains a while(1) (i.e., @@ -4548,9 +4555,9 @@ void TestAPI(void) CFE_ES_Global.AppTable[Id].AppState = CFE_ES_AppState_RUNNING; CFE_ES_Global.TaskTable[Id].RecordUsed = false; CFE_ES_Global.TaskTable[Id].AppId = Id; - RunStatus = CFE_ES_RunStatus_APP_EXIT; + RunStatus = CFE_ES_RunStatus_APP_RUN; CFE_ES_Global.AppTable[Id].ControlReq.AppControlRequest = - CFE_ES_RunStatus_APP_EXIT; + CFE_ES_RunStatus_APP_RUN; UT_Report(__FILE__, __LINE__, CFE_ES_RunLoop(&RunStatus) == false, "CFE_ES_RunLoop", @@ -4571,6 +4578,20 @@ void TestAPI(void) "CFE_ES_RunLoop", "Invalid run status"); + /* Test run loop with a NULL run status */ + ES_ResetUnitTest(); + OS_TaskCreate(&TestObjId, "UT", NULL, NULL, 0, 0, 0); + Id = ES_UT_OSALID_TO_ARRAYIDX(TestObjId); + CFE_ES_Global.AppTable[Id].AppState = CFE_ES_AppState_RUNNING; + CFE_ES_Global.TaskTable[Id].RecordUsed = true; + CFE_ES_Global.TaskTable[Id].AppId = Id; + CFE_ES_Global.AppTable[Id].ControlReq.AppControlRequest = + CFE_ES_RunStatus_APP_RUN; + UT_Report(__FILE__, __LINE__, + CFE_ES_RunLoop(NULL), + "CFE_ES_RunLoop", + "Nominal, NULL output pointer"); + /* Test run loop with startup sync code */ ES_ResetUnitTest(); OS_TaskCreate(&TestObjId, "UT", NULL, NULL, 0, 0, 0);