From 33364e8152f95b20b199de3eab19a56b9f97c67f Mon Sep 17 00:00:00 2001 From: Jacob Hageman Date: Wed, 21 Oct 2020 09:36:50 -0400 Subject: [PATCH 1/8] Fix #928, Extracted msg map and route table from SB - Removed all index/pointer accesses of message map and routing table - All references now via IDs and APIs - Note SB still owns destination logic (unchanged linear linked list) - Limited whitespace fixes for readability - Resolved observed instances of variables not declared at the start of functions - Cleaned comments - Resolved potential double locks in CFE_SB_SendPrevSubs - Route and message write to file no longer guaranteed in msgid order to maintain performance for large msgid space implementations - Removed unused CFE_SB_FindGlobalMsgIdCnt - Clarified CFE_PLATFORM_SB_MAX_MSG_IDS config param description - Eliminated potential race in CFE_SB_PipeDeleteFull - Individual destination removal debug events no longer reported during a CFE_SB_PipeDeleteFull --- cmake/sample_defs/cpu1_platform_cfg.h | 6 +- fsw/cfe-core/src/inc/cfe_sb_events.h | 15 + fsw/cfe-core/src/inc/cfe_sb_extern_typedefs.h | 2 +- fsw/cfe-core/src/inc/cfe_sb_msg.h | 4 +- .../inc/private/cfe_sb_destination_typedef.h | 52 ++ fsw/cfe-core/src/inc/private/cfe_sbr.h | 205 ++++++++ fsw/cfe-core/src/sb/cfe_sb_api.c | 315 +++++------- fsw/cfe-core/src/sb/cfe_sb_init.c | 69 +-- fsw/cfe-core/src/sb/cfe_sb_msg_id_util.c | 23 - fsw/cfe-core/src/sb/cfe_sb_priv.c | 378 +++----------- fsw/cfe-core/src/sb/cfe_sb_priv.h | 300 +++-------- fsw/cfe-core/src/sb/cfe_sb_task.c | 480 ++++++++---------- 12 files changed, 767 insertions(+), 1082 deletions(-) create mode 100644 fsw/cfe-core/src/inc/private/cfe_sb_destination_typedef.h create mode 100644 fsw/cfe-core/src/inc/private/cfe_sbr.h 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/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/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 */ From 0aac36a10091ccc668f52a5ac9f22140aebc8c2f Mon Sep 17 00:00:00 2001 From: Jacob Hageman Date: Wed, 21 Oct 2020 10:00:57 -0400 Subject: [PATCH 2/8] Fix #928, Added software bus routing module - Implementation for direct map and unsorted routing table - Includes full coverage tests - Removed msg key and route stack concepts from direct map --- cmake/mission_defaults.cmake | 1 + modules/sbr/CMakeLists.txt | 43 ++++ modules/sbr/private_inc/cfe_sbr_priv.h | 66 ++++++ modules/sbr/src/cfe_sbr_map_direct.c | 93 ++++++++ modules/sbr/src/cfe_sbr_route_unsorted.c | 219 ++++++++++++++++++ modules/sbr/unit-test-coverage/CMakeLists.txt | 59 +++++ .../test_cfe_sbr_map_direct.c | 112 +++++++++ .../test_cfe_sbr_route_unsorted.c | 198 ++++++++++++++++ 8 files changed, 791 insertions(+) create mode 100644 modules/sbr/CMakeLists.txt create mode 100644 modules/sbr/private_inc/cfe_sbr_priv.h create mode 100644 modules/sbr/src/cfe_sbr_map_direct.c create mode 100644 modules/sbr/src/cfe_sbr_route_unsorted.c create mode 100644 modules/sbr/unit-test-coverage/CMakeLists.txt create mode 100644 modules/sbr/unit-test-coverage/test_cfe_sbr_map_direct.c create mode 100644 modules/sbr/unit-test-coverage/test_cfe_sbr_route_unsorted.c 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/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_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_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); +} From 5a795ad5d4097a8328927eac242b7b7b6ca548ff Mon Sep 17 00:00:00 2001 From: Jacob Hageman Date: Wed, 21 Oct 2020 10:02:00 -0400 Subject: [PATCH 3/8] Fix #929, Add message map has implementation - Message map size based on used routes - Oversized (4x) to limit collisions while retaining resonable size related to routing table (still smaller) - ~10% single collisions seen for full routing table with realistic message ID use - Oversizing means map can never fill, simplifies logic - Observed approximately 10%-20% performance hit, trade against memory use (can now use full 32 bit MsgId space) - Hash intended for 32 bit, if CFE_SB_MsgId_Atom_t size changes may require modification to hash - Also added full coverage unit tests --- modules/sbr/src/cfe_sbr_map_hash.c | 163 ++++++++++++++++++ .../test_cfe_sbr_map_hash.c | 118 +++++++++++++ 2 files changed, 281 insertions(+) create mode 100644 modules/sbr/src/cfe_sbr_map_hash.c create mode 100644 modules/sbr/unit-test-coverage/test_cfe_sbr_map_hash.c 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/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); +} From 9b56d52a38942bea94f1701053017a789a1db882 Mon Sep 17 00:00:00 2001 From: Jacob Hageman Date: Wed, 21 Oct 2020 10:02:31 -0400 Subject: [PATCH 4/8] Fix #928, Update SB unit test for SBR module with direct link - Linking SBR with SB unit test, not stubbed - Confirms matching functionality (with updates for intended changes) --- fsw/cfe-core/unit-test/CMakeLists.txt | 1 + fsw/cfe-core/unit-test/sb_UT.c | 165 +++++++++----------------- 2 files changed, 58 insertions(+), 108 deletions(-) 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/sb_UT.c b/fsw/cfe-core/unit-test/sb_UT.c index 820957f0f..600fa5b6a 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); From 6932f1fe9180f4fd3f6756e4074b2c4b27a703cf Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Fri, 16 Oct 2020 12:05:36 -0400 Subject: [PATCH 5/8] Fix #950, race condition in control request Because the process of handling a control request involves calling other subsystems, the ES lock needs to be released. However, this also means that the app record can change state for other reasons, such as the app self-exiting at the same time. To avoid this possibility, process in two phases: First assemble a list of tasks that have timed out and need to be cleaned up, while ES is locked. Next actually perform the cleanup, while ES is unlocked. In areas during cleanup that need to update the ES global, the lock is locally re-acquired and released. --- fsw/cfe-core/src/es/cfe_es_apps.c | 766 ++++++++++++++++----------- fsw/cfe-core/src/es/cfe_es_apps.h | 4 +- fsw/cfe-core/src/inc/cfe_es_events.h | 14 +- fsw/cfe-core/unit-test/es_UT.c | 77 ++- 4 files changed, 516 insertions(+), 345 deletions(-) diff --git a/fsw/cfe-core/src/es/cfe_es_apps.c b/fsw/cfe-core/src/es/cfe_es_apps.c index ebd7916de..8cb13dd16 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.c +++ b/fsw/cfe-core/src/es/cfe_es_apps.c @@ -822,9 +822,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 +847,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 +891,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 +914,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 +947,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.FileName, + OrigStartParams.EntryPoint, + OrigStartParams.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); - - 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); - } - - 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: + case CFE_ES_RunStatus_SYS_EXCEPTION: + ReqName = "ES_ProcControlReq: Invalid State"; + EventID = CFE_ES_PCR_ERR1_EID; + snprintf(MessageDetail, sizeof(MessageDetail), "EXCEPTION"); + break; - 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); + default: + ReqName = "ES_ProcControlReq: Unknown State"; + EventID = CFE_ES_PCR_ERR2_EID; + snprintf(MessageDetail, sizeof(MessageDetail), "( %lu )", + (unsigned long)PendingControlReq); + break; + } - /* - * 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.Name, MessageDetail); + } } /* End Function */ @@ -1116,154 +1179,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->StartParams.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__); + 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; + } - 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; - } - } + CFE_ES_UnlockSharedData(__func__, __LINE__); - ++MemPoolRecPtr; - } /* end for */ + if (ReturnCode != CFE_SUCCESS) + { + return ReturnCode; + } + /* + * 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. + */ - CFE_ES_UnlockSharedData(__func__,__LINE__); + /* + ** Call the Table Clean up function + */ + CFE_TBL_CleanUpApp(AppId); - return(ReturnCode); + /* + ** 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 +1544,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 +1582,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,15 +1604,6 @@ 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); } diff --git a/fsw/cfe-core/src/es/cfe_es_apps.h b/fsw/cfe-core/src/es/cfe_es_apps.h index fa29774b4..4cf2c11bc 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.h +++ b/fsw/cfe-core/src/es/cfe_es_apps.h @@ -199,12 +199,12 @@ 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 diff --git a/fsw/cfe-core/src/inc/cfe_es_events.h b/fsw/cfe-core/src/inc/cfe_es_events.h index c7bad610e..8b0f4b432 100644 --- a/fsw/cfe-core/src/inc/cfe_es_events.h +++ b/fsw/cfe-core/src/inc/cfe_es_events.h @@ -167,8 +167,8 @@ **/ #define CFE_ES_RESTART_APP_DBG_EID 9 -/** \brief '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/unit-test/es_UT.c b/fsw/cfe-core/unit-test/es_UT.c index fe99f690e..3a134cf50 100644 --- a/fsw/cfe-core/unit-test/es_UT.c +++ b/fsw/cfe-core/unit-test/es_UT.c @@ -1437,8 +1437,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 +1465,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 +1488,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", @@ -1512,7 +1511,8 @@ void TestApps(void) OS_ModuleLoad(&UtAppRecPtr->StartParams.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", @@ -1526,7 +1526,8 @@ void TestApps(void) 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); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_EXIT_APP_ERR_EID), "CFE_ES_ProcessControlRequest", @@ -1541,7 +1542,8 @@ void TestApps(void) 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); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_STOP_ERR3_EID), "CFE_ES_ProcessControlRequest", @@ -1556,7 +1558,8 @@ void TestApps(void) 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); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_RESTART_APP_ERR4_EID), "CFE_ES_ProcessControlRequest", @@ -1571,7 +1574,8 @@ void TestApps(void) CFE_ES_RunStatus_SYS_RESTART; OS_ModuleLoad(&UtAppRecPtr->StartParams.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", @@ -1586,7 +1590,8 @@ void TestApps(void) CFE_ES_RunStatus_SYS_RELOAD; OS_ModuleLoad(&UtAppRecPtr->StartParams.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", @@ -1601,7 +1606,8 @@ void TestApps(void) CFE_ES_RunStatus_SYS_RELOAD; OS_ModuleLoad(&UtAppRecPtr->StartParams.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", @@ -1625,7 +1631,8 @@ void TestApps(void) OS_ModuleLoad(&UtAppRecPtr->StartParams.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", @@ -1640,7 +1647,8 @@ void TestApps(void) UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_ERROR; OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_ERREXIT_APP_ERR_EID), "CFE_ES_ProcessControlRequest", @@ -1662,7 +1670,8 @@ void TestApps(void) UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_DELETE; OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_STOP_INF_EID), "CFE_ES_ProcessControlRequest", @@ -1684,7 +1693,8 @@ void TestApps(void) UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RESTART; OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_RESTART_APP_INF_EID), "CFE_ES_ProcessControlRequest", @@ -1706,7 +1716,8 @@ void TestApps(void) UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_RELOAD; OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_RELOAD_APP_INF_EID), "CFE_ES_ProcessControlRequest", @@ -1730,7 +1741,8 @@ void TestApps(void) UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_SYS_EXCEPTION; OS_ModuleLoad(&UtAppRecPtr->StartParams.ModuleId, NULL, NULL); - CFE_ES_ProcessControlRequest(UtAppRecPtr); + Id = CFE_ES_AppRecordGetID(UtAppRecPtr); + CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, UT_EventIsInHistory(CFE_ES_PCR_ERR1_EID), "CFE_ES_ProcessControlRequest", @@ -1800,8 +1812,9 @@ void TestApps(void) OS_ModuleLoad(&UtAppRecPtr->StartParams.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"); @@ -1814,8 +1827,9 @@ void TestApps(void) 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"); @@ -1826,8 +1840,9 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); OS_ModuleLoad(&UtAppRecPtr->StartParams.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"); @@ -1838,8 +1853,9 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); OS_ModuleLoad(&UtAppRecPtr->StartParams.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"); @@ -2015,8 +2031,9 @@ void TestApps(void) OS_ModuleLoad(&UtAppRecPtr->StartParams.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__, @@ -2038,8 +2055,9 @@ void TestApps(void) 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__, @@ -2065,12 +2083,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 +2106,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"); @@ -2113,8 +2133,9 @@ void TestApps(void) OS_ModuleLoad(&UtAppRecPtr->StartParams.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", From 0749d692c0c402ed2f1f22913966225fe6345680 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Fri, 16 Oct 2020 12:19:27 -0400 Subject: [PATCH 6/8] Fix #173, refactor app and lib loading procedure Reorganize the global data structures for apps and libraries into components that can be shared between the two concepts. Break up the monolithic AppCreate and LoadLibrary functions and have these call subroutines that operate on the common components. --- fsw/cfe-core/src/es/cfe_es_api.c | 2 +- fsw/cfe-core/src/es/cfe_es_apps.c | 618 ++++++++++++--------- fsw/cfe-core/src/es/cfe_es_apps.h | 108 +++- fsw/cfe-core/src/es/cfe_es_resource.h | 4 +- fsw/cfe-core/src/es/cfe_es_start.c | 170 +++--- fsw/cfe-core/unit-test/es_UT.c | 185 +++--- fsw/cfe-core/unit-test/ut_osprintf_stubs.c | 6 +- 7 files changed, 604 insertions(+), 489 deletions(-) diff --git a/fsw/cfe-core/src/es/cfe_es_api.c b/fsw/cfe-core/src/es/cfe_es_api.c index 22cbbe1e5..78b2feb25 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 diff --git a/fsw/cfe-core/src/es/cfe_es_apps.c b/fsw/cfe-core/src/es/cfe_es_apps.c index 8cb13dd16..a20402195 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); @@ -1014,9 +1117,9 @@ void CFE_ES_ProcessControlRequest(CFE_ES_ResourceID_t AppId) PendingControlReq == CFE_ES_RunStatus_SYS_RELOAD ) { StartupStatus = CFE_ES_AppCreate(&NewAppId, - OrigStartParams.FileName, - OrigStartParams.EntryPoint, - OrigStartParams.Name, + OrigStartParams.BasicInfo.FileName, + OrigStartParams.BasicInfo.EntryPoint, + OrigStartParams.BasicInfo.Name, OrigStartParams.Priority, OrigStartParams.StackSize, OrigStartParams.ExceptionAction); @@ -1167,7 +1270,7 @@ void CFE_ES_ProcessControlRequest(CFE_ES_ResourceID_t AppId) } CFE_EVS_SendEvent(EventID, EventType, "%s Application %s %s", - ReqName, OrigStartParams.Name, MessageDetail); + ReqName, OrigStartParams.BasicInfo.Name, MessageDetail); } } /* End Function */ @@ -1218,7 +1321,7 @@ int32 CFE_ES_CleanUpApp(CFE_ES_ResourceID_t AppId) * * (this will be OS_OBJECT_ID_UNDEFINED if it was not loaded dynamically) */ - ModuleId = AppRecPtr->StartParams.ModuleId; + ModuleId = AppRecPtr->ModuleInfo.ModuleId; } /* @@ -1645,18 +1748,17 @@ int32 CFE_ES_GetAppInfoInternal(CFE_ES_AppRecord_t *AppRecPtr, CFE_ES_AppInfo_t sizeof(AppInfoPtr->Name)-1); AppInfoPtr->Name[sizeof(AppInfoPtr->Name)-1] = '\0'; - strncpy((char *)AppInfoPtr->EntryPoint, - AppRecPtr->StartParams.EntryPoint, + strncpy(AppInfoPtr->EntryPoint, AppRecPtr->StartParams.BasicInfo.EntryPoint, sizeof(AppInfoPtr->EntryPoint) - 1); AppInfoPtr->EntryPoint[sizeof(AppInfoPtr->EntryPoint) - 1] = '\0'; - strncpy((char *)AppInfoPtr->FileName, (char *)AppRecPtr->StartParams.FileName, + strncpy(AppInfoPtr->FileName, AppRecPtr->StartParams.BasicInfo.FileName, sizeof(AppInfoPtr->FileName) - 1); AppInfoPtr->FileName[sizeof(AppInfoPtr->FileName) - 1] = '\0'; - AppInfoPtr->ModuleId = AppRecPtr->StartParams.ModuleId; + AppInfoPtr->ModuleId = AppRecPtr->ModuleInfo.ModuleId; AppInfoPtr->StackSize = AppRecPtr->StartParams.StackSize; - CFE_SB_SET_MEMADDR(AppInfoPtr->StartAddress, AppRecPtr->StartParams.StartAddress); + CFE_SB_SET_MEMADDR(AppInfoPtr->StartAddress, AppRecPtr->ModuleInfo.EntryAddress); AppInfoPtr->ExceptionAction = AppRecPtr->StartParams.ExceptionAction; AppInfoPtr->Priority = AppRecPtr->StartParams.Priority; diff --git a/fsw/cfe-core/src/es/cfe_es_apps.h b/fsw/cfe-core/src/es/cfe_es_apps.h index 4cf2c11bc..2c7540e50 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]; + char Name[OS_MAX_API_NAME]; + char EntryPoint[OS_MAX_API_NAME]; + char FileName[OS_MAX_PATH_LEN]; - uint32 StackSize; - cpuaddr StartAddress; - osal_id_t ModuleId; +} 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 +{ + cpuaddr EntryAddress; + osal_id_t ModuleId; - uint16 ExceptionAction; - uint16 Priority; +} CFE_ES_ModuleLoadStatus_t; + + + +/* +** 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); /* 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/unit-test/es_UT.c b/fsw/cfe-core/unit-test/es_UT.c index 3a134cf50..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, @@ -1498,17 +1484,17 @@ 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; Id = CFE_ES_AppRecordGetID(UtAppRecPtr); @@ -1525,7 +1511,7 @@ 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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); Id = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, @@ -1541,7 +1527,7 @@ 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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); Id = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, @@ -1557,7 +1543,7 @@ 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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); Id = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, @@ -1572,7 +1558,7 @@ 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); Id = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(Id); @@ -1588,7 +1574,7 @@ 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); Id = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(Id); @@ -1604,7 +1590,7 @@ 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); Id = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(Id); @@ -1618,17 +1604,17 @@ 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; Id = CFE_ES_AppRecordGetID(UtAppRecPtr); @@ -1646,7 +1632,7 @@ 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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); Id = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, @@ -1657,19 +1643,19 @@ 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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); Id = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, @@ -1680,19 +1666,19 @@ 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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); Id = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, @@ -1703,19 +1689,19 @@ 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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); Id = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, @@ -1728,19 +1714,19 @@ 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); + OS_ModuleLoad(&UtAppRecPtr->ModuleInfo.ModuleId, NULL, NULL); Id = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_ES_ProcessControlRequest(Id); UT_Report(__FILE__, __LINE__, @@ -1809,7 +1795,7 @@ 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); @@ -1823,7 +1809,7 @@ 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); @@ -1838,7 +1824,7 @@ 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__, @@ -1851,7 +1837,7 @@ 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__, @@ -2023,12 +2009,12 @@ 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); @@ -2051,7 +2037,7 @@ 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 */ @@ -2072,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); @@ -2131,7 +2117,7 @@ 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__, @@ -2202,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; @@ -2216,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, @@ -2242,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", @@ -2290,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 @@ -2304,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/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", }; From 1c75d338435a6ff1ccd7475edc4186455c0ea845 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Mon, 19 Oct 2020 16:34:18 -0400 Subject: [PATCH 7/8] Fix #28, Provide Library API similar to App API Allows the existing "CFE_ES_AppInfo_t" structure to be extended to libraries as well as applications by introducing a new value (3) for the Type field. Allows Libraries to be queried via API calls similar to App API. Also extends the Query All/Query One commands to operate on Libraries or Applications. --- fsw/cfe-core/src/es/cfe_es_api.c | 258 ++++++++++++++---- fsw/cfe-core/src/es/cfe_es_apps.c | 211 ++++---------- fsw/cfe-core/src/es/cfe_es_apps.h | 33 ++- fsw/cfe-core/src/es/cfe_es_task.c | 105 +++++-- fsw/cfe-core/src/es/cfe_es_task.h | 6 + fsw/cfe-core/src/inc/cfe_es.h | 76 +++++- fsw/cfe-core/src/inc/cfe_es_extern_typedefs.h | 7 +- 7 files changed, 444 insertions(+), 252 deletions(-) diff --git a/fsw/cfe-core/src/es/cfe_es_api.c b/fsw/cfe-core/src/es/cfe_es_api.c index 78b2feb25..3955160bd 100644 --- a/fsw/cfe-core/src/es/cfe_es_api.c +++ b/fsw/cfe-core/src/es/cfe_es_api.c @@ -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 a20402195..3800a898c 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.c +++ b/fsw/cfe-core/src/es/cfe_es_apps.c @@ -1713,7 +1713,7 @@ int32 CFE_ES_CleanupTaskResources(CFE_ES_ResourceID_t TaskId) /* **--------------------------------------------------------------------------------------- -** Name: CFE_ES_GetAppInfoInternal +** Name: CFE_ES_CopyModuleBasicInfo ** ** Purpose: Populate the cFE_ES_AppInfo structure with the data for an app. ** @@ -1721,180 +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; + strncpy(AppInfoPtr->Name, ParamsPtr->Name, + sizeof(AppInfoPtr->Name)-1); + AppInfoPtr->Name[sizeof(AppInfoPtr->Name)-1] = '\0'; - 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(AppInfoPtr->EntryPoint, AppRecPtr->StartParams.BasicInfo.EntryPoint, - sizeof(AppInfoPtr->EntryPoint) - 1); - AppInfoPtr->EntryPoint[sizeof(AppInfoPtr->EntryPoint) - 1] = '\0'; - - strncpy(AppInfoPtr->FileName, AppRecPtr->StartParams.BasicInfo.FileName, - sizeof(AppInfoPtr->FileName) - 1); - AppInfoPtr->FileName[sizeof(AppInfoPtr->FileName) - 1] = '\0'; - - AppInfoPtr->ModuleId = AppRecPtr->ModuleInfo.ModuleId; - AppInfoPtr->StackSize = AppRecPtr->StartParams.StackSize; - CFE_SB_SET_MEMADDR(AppInfoPtr->StartAddress, AppRecPtr->ModuleInfo.EntryAddress); - 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->EntryPoint, ParamsPtr->EntryPoint, + sizeof(AppInfoPtr->EntryPoint) - 1); + AppInfoPtr->EntryPoint[sizeof(AppInfoPtr->EntryPoint) - 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; - } - - } - - 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 2c7540e50..e9aaa7562 100644 --- a/fsw/cfe-core/src/es/cfe_es_apps.h +++ b/fsw/cfe-core/src/es/cfe_es_apps.h @@ -279,18 +279,33 @@ int32 CFE_ES_CleanUpApp(CFE_ES_ResourceID_t AppId); */ 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_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 Date: Wed, 28 Oct 2020 11:15:39 -0400 Subject: [PATCH 8/8] Bump to v6.8.0-rc1+dev150, Update Readme --- README.md | 19 +++++++++++++++++++ fsw/cfe-core/src/inc/cfe_version.h | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) 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/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 */