GCC Code Coverage Report


Directory: ./
File: WasmSequencerController.cpp
Date: 2026-09-23 22:13:25
Exec Total Coverage
Lines: 7 219 3.2%
Functions: 2 34 5.9%
Branches: 1 141 0.7%

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