|
| 1 | +/* |
| 2 | +** GSC-18128-1, "Core Flight Executive Version 6.7" |
| 3 | +** |
| 4 | +** Copyright (c) 2006-2019 United States Government as represented by |
| 5 | +** the Administrator of the National Aeronautics and Space Administration. |
| 6 | +** All Rights Reserved. |
| 7 | +** |
| 8 | +** Licensed under the Apache License, Version 2.0 (the "License"); |
| 9 | +** you may not use this file except in compliance with the License. |
| 10 | +** You may obtain a copy of the License at |
| 11 | +** |
| 12 | +** http://www.apache.org/licenses/LICENSE-2.0 |
| 13 | +** |
| 14 | +** Unless required by applicable law or agreed to in writing, software |
| 15 | +** distributed under the License is distributed on an "AS IS" BASIS, |
| 16 | +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 17 | +** See the License for the specific language governing permissions and |
| 18 | +** limitations under the License. |
| 19 | +*/ |
| 20 | + |
| 21 | +/* |
| 22 | +** File: cfe_es_backgroundtask.c |
| 23 | +** |
| 24 | +** Purpose: This file contains the implementation of the ES "background task" |
| 25 | +** |
| 26 | +** This task sits idle most of the time, but is woken by the ES application |
| 27 | +** for various maintenance duties that may take time to execute, such as |
| 28 | +** writing status/log files. |
| 29 | +** |
| 30 | +*/ |
| 31 | + |
| 32 | +/* |
| 33 | +** Include Section |
| 34 | +*/ |
| 35 | + |
| 36 | +#include <string.h> |
| 37 | + |
| 38 | +#include "osapi.h" |
| 39 | +#include "private/cfe_private.h" |
| 40 | +#include "cfe_es_perf.h" |
| 41 | +#include "cfe_es_global.h" |
| 42 | +#include "cfe_es_task.h" |
| 43 | + |
| 44 | +#define CFE_ES_BACKGROUND_SEM_NAME "ES_BackgroundSem" |
| 45 | +#define CFE_ES_BACKGROUND_CHILD_NAME "ES_BackgroundTask" |
| 46 | +#define CFE_ES_BACKGROUND_CHILD_STACK_PTR NULL |
| 47 | +#define CFE_ES_BACKGROUND_CHILD_STACK_SIZE CFE_PLATFORM_ES_PERF_CHILD_STACK_SIZE |
| 48 | +#define CFE_ES_BACKGROUND_CHILD_PRIORITY CFE_PLATFORM_ES_PERF_CHILD_PRIORITY |
| 49 | +#define CFE_ES_BACKGROUND_CHILD_FLAGS 0 |
| 50 | +#define CFE_ES_BACKGROUND_MAX_IDLE_DELAY 30000 /* 30 seconds */ |
| 51 | + |
| 52 | + |
| 53 | +typedef struct |
| 54 | +{ |
| 55 | + bool (*RunFunc)(uint32 ElapsedTime, void *Arg); |
| 56 | + void *JobArg; |
| 57 | + uint32 ActivePeriod; /**< max wait/delay time between calls when job is active */ |
| 58 | + uint32 IdlePeriod; /**< max wait/delay time between calls when job is idle */ |
| 59 | +} CFE_ES_BackgroundJobEntry_t; |
| 60 | + |
| 61 | +/* |
| 62 | + * List of "background jobs" |
| 63 | + * |
| 64 | + * This is just a list of functions to periodically call from the context of the background task, |
| 65 | + * and can be added/extended as needed. |
| 66 | + * |
| 67 | + * Each Job function returns a boolean, and should return "true" if it is active, or "false" if it is idle. |
| 68 | + * |
| 69 | + * This uses "cooperative multitasking" -- the function should do some limited work, then return to the |
| 70 | + * background task. It will be called again after a delay period to do more work. |
| 71 | + */ |
| 72 | +const CFE_ES_BackgroundJobEntry_t CFE_ES_BACKGROUND_JOB_TABLE[] = |
| 73 | +{ |
| 74 | + { /* Performance Log Data Dump to file */ |
| 75 | + .RunFunc = CFE_ES_RunPerfLogDump, |
| 76 | + .JobArg = &CFE_ES_TaskData.BackgroundPerfDumpState, |
| 77 | + .ActivePeriod = CFE_PLATFORM_ES_PERF_CHILD_MS_DELAY, |
| 78 | + .IdlePeriod = CFE_PLATFORM_ES_PERF_CHILD_MS_DELAY * 1000 |
| 79 | + } |
| 80 | +}; |
| 81 | + |
| 82 | +#define CFE_ES_BACKGROUND_NUM_JOBS (sizeof(CFE_ES_BACKGROUND_JOB_TABLE) / sizeof(CFE_ES_BACKGROUND_JOB_TABLE[0])) |
| 83 | + |
| 84 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 85 | +/* Name: CFE_ES_BackgroundTask */ |
| 86 | +/* */ |
| 87 | +/* Purpose: A helper task for low priority routines that may take time to */ |
| 88 | +/* execute, such as writing log files. */ |
| 89 | +/* */ |
| 90 | +/* Assumptions and Notes: This is started from the ES initialization, and */ |
| 91 | +/* pends on a semaphore until a work request comes in. This is intended to */ |
| 92 | +/* avoid the need to create a child task "on demand" when work items arrive, */ |
| 93 | +/* which is a form of dynamic allocation. */ |
| 94 | +/* */ |
| 95 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 96 | +void CFE_ES_BackgroundTask(void) |
| 97 | +{ |
| 98 | + int32 status; |
| 99 | + uint32 JobTotal; |
| 100 | + uint32 NumJobsRunning; |
| 101 | + uint32 NextDelay; |
| 102 | + uint32 ElapsedTime; |
| 103 | + OS_time_t CurrTime; |
| 104 | + OS_time_t LastTime; |
| 105 | + const CFE_ES_BackgroundJobEntry_t *JobPtr; |
| 106 | + |
| 107 | + status = CFE_ES_RegisterChildTask(); |
| 108 | + if (status != CFE_SUCCESS) |
| 109 | + { |
| 110 | + /* should never occur */ |
| 111 | + CFE_ES_WriteToSysLog("CFE_ES: Background Task Failed to register: %08lx\n", (unsigned long)status); |
| 112 | + return; |
| 113 | + } |
| 114 | + |
| 115 | + CFE_PSP_GetTime(&LastTime); |
| 116 | + |
| 117 | + while (true) |
| 118 | + { |
| 119 | + /* |
| 120 | + * compute the elapsed time (difference) between last |
| 121 | + * execution and now, in microseconds. |
| 122 | + * |
| 123 | + * Note this calculation is done as a uint32 which will overflow |
| 124 | + * after about 35 minutes, but the max delays ensure that this |
| 125 | + * executes at least every few seconds, so that should never happen. |
| 126 | + */ |
| 127 | + CFE_PSP_GetTime(&CurrTime); |
| 128 | + ElapsedTime = 1000000 * (CurrTime.seconds - LastTime.seconds); |
| 129 | + ElapsedTime += CurrTime.microsecs; |
| 130 | + ElapsedTime -= LastTime.microsecs; |
| 131 | + LastTime = CurrTime; |
| 132 | + |
| 133 | + /* |
| 134 | + * convert to milliseconds. |
| 135 | + * we do not really need high precision |
| 136 | + * for background task timings |
| 137 | + */ |
| 138 | + ElapsedTime /= 1000; |
| 139 | + |
| 140 | + NextDelay = CFE_ES_BACKGROUND_MAX_IDLE_DELAY; /* default; will be adjusted based on active jobs */ |
| 141 | + JobPtr = CFE_ES_BACKGROUND_JOB_TABLE; |
| 142 | + JobTotal = CFE_ES_BACKGROUND_NUM_JOBS; |
| 143 | + NumJobsRunning = 0; |
| 144 | + |
| 145 | + while (JobTotal > 0) |
| 146 | + { |
| 147 | + /* |
| 148 | + * call the background job - |
| 149 | + * if it returns "true" that means it is active, |
| 150 | + * if it returns "false" that means it is idle |
| 151 | + */ |
| 152 | + if (JobPtr->RunFunc != NULL && JobPtr->RunFunc(ElapsedTime, JobPtr->JobArg)) |
| 153 | + { |
| 154 | + ++NumJobsRunning; |
| 155 | + |
| 156 | + if (JobPtr->ActivePeriod != 0 && NextDelay > JobPtr->ActivePeriod) |
| 157 | + { |
| 158 | + /* next delay is based on this active job wait time */ |
| 159 | + NextDelay = JobPtr->ActivePeriod; |
| 160 | + } |
| 161 | + } |
| 162 | + else if (JobPtr->IdlePeriod != 0 && NextDelay > JobPtr->IdlePeriod) |
| 163 | + { |
| 164 | + /* next delay is based on this idle job wait time */ |
| 165 | + NextDelay = JobPtr->IdlePeriod; |
| 166 | + } |
| 167 | + --JobTotal; |
| 168 | + ++JobPtr; |
| 169 | + } |
| 170 | + |
| 171 | + CFE_ES_Global.BackgroundTask.NumJobsRunning = NumJobsRunning; |
| 172 | + |
| 173 | + status = OS_BinSemTimedWait(CFE_ES_Global.BackgroundTask.WorkSem, NextDelay); |
| 174 | + if (status != OS_SUCCESS && status != OS_SEM_TIMEOUT) |
| 175 | + { |
| 176 | + /* should never occur */ |
| 177 | + CFE_ES_WriteToSysLog("CFE_ES: Failed to take background sem: %08lx\n", (unsigned long)status); |
| 178 | + break; |
| 179 | + } |
| 180 | + |
| 181 | + } |
| 182 | +} |
| 183 | + |
| 184 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 185 | +/* Name: CFE_ES_BackgroundInit */ |
| 186 | +/* */ |
| 187 | +/* Purpose: Initialize the background task */ |
| 188 | +/* */ |
| 189 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 190 | +int32 CFE_ES_BackgroundInit(void) |
| 191 | +{ |
| 192 | + int32 status; |
| 193 | + |
| 194 | + status = OS_BinSemCreate(&CFE_ES_Global.BackgroundTask.WorkSem, CFE_ES_BACKGROUND_SEM_NAME, 0, 0); |
| 195 | + if (status != OS_SUCCESS) |
| 196 | + { |
| 197 | + CFE_ES_WriteToSysLog("CFE_ES: Failed to create background sem: %08lx\n", (unsigned long)status); |
| 198 | + return status; |
| 199 | + } |
| 200 | + |
| 201 | + /* Spawn a task to write the performance data to a file */ |
| 202 | + status = CFE_ES_CreateChildTask(&CFE_ES_Global.BackgroundTask.TaskID, |
| 203 | + CFE_ES_BACKGROUND_CHILD_NAME, |
| 204 | + CFE_ES_BackgroundTask, |
| 205 | + CFE_ES_BACKGROUND_CHILD_STACK_PTR, |
| 206 | + CFE_ES_BACKGROUND_CHILD_STACK_SIZE, |
| 207 | + CFE_ES_BACKGROUND_CHILD_PRIORITY, |
| 208 | + CFE_ES_BACKGROUND_CHILD_FLAGS); |
| 209 | + |
| 210 | + if (status != OS_SUCCESS) |
| 211 | + { |
| 212 | + CFE_ES_WriteToSysLog("CFE_ES: Failed to create background task: %08lx\n", (unsigned long)status); |
| 213 | + return status; |
| 214 | + } |
| 215 | + |
| 216 | + return CFE_SUCCESS; |
| 217 | +} |
| 218 | + |
| 219 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 220 | +/* Name: CFE_ES_BackgroundCleanup */ |
| 221 | +/* */ |
| 222 | +/* Purpose: Exit/Stop the background task */ |
| 223 | +/* */ |
| 224 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 225 | +void CFE_ES_BackgroundCleanup(void) |
| 226 | +{ |
| 227 | + CFE_ES_DeleteChildTask(CFE_ES_Global.BackgroundTask.TaskID); |
| 228 | + OS_BinSemDelete(CFE_ES_Global.BackgroundTask.WorkSem); |
| 229 | + |
| 230 | + CFE_ES_Global.BackgroundTask.TaskID = 0; |
| 231 | + CFE_ES_Global.BackgroundTask.WorkSem = 0; |
| 232 | +} |
| 233 | + |
| 234 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 235 | +/* Name: CFE_ES_BackgroundWakeup */ |
| 236 | +/* */ |
| 237 | +/* Purpose: Wake up the background task */ |
| 238 | +/* Notifies the background task to perform an extra poll for new work */ |
| 239 | +/* */ |
| 240 | +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
| 241 | +void CFE_ES_BackgroundWakeup(void) |
| 242 | +{ |
| 243 | + /* wake up the background task by giving the sem. |
| 244 | + * This is "informational" and not strictly required, |
| 245 | + * but it will make the task immediately wake up and check for new |
| 246 | + * work if it was idle. */ |
| 247 | + OS_BinSemGive(CFE_ES_Global.BackgroundTask.WorkSem); |
| 248 | +} |
| 249 | + |
| 250 | + |
0 commit comments