Skip to content

Commit

Permalink
Merge pull request #1148 from jphickey/fix-139-filewrite-background
Browse files Browse the repository at this point in the history
Fix #139, Do file writes in background
  • Loading branch information
astrogeco authored Feb 17, 2021
2 parents c708d64 + 81cbc46 commit 37df32d
Show file tree
Hide file tree
Showing 25 changed files with 1,764 additions and 1,033 deletions.
11 changes: 8 additions & 3 deletions fsw/cfe-core/src/es/cfe_es_apps.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,14 @@ bool CFE_ES_RunAppTableScan(uint32 ElapsedTime, void *Arg);
bool CFE_ES_RunExceptionScan(uint32 ElapsedTime, void *Arg);

/*
** Check if ER log dump request is pending
*/
bool CFE_ES_RunERLogDump(uint32 ElapsedTime, void *Arg);
* Background file write data getter for ER log entry
*/
bool CFE_ES_BackgroundERLogFileDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize);

/*
* Background file write event handler for ER log entry
*/
void CFE_ES_BackgroundERLogFileEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum, size_t BlockSize, size_t Position);

/*
** Perform the requested control action for an application
Expand Down
6 changes: 3 additions & 3 deletions fsw/cfe-core/src/es/cfe_es_backgroundtask.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ const CFE_ES_BackgroundJobEntry_t CFE_ES_BACKGROUND_JOB_TABLE[] =
.ActivePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE,
.IdlePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE
},
{ /* Check for ER log write requests */
.RunFunc = CFE_ES_RunERLogDump,
.JobArg = &CFE_ES_TaskData.BackgroundERLogDumpState,
{ /* Call FS to handle background file writes */
.RunFunc = CFE_FS_RunBackgroundFileDump,
.JobArg = NULL,
.ActivePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE,
.IdlePeriod = CFE_PLATFORM_ES_APP_SCAN_RATE
}
Expand Down
186 changes: 89 additions & 97 deletions fsw/cfe-core/src/es/cfe_es_erlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,126 +181,118 @@ int32 CFE_ES_WriteToERLog( CFE_ES_LogEntryType_Enum_t EntryType, uint32 Reset
} /* End of CFE_ES_WriteToERLog() */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Function: CFE_ES_RunERLogDump() */
/* Function: CFE_ES_BackgroundERLogFileDataGetter() */
/* */
/* Purpose: */
/* Write exception & reset log to a file. */
/* */
/* Implemented as an ES background job, but the entire file write is done */
/* in a single invocation, as the file is expected to be relatively small. */
/* Gets a single record from exception & reset log to write to a file. */
/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool CFE_ES_RunERLogDump(uint32 ElapsedTime, void *Arg)
bool CFE_ES_BackgroundERLogFileDataGetter(void *Meta, uint32 RecordNum, void **Buffer, size_t *BufSize)
{
CFE_ES_BackgroundLogDumpGlobal_t *State = (CFE_ES_BackgroundLogDumpGlobal_t *)Arg;
int32 Status;
int32 PspStatus;
CFE_FS_Header_t FileHdr;
CFE_ES_ERLog_FileEntry_t FileEntry;
CFE_ES_BackgroundLogDumpGlobal_t *BgFilePtr;
CFE_ES_ERLog_FileEntry_t *FileBufferPtr;
CFE_ES_ERLog_MetaData_t *EntryPtr;
uint32 FileSize;
uint32 i;
osal_id_t fd;

int32 PspStatus;

BgFilePtr = (CFE_ES_BackgroundLogDumpGlobal_t *)Meta;
FileBufferPtr = &BgFilePtr->EntryBuffer;

if (!State->IsPending)
if (RecordNum < CFE_PLATFORM_ES_ER_LOG_ENTRIES)
{
return false;
}
EntryPtr = &CFE_ES_ResetDataPtr->ERLog[RecordNum];

FileSize = 0;
Status = OS_OpenCreate(&fd, State->DataFileName, OS_FILE_FLAG_CREATE | OS_FILE_FLAG_TRUNCATE, OS_WRITE_ONLY);
if(Status < 0)
{
CFE_EVS_SendEvent(CFE_ES_ERLOG2_ERR_EID,CFE_EVS_EventType_ERROR,
"Error creating file %s, RC = %d",
State->DataFileName, (int)Status);
}
else
{
CFE_FS_InitHeader(&FileHdr, CFE_ES_ER_LOG_DESC, CFE_FS_SubType_ES_ERLOG);
/* First wipe the buffer before re-use */
memset(FileBufferPtr, 0, sizeof(*FileBufferPtr));

CFE_ES_LockSharedData(__func__,__LINE__);

/* The basic info comes directly from the ES log */
FileBufferPtr->BaseInfo = EntryPtr->BaseInfo;

/* write the cFE header to the file */
Status = CFE_FS_WriteHeader(fd, &FileHdr);
if(Status != sizeof(CFE_FS_Header_t))
/*
* The context info, if available, comes from the PSP.
* This returns the actual size of the context info, or <0 on error.
*/
PspStatus = CFE_PSP_Exception_CopyContext(EntryPtr->PspContextId, &FileBufferPtr->Context,
sizeof(FileBufferPtr->Context));
if (PspStatus > 0)
{
CFE_ES_FileWriteByteCntErr(State->DataFileName,sizeof(CFE_FS_Header_t),Status);
FileBufferPtr->ContextSize = PspStatus;
}
else
{
FileSize += Status;

/* write a single ER log entry on each pass */
for(i=0;i<CFE_PLATFORM_ES_ER_LOG_ENTRIES;i++)
{
EntryPtr = &CFE_ES_ResetDataPtr->ERLog[i];

/* The basic info comes directly from the ES log */
FileEntry.BaseInfo = EntryPtr->BaseInfo;

/*
* The context info, if available, comes from the PSP.
* This returns the actual size of the context info, or <0 on error.
*/
PspStatus = CFE_PSP_Exception_CopyContext(EntryPtr->PspContextId, &FileEntry.Context, sizeof(FileEntry.Context));
if (PspStatus > 0)
{
FileEntry.ContextSize = PspStatus;
}
else
{
/*
* errors here are OK - just means there is no context available.
* Record a size of 0 in the log file.
*/
FileEntry.ContextSize = 0;
}

/*
* any unused context space should be cleared.
*
* This is for binary compatibility with historical log files, where a fixed amount
* of space is given per-entry, regardless of the actual size.
*/
if (FileEntry.ContextSize < sizeof(FileEntry.Context))
{
memset(&FileEntry.Context[FileEntry.ContextSize], 0,
sizeof(FileEntry.Context) - FileEntry.ContextSize);
}

/*
* Now write to file
*/
Status = OS_write(fd,&FileEntry,sizeof(FileEntry));

if(Status != sizeof(FileEntry))
{
CFE_ES_FileWriteByteCntErr(State->DataFileName,sizeof(FileEntry),Status);
break;
}/* end if */
/*
* errors here are OK - just means there is no context available.
* Record a size of 0 in the log file.
*/
FileBufferPtr->ContextSize = 0;
}

FileSize += Status;
CFE_ES_UnlockSharedData(__func__,__LINE__);

} /* end for */
/*
* Export data to caller for actual write
*/
*Buffer = FileBufferPtr;
*BufSize = sizeof(*FileBufferPtr);
}
else
{
*Buffer = NULL;
*BufSize = 0;
}

} /* end if */
/* Check for EOF (last entry) */
return (RecordNum >= (CFE_PLATFORM_ES_ER_LOG_ENTRIES-1));
}

OS_close(fd);

CFE_EVS_SendEvent(CFE_ES_ERLOG2_EID, CFE_EVS_EventType_DEBUG,
"%s written:Size=%lu",State->DataFileName,(unsigned long)FileSize);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Function: CFE_ER_BackgroundERLogFileEventHandler() */
/* */
/* Purpose: */
/* Report events during writing exception & reset log to a file. */
/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void CFE_ES_BackgroundERLogFileEventHandler(void *Meta, CFE_FS_FileWriteEvent_t Event, int32 Status, uint32 RecordNum, size_t BlockSize, size_t Position)
{
CFE_ES_BackgroundLogDumpGlobal_t *BgFilePtr;

} /* end if */
BgFilePtr = (CFE_ES_BackgroundLogDumpGlobal_t *)Meta;

/*
* Always clear the "pending" flag whether successful or not.
* If unsuccessful, an operator needs to investigate the error and re-issue command.
* Note that this runs in the context of ES background task (file writer background job)
* It does NOT run in the context of the CFE_TBL app task.
*
* Events should use CFE_EVS_SendEventWithAppID() rather than CFE_EVS_SendEvent()
* to get proper association with TBL task.
*/
State->IsPending = false;

return false;
}/* end CFE_ES_RunERLogDump */

switch(Event)
{
case CFE_FS_FileWriteEvent_COMPLETE:
CFE_EVS_SendEvent(CFE_ES_ERLOG2_EID, CFE_EVS_EventType_DEBUG,
"%s written:Size=%lu",
BgFilePtr->FileWrite.FileName,(unsigned long)Position);
break;

case CFE_FS_FileWriteEvent_HEADER_WRITE_ERROR:
case CFE_FS_FileWriteEvent_RECORD_WRITE_ERROR:
CFE_EVS_SendEvent(CFE_ES_FILEWRITE_ERR_EID,CFE_EVS_EventType_ERROR,
"File write,byte cnt err,file %s,request=%u,actual=%u",
BgFilePtr->FileWrite.FileName, (int)BlockSize, (int)Status);
break;

case CFE_FS_FileWriteEvent_CREATE_ERROR:
CFE_EVS_SendEvent(CFE_ES_ERLOG2_ERR_EID,CFE_EVS_EventType_ERROR,
"Error creating file %s, RC = %d",
BgFilePtr->FileWrite.FileName, (int)Status);
break;

default:
/* unhandled event - ignore */
break;
}
}

/*
**---------------------------------------------------------------------------------------
Expand Down
45 changes: 35 additions & 10 deletions fsw/cfe-core/src/es/cfe_es_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -1612,26 +1612,51 @@ int32 CFE_ES_ClearERLogCmd(const CFE_ES_ClearERLogCmd_t *data)
int32 CFE_ES_WriteERLogCmd(const CFE_ES_WriteERLogCmd_t *data)
{
const CFE_ES_FileNameCmd_Payload_t *CmdPtr = &data->Payload;
CFE_ES_BackgroundLogDumpGlobal_t *StatePtr;
int32 Status;

StatePtr = &CFE_ES_TaskData.BackgroundERLogDumpState;

/* check if pending before overwriting fields in the structure */
if (CFE_FS_BackgroundFileDumpIsPending(&StatePtr->FileWrite))
{
Status = CFE_STATUS_REQUEST_ALREADY_PENDING;
}
else
{
/* Reset the entire state object (just for good measure, ensure no stale data) */
memset(StatePtr, 0, sizeof(*StatePtr));

/*
* Fill out the remainder of meta data.
* This data is currently the same for every request
*/
StatePtr->FileWrite.FileSubType = CFE_FS_SubType_ES_ERLOG;
snprintf(StatePtr->FileWrite.Description, sizeof(StatePtr->FileWrite.Description), CFE_ES_ER_LOG_DESC);

StatePtr->FileWrite.GetData = CFE_ES_BackgroundERLogFileDataGetter;
StatePtr->FileWrite.OnEvent = CFE_ES_BackgroundERLogFileEventHandler;

if (CFE_ES_TaskData.BackgroundERLogDumpState.IsPending)
CFE_SB_MessageStringGet(StatePtr->FileWrite.FileName, CmdPtr->FileName,
CFE_PLATFORM_ES_DEFAULT_ER_LOG_FILE,
sizeof(StatePtr->FileWrite.FileName), sizeof(CmdPtr->FileName));

Status = CFE_FS_BackgroundFileDumpRequest(&StatePtr->FileWrite);
}

if (Status != CFE_SUCCESS)
{
CFE_EVS_SendEvent(CFE_ES_ERLOG_PENDING_ERR_EID,CFE_EVS_EventType_ERROR,
"Error log write to file %s already in progress",
CFE_ES_TaskData.BackgroundERLogDumpState.DataFileName);
StatePtr->FileWrite.FileName);

/* background dump already running, consider this an error */
CFE_ES_TaskData.CommandErrorCounter++;
}
}
else
{
CFE_SB_MessageStringGet(CFE_ES_TaskData.BackgroundERLogDumpState.DataFileName, (char *)CmdPtr->FileName,
CFE_PLATFORM_ES_DEFAULT_ER_LOG_FILE,
sizeof(CFE_ES_TaskData.BackgroundERLogDumpState.DataFileName), sizeof(CmdPtr->FileName));

CFE_ES_TaskData.BackgroundERLogDumpState.IsPending = true;
CFE_ES_TaskData.CommandCounter++;
CFE_ES_BackgroundWakeup();
}
}

return CFE_SUCCESS;
}/* end CFE_ES_WriteERLogCmd */
Expand Down
6 changes: 3 additions & 3 deletions fsw/cfe-core/src/es/cfe_es_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "cfe_es_events.h"
#include "cfe_es_msg.h"
#include "cfe_es_perf.h"
#include "private/cfe_es_erlog_typedef.h"

/*************************************************************************/

Expand Down Expand Up @@ -90,8 +91,8 @@
*/
typedef struct
{
volatile bool IsPending;
char DataFileName[OS_MAX_PATH_LEN];
CFE_FS_FileWriteMetaData_t FileWrite; /**< FS state data - must be first */
CFE_ES_ERLog_FileEntry_t EntryBuffer; /**< Temp holding area for record to write */
} CFE_ES_BackgroundLogDumpGlobal_t;

/*
Expand Down Expand Up @@ -164,7 +165,6 @@ void CFE_ES_TaskPipe(CFE_SB_Buffer_t *SBBufPtr);
*/
int32 CFE_ES_BackgroundInit(void);
void CFE_ES_BackgroundTask(void);
void CFE_ES_BackgroundWakeup(void);
void CFE_ES_BackgroundCleanup(void);

/*
Expand Down
Loading

0 comments on commit 37df32d

Please sign in to comment.