GCC Code Coverage Report


Directory: ./
File: Svc/WasmSequencer/WasmSequencerController.cpp
Date: 2026-10-14 21:15:02
Exec Total Coverage
Lines: 217 222 97.7%
Functions: 34 34 100.0%
Branches: 139 143 97.2%

Line Branch Exec Source
1 // ======================================================================
2 // \title WasmSequencerController.cpp
3 // \author tumbar
4 // \brief cpp file for WasmSequencer controller state machine
5 // ======================================================================
6
7 #include "Fw/Cmd/CmdResponseEnumAc.hpp"
8 #include "Fw/Types/Assert.hpp"
9 #include "Os/File.hpp"
10 #include "Svc/Seq/BlockStateEnumAc.hpp"
11 #include "Svc/WasmSequencer/WasmSequencer.hpp"
12 #include "Svc/WasmSequencer/WasmSequencer_LoadRequestSerializableAc.hpp"
13 #include "Svc/WasmSequencer/WasmSequencer_ModuleIdxAliasAc.hpp"
14 #include "Svc/WasmSequencer/WasmSequencer_SignalSourceEnumAc.hpp"
15 #include "config/FwAssertArgTypeAliasAc.h"
16 #include "spacewasm.h"
17
18 namespace Svc {
19
20 // ----------------------------------------------------------------------
21 // Implementations for internal state machine actions
22 // ----------------------------------------------------------------------
23
24 11 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_processInvoke(
25 SmId smId,
26 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
27 const Svc::WasmSequencer_InvokeRequest& value) {
28 // Resolve the module name to its index within the engine.
29 11 FW_ASSERT(this->m_wasm != nullptr);
30 11 U32 moduleIdx = 0;
31 const spacewasm_status_t findStatus =
32
1/1
✓ Branch 13 taken 11 times.
11 spacewasm_find_module(this->m_wasm, value.get_moduleName().toChar(), &moduleIdx);
33
34
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
11 if (findStatus != SPACEWASM_OK) {
35
1/1
✓ Branch 11 taken 2 times.
2 this->log_WARNING_LO_ModuleNotFound(value.get_moduleName());
36
1/1
✓ Branch 9 taken 2 times.
2 this->controller_sendSignal_invokeFailed(value.get_context());
37 } else {
38
1/1
✓ Branch 6 taken 9 times.
9 Svc::WasmSequencer_RequestContext context = value.get_context();
39
1/1
✓ Branch 2 taken 9 times.
9 context.set_moduleIdx(static_cast<WasmSequencer_ModuleIdx>(moduleIdx));
40
1/1
✓ Branch 5 taken 9 times.
9 this->controller_sendSignal_invoked(context);
41 9 }
42 11 }
43
44 136 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respond_noblock_OK(
45 SmId smId,
46 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
47 const Svc::WasmSequencer_RequestContext& value) {
48 // Respond only to NO_BLOCK requests
49
2/2
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 107 times.
136 if (value.get_block() == Svc::BlockState::NO_BLOCK) {
50 // Respond to this request!
51
2/2
✓ Branch 5 taken 29 times.
✓ Branch 9 taken 29 times.
29 this->respondToRequest(value, Fw::CmdResponse::OK);
52 }
53 136 }
54
55 28 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respond_ERROR(
56 SmId smId,
57 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
58 const Svc::WasmSequencer_RequestContext& value) {
59
2/2
✓ Branch 5 taken 28 times.
✓ Branch 9 taken 28 times.
28 this->respondToRequest(value, Fw::CmdResponse::EXECUTION_ERROR);
60
61 // Respond to all wait requests
62
2/2
✓ Branch 5 taken 28 times.
✓ Branch 9 taken 28 times.
28 this->respondToWaiting(Fw::CmdResponse::EXECUTION_ERROR);
63
64 // Respond to port requests
65
2/2
✓ Branch 5 taken 28 times.
✓ Branch 9 taken 28 times.
28 this->reportSeqAborted(value, Fw::CmdResponse::EXECUTION_ERROR);
66 28 }
67
68 24 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_incrementSequenceFailure(
69 SmId smId,
70 Svc_WasmSequencer_ControllerStateMachine::Signal signal) {
71 24 this->m_tlm.sequencesFailed++;
72 24 }
73
74 8 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_setCancelRequested(
75 SmId smId,
76 Svc_WasmSequencer_ControllerStateMachine::Signal signal) {
77 8 this->m_cancelRequested = true;
78 8 }
79
80 438 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_clearCancelRequested(
81 SmId smId,
82 Svc_WasmSequencer_ControllerStateMachine::Signal signal) {
83 438 this->m_cancelRequested = false;
84 438 }
85
86 7 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_cancelPendingRequest(
87 SmId smId,
88 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
89 const Svc::WasmSequencer_RequestContext& value) {
90 7 this->m_tlm.sequencesCancelled++;
91
2/2
✓ Branch 5 taken 7 times.
✓ Branch 9 taken 7 times.
7 this->respondToRequest(value, Fw::CmdResponse::EXECUTION_ERROR);
92
2/2
✓ Branch 5 taken 7 times.
✓ Branch 9 taken 7 times.
7 this->respondToWaiting(Fw::CmdResponse::EXECUTION_ERROR);
93
94 // Respond to port requests
95
2/2
✓ Branch 5 taken 7 times.
✓ Branch 9 taken 7 times.
7 this->reportSeqAborted(value, Fw::CmdResponse::EXECUTION_ERROR);
96 7 }
97
98 1 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respondInvoke_BUSY(
99 SmId smId,
100 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
101 const Svc::WasmSequencer_InvokeRequest& value) {
102
3/3
✓ Branch 7 taken 1 times.
✓ Branch 20 taken 1 times.
✓ Branch 24 taken 1 times.
1 this->log_WARNING_LO_ControllerBusy(value.get_context().get_source(), this->controller_getState());
103
2/2
✓ Branch 5 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->respondToRequest(value.get_context(), Fw::CmdResponse::BUSY);
104 1 }
105
106 1 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respondInvoke_ERROR(
107 SmId smId,
108 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
109 const Svc::WasmSequencer_InvokeRequest& value) {
110 1 this->log_WARNING_LO_ControllerCannotInvoke();
111
2/2
✓ Branch 5 taken 1 times.
✓ Branch 13 taken 1 times.
1 this->respondToRequest(value.get_context(), Fw::CmdResponse::EXECUTION_ERROR);
112 1 }
113
114 3 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respondLoad_BUSY(
115 SmId smId,
116 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
117 const Svc::WasmSequencer_LoadRequest& value) {
118
3/3
✓ Branch 7 taken 3 times.
✓ Branch 20 taken 3 times.
✓ Branch 24 taken 3 times.
3 this->log_WARNING_LO_ControllerBusy(value.get_context().get_source(), this->controller_getState());
119
2/2
✓ Branch 5 taken 3 times.
✓ Branch 13 taken 3 times.
3 this->respondToRequest(value.get_context(), Fw::CmdResponse::BUSY);
120
121 // Respond to port requests
122
2/2
✓ Branch 5 taken 3 times.
✓ Branch 13 taken 3 times.
3 this->reportSeqAborted(value.get_context(), Fw::CmdResponse::BUSY);
123 3 }
124
125 108 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respond_block_OK(
126 SmId smId,
127 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
128 const Svc::WasmSequencer_RequestContext& value) {
129 // Respond only to BLOCK requests
130
2/2
✓ Branch 4 taken 94 times.
✓ Branch 5 taken 14 times.
108 if (value.get_block() == Svc::BlockState::BLOCK) {
131 // Respond to this request!
132
2/2
✓ Branch 5 taken 94 times.
✓ Branch 9 taken 94 times.
94 this->respondToRequest(value, Fw::CmdResponse::OK);
133 }
134
135 // Respond to all wait requests
136
2/2
✓ Branch 5 taken 108 times.
✓ Branch 9 taken 108 times.
108 this->respondToWaiting(Fw::CmdResponse::OK);
137
138 // If this concluded an active RUN, report the done to internal callers.
139
2/2
✓ Branch 5 taken 108 times.
✓ Branch 9 taken 108 times.
108 this->reportSeqDone(value, Fw::CmdResponse::OK);
140 108 }
141
142 73 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respond_block_ERROR(
143 SmId smId,
144 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
145 const Svc::WasmSequencer_RequestContext& value) {
146 // Respond only to BLOCK requests
147
2/2
✓ Branch 4 taken 58 times.
✓ Branch 5 taken 15 times.
73 if (value.get_block() == Svc::BlockState::BLOCK) {
148 // Respond to this request!
149
2/2
✓ Branch 5 taken 58 times.
✓ Branch 9 taken 58 times.
58 this->respondToRequest(value, Fw::CmdResponse::EXECUTION_ERROR);
150 }
151
152 // Respond to all wait requests
153
2/2
✓ Branch 5 taken 73 times.
✓ Branch 9 taken 73 times.
73 this->respondToWaiting(Fw::CmdResponse::EXECUTION_ERROR);
154
155 // If this concluded an active RUN, report the done to internal callers.
156
2/2
✓ Branch 5 taken 73 times.
✓ Branch 9 taken 73 times.
73 this->reportSeqDone(value, Fw::CmdResponse::EXECUTION_ERROR);
157 73 }
158
159 206 bool WasmSequencer ::resolveSequencePath(const Fw::StringBase& fileName, Fw::String& filePath) {
160 // Resolve the requested path against the SEQ_BASE_DIR parameter
161
1/1
✓ Branch 2 taken 206 times.
206 Fw::ParamValid baseDirValid;
162
1/1
✓ Branch 3 taken 206 times.
206 const Fw::ParamString baseDir = this->paramGet_SEQ_BASE_DIR(baseDirValid);
163
164
3/3
✓ Branch 2 taken 206 times.
✓ Branch 4 taken 201 times.
✓ Branch 5 taken 5 times.
206 if (baseDir.length() == 0) {
165
1/1
✓ Branch 7 taken 201 times.
201 filePath = fileName;
166 201 return true;
167 }
168
169 // With a base dir configured, SEQ_BASE_DIR acts as a containment boundary.
170 // A ground-supplied file name containing a ".." component could escape it
171 // (e.g. "../../etc/passwd"), so reject such names rather than opening a path
172 // outside the configured base directory.
173
3/3
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 4 times.
5 if (WasmSequencer::pathHasParentTraversal(fileName)) {
174
1/1
✓ Branch 5 taken 1 times.
1 this->log_WARNING_HI_SequenceFilePathNotContained(baseDir, fileName);
175 1 return false;
176 }
177
178 // Join the base dir and file name with exactly one '/' separator. Without an
179 // explicit separator a base dir that lacks a trailing slash both mis-resolves
180 // ordinary names ("seqs" + "a.wasm" -> "seqsa.wasm") and can escape the
181 // containment boundary ("seqs" + "_priv/x.wasm" -> "seqs_priv/x.wasm", a sibling
182 // directory). The ".." rejection above plus a guaranteed base-dir prefix keeps
183 // the resolved path inside the configured directory.
184
1/1
✓ Branch 2 taken 4 times.
4 const FwSizeType baseLen = static_cast<FwSizeType>(baseDir.length());
185
3/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
4 const char* const separator = (baseLen > 0 && baseDir.toChar()[baseLen - 1] == '/') ? "" : "/";
186
187
2/2
✓ Branch 15 taken 4 times.
✓ Branch 20 taken 4 times.
4 const Fw::FormatStatus fmtStatus = filePath.format("%s%s%s", baseDir.toChar(), separator, fileName.toChar());
188
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (fmtStatus != Fw::FormatStatus::SUCCESS) {
189 1 FW_ASSERT(fmtStatus == Fw::FormatStatus::OVERFLOWED, static_cast<FwAssertArgType>(fmtStatus));
190
1/1
✓ Branch 5 taken 1 times.
1 this->log_WARNING_HI_SequenceFilePathTooLong(baseDir, fileName);
191 1 return false;
192 }
193
194 3 return true;
195 206 }
196
197 namespace {
198 struct WasmFileReader {
199 198 explicit WasmFileReader(Os::File& loadFile) : m_loadFile(loadFile) {}
200
201 390 spacewasm_read_result_t readChunk(const U8** outBuf, std::size_t* outLen) {
202 390 FwSizeType size = sizeof(this->m_readBuf);
203
1/1
✓ Branch 7 taken 390 times.
390 const Os::File::Status status = this->m_loadFile.read(this->m_readBuf, size);
204
205 spacewasm_read_result_t readStatus;
206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 390 times.
390 if (status != Os::File::Status::OP_OK) {
207 ✗ *outLen = 0;
208 ✗ readStatus = SPACEWASM_READ_ERROR;
209 } else {
210 // `size` is updated in-place with the number of bytes actually read.
211 390 *outBuf = this->m_readBuf;
212 390 *outLen = static_cast<std::size_t>(size);
213
214
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 198 times.
390 if (size == 0) {
215 192 readStatus = SPACEWASM_READ_EOF;
216 } else {
217 198 readStatus = SPACEWASM_READ_OK;
218 }
219 }
220
221 390 return readStatus;
222 }
223
224 390 static spacewasm_read_result_t readChunkCallback(void* userdata, const U8** outBuf, size_t* outLen) {
225 390 FW_ASSERT(userdata != nullptr);
226 390 return static_cast<WasmFileReader*>(userdata)->readChunk(outBuf, outLen);
227 }
228
229 //! Currently loading file handle
230 Os::File& m_loadFile;
231
232 //! Buffer handed to the streaming loader, filled from `m_loadFile`.
233 U8 m_readBuf[Svc::WasmSequencerConfig::LOAD_READ_CHUNK_SIZE]{};
234 };
235 } // namespace
236
237 206 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_load(
238 SmId smId,
239 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
240 const Svc::WasmSequencer_LoadRequest& value) {
241 206 FW_ASSERT(this->m_wasm != nullptr);
242 206 FW_ASSERT(this->m_guest_allocator != nullptr);
243
244 // Resolve the sequence file path against SEQ_BASE_DIR
245
1/1
✓ Branch 2 taken 206 times.
206 Fw::String filePath;
246
3/3
✓ Branch 10 taken 206 times.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 204 times.
206 if (!this->resolveSequencePath(value.get_fileName(), filePath)) {
247
1/1
✓ Branch 9 taken 2 times.
2 this->controller_sendSignal_loadFailed(value.get_context());
248 2 return;
249 }
250
251 // Record the sequence name for telemetry (module name, or filename stem).
252
1/1
✓ Branch 10 taken 204 times.
204 this->setSequenceName(filePath, value.get_moduleName());
253
254
1/1
✓ Branch 2 taken 204 times.
204 Os::File file;
255
1/1
✓ Branch 4 taken 204 times.
204 const Os::File::Status openStatus = file.open(filePath.toChar(), Os::File::OPEN_READ);
256
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 198 times.
204 if (openStatus != Os::File::Status::OP_OK) {
257
1/1
✓ Branch 5 taken 6 times.
6 this->log_WARNING_HI_FileOpenError(filePath, openStatus);
258
1/1
✓ Branch 9 taken 6 times.
6 this->controller_sendSignal_loadFailed(value.get_context());
259 6 return;
260 }
261
262
1/1
✓ Branch 12 taken 198 times.
198 this->m_lastLoadFileName = value.get_fileName();
263
264
1/1
✓ Branch 4 taken 198 times.
198 this->takeAllocatorLock();
265
266 198 U32 moduleIndex = 0;
267
1/1
✓ Branch 6 taken 198 times.
198 Svc::WasmSequencer_RequestContext next = value.get_context();
268
269 198 WasmFileReader reader(file);
270
271 auto status =
272
1/1
✓ Branch 15 taken 198 times.
198 spacewasm_load_module(this->m_wasm, value.get_moduleName().toChar(), &WasmFileReader::readChunkCallback,
273 198 &reader, this->m_guest_allocator, &moduleIndex);
274
275
1/1
✓ Branch 2 taken 198 times.
198 next.set_moduleIdx(static_cast<WasmSequencer_ModuleIdx>(moduleIndex));
276
277
1/1
✓ Branch 4 taken 198 times.
198 this->releaseAllocatorLock();
278
279
1/1
✓ Branch 2 taken 198 times.
198 file.close();
280
281
2/2
✓ Branch 0 taken 191 times.
✓ Branch 1 taken 7 times.
198 if (status == SPACEWASM_OK) {
282
1/1
✓ Branch 5 taken 191 times.
191 this->controller_sendSignal_loadSucceeded(next);
283 } else {
284
2/2
✓ Branch 6 taken 7 times.
✓ Branch 10 taken 7 times.
7 this->log_WARNING_HI_ModuleLoadFailed(WasmSequencer_Status(status));
285
1/1
✓ Branch 9 taken 7 times.
7 this->controller_sendSignal_loadFailed(value.get_context());
286 }
287 212 }
288
289 13 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_invokeStart(
290 SmId smId,
291 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
292 const Svc::WasmSequencer_RequestContext& value) {
293 13 U32 start_module_idx;
294 13 U32 start_function_idx;
295
296 // Get the module's start function WasmRef
297
1/1
✓ Branch 9 taken 13 times.
13 auto status = spacewasm_module_start(this->m_wasm, value.get_moduleIdx(), &start_module_idx, &start_function_idx);
298 13 FW_ASSERT(status == SPACEWASM_OK, status);
299
300
1/1
✓ Branch 7 taken 13 times.
13 this->m_invokeStatus = spacewasm_invoke(this->m_wasm, start_module_idx, start_function_idx, nullptr, 0);
301 13 }
302
303 138 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_invokeMain(
304 SmId smId,
305 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
306 const Svc::WasmSequencer_RequestContext& value) {
307 // Resolve the main function of given module index
308 138 U32 funcIndex = 0;
309
1/1
✓ Branch 9 taken 138 times.
138 auto status = spacewasm_find_export_func(this->m_wasm, static_cast<U32>(value.get_moduleIdx()), "main", &funcIndex);
310
311 // This should always succeed because our state machine is checking whether this module has a main/is-valid
312 138 FW_ASSERT(status == SPACEWASM_OK, status);
313
314 276 this->m_invokeStatus =
315
1/1
✓ Branch 10 taken 138 times.
276 spacewasm_invoke(this->m_wasm, static_cast<U32>(value.get_moduleIdx()), funcIndex, nullptr, 0);
316 138 }
317 3 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleInvalidMain(
318 SmId smId,
319 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
320 const Svc::WasmSequencer_RequestContext& value) {
321 // Get the failure status of why the main module is invalid
322 3 auto problemStatus = this->validateModuleMain(value.get_moduleIdx());
323
2/2
✓ Branch 6 taken 3 times.
✓ Branch 14 taken 3 times.
3 this->log_WARNING_HI_InvalidModuleEntrypoint(value.get_moduleIdx(), WasmSequencer_Status(problemStatus));
324 3 }
325
326 2 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleMainInvokeFailed(
327 SmId smId,
328 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
329 const Svc::WasmSequencer_RequestContext& value) {
330
2/2
✓ Branch 10 taken 2 times.
✓ Branch 14 taken 2 times.
2 this->log_WARNING_HI_ModuleMainInvokeFailed(WasmSequencer_Status(this->m_invokeStatus));
331 2 }
332
333 2 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStartInvokeFailed(
334 SmId smId,
335 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
336 const Svc::WasmSequencer_RequestContext& value) {
337
2/2
✓ Branch 10 taken 2 times.
✓ Branch 14 taken 2 times.
2 this->log_WARNING_HI_ModuleStartInvokeFailed(WasmSequencer_Status(this->m_invokeStatus));
338 2 }
339
340 136 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStarted(
341 SmId smId,
342 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
343 const Svc::WasmSequencer_RequestContext& value) {
344 136 this->log_ACTIVITY_HI_SequenceStarting(value.get_moduleIdx());
345
6/6
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 125 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 128 times.
✓ Branch 9 taken 8 times.
147 if (value.get_source() == Svc::WasmSequencer_SignalSource::COMMAND_RUN ||
346 11 value.get_source() == Svc::WasmSequencer_SignalSource::PORT_RUN) {
347
2/2
✓ Branch 5 taken 127 times.
✓ Branch 6 taken 1 times.
128 if (this->isConnected_seqStartOut_OutputPort(0)) {
348
2/2
✓ Branch 6 taken 127 times.
✓ Branch 13 taken 127 times.
127 this->seqStartOut_out(0, this->m_lastLoadFileName, Svc::SeqArgs{});
349 }
350 }
351 136 }
352
353 331 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_resetStore(
354 SmId smId,
355 Svc_WasmSequencer_ControllerStateMachine::Signal signal) {
356
2/2
✓ Branch 4 taken 218 times.
✓ Branch 5 taken 113 times.
331 if (this->m_wasm == nullptr) {
357 // The store has not been created yet.
358 // This should be the initial transition
359 218 FW_ASSERT(signal == Svc_WasmSequencer_ControllerStateMachine::Signal::__FPRIME_INITIAL_TRANSITION,
360 static_cast<FwAssertArgType>(signal));
361
362 // `configure()` will initialize the first store
363 } else {
364 113 this->destroyStore();
365 113 this->createStore();
366 }
367 331 }
368
369 147 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_runEngine(
370 SmId smId,
371 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
372 const Svc::WasmSequencer_RequestContext& value) {
373 147 this->interpreter_sendSignal_run(value);
374 147 }
375
376 62 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleSucceeded(
377 SmId smId,
378 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
379 const Svc::WasmSequencer_RequestContext& value) {
380 62 this->m_tlm.sequencesSucceeded++;
381 62 this->log_ACTIVITY_HI_SequenceSucceeded(value.get_moduleIdx());
382 62 }
383
384 4 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStartFailed(
385 SmId smId,
386 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
387 const Svc::WasmSequencer_RequestContext& value) {
388 // A failure while running a module's start function (LOAD-with-start, or the
389 // start phase of a RUN-with-start).
390
2/2
✓ Branch 5 taken 4 times.
✓ Branch 12 taken 4 times.
4 this->reportSequenceRuntimeFailure(value.get_moduleIdx(), WasmSequencer_SequencePhase::START);
391 4 }
392
393 73 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleMainFailed(
394 SmId smId,
395 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
396 const Svc::WasmSequencer_RequestContext& value) {
397 // A failure while running a module's main function.
398
2/2
✓ Branch 5 taken 73 times.
✓ Branch 12 taken 73 times.
73 this->reportSequenceRuntimeFailure(value.get_moduleIdx(), WasmSequencer_SequencePhase::MAIN);
399 73 }
400
401 77 void WasmSequencer ::reportSequenceRuntimeFailure(WasmSequencer_ModuleIdx moduleIdx,
402 WasmSequencer_SequencePhase phase) {
403
5/5
✓ Branch 6 taken 15 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 34 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 24 times.
77 switch (this->m_exit.reason) {
404 15 case WasmSequencer_ExitReason::CANCEL:
405 15 this->m_tlm.sequencesCancelled++;
406 15 this->log_ACTIVITY_HI_SequenceCancelled(moduleIdx, phase);
407 15 break;
408 2 case WasmSequencer_ExitReason::HOST_PANIC:
409 2 this->m_tlm.sequencesFailed++;
410 2 this->log_WARNING_HI_SequencePanic(moduleIdx, phase, this->m_exit.code);
411 2 break;
412 34 case WasmSequencer_ExitReason::INTERPRETER_TRAP:
413 34 this->m_tlm.sequencesFailed++;
414 34 this->log_WARNING_HI_SequenceTrapped(moduleIdx, phase, this->m_exit.lastTrapReason);
415 34 break;
416 2 case WasmSequencer_ExitReason::INTERPRETER_FINISHED: // fallthrough is intended
417 case WasmSequencer_ExitReason::HOST_EXIT:
418 // Only reached on the failure path: a non-zero main return value or a
419 // non-zero fprime.exit code.
420 2 this->m_tlm.sequencesFailed++;
421 2 this->log_WARNING_HI_SequenceExited(moduleIdx, phase, this->m_exit.code);
422 2 break;
423 24 case WasmSequencer_ExitReason::UNKNOWN:
424 case WasmSequencer_ExitReason::REPLY_TIMEOUT:
425 case WasmSequencer_ExitReason::HOST_FAILURE:
426 case WasmSequencer_ExitReason::UNEXPECTED_REPLY:
427 case WasmSequencer_ExitReason::TIMER_INCOMPARABLE:
428 default:
429 24 this->m_tlm.sequencesFailed++;
430 48 this->log_WARNING_HI_SequenceHostFailure(moduleIdx, phase, this->m_exit.reason,
431 24 this->m_exit.lastHostFunction);
432 24 break;
433 }
434 77 }
435
436 // ----------------------------------------------------------------------
437 // Implementations for internal state machine guards
438 // ----------------------------------------------------------------------
439
440 184 bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_moduleHasStart(
441 SmId smId,
442 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
443 const Svc::WasmSequencer_RequestContext& value) const {
444 184 U32 start_module_idx;
445 184 U32 start_function_idx;
446
1/1
✓ Branch 9 taken 184 times.
184 auto status = spacewasm_module_start(this->m_wasm, static_cast<U32>(value.get_moduleIdx()), &start_module_idx,
447 &start_function_idx);
448
449
2/3
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 171 times.
✗ Branch 2 not taken.
184 switch (status) {
450 13 case SPACEWASM_OK:
451 13 return true;
452 171 case SPACEWASM_ERR_NOT_FOUND:
453 171 return false;
454 ✗ default:
455 // All other status means we passed the c api invalid options
456 ✗ FW_ASSERT(false, status);
457 ✗ return false;
458 }
459 }
460
461 147 bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_moduleHasValidMain(
462 SmId smId,
463 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
464 const Svc::WasmSequencer_RequestContext& value) const {
465 147 return this->validateModuleMain(value.get_moduleIdx()) == SPACEWASM_OK;
466 }
467
468 151 bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_invokeSucceeded(
469 SmId smId,
470 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
471 const Svc::WasmSequencer_RequestContext& value) const {
472 151 return this->m_invokeStatus == SPACEWASM_OK;
473 }
474
475 146 bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_interpreterSucceeded(
476 SmId smId,
477 Svc_WasmSequencer_ControllerStateMachine::Signal signal) const {
478 // The engine sets m_exit.reason and m_exit.code before signalling
479 // engineFinished. A run succeeds only when it finished with a zero code:
480 // main returned 0 (a void return reports code 0) or the guest called
481 // fprime.exit(0)
482
2/2
✓ Branch 11 taken 71 times.
✓ Branch 12 taken 75 times.
146 switch (this->m_exit.reason) {
483 71 case WasmSequencer_ExitReason::INTERPRETER_FINISHED:
484 case WasmSequencer_ExitReason::HOST_EXIT:
485 71 return this->m_exit.code == 0;
486 75 default:
487 75 return false;
488 }
489 }
490
491 203 bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_cancelRequested(
492 SmId smId,
493 Svc_WasmSequencer_ControllerStateMachine::Signal signal) const {
494
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 203 times.
203 return this->m_cancelRequested;
495 }
496
497 } // namespace Svc
498