GCC Code Coverage Report


Directory: ./
File: WasmSequencerController.cpp
Date: 2026-10-14 22:13:20
Exec Total Coverage
Lines: 7 217 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 ✗ Svc::WasmSequencer_RequestContext context = value.get_context();
39 ✗ context.set_moduleIdx(static_cast<WasmSequencer_ModuleIdx>(moduleIdx));
40 ✗ this->controller_sendSignal_invoked(context);
41 ✗ }
42 ✗ }
43
44 ✗ 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 ✗ if (value.get_block() == Svc::BlockState::NO_BLOCK) {
50 // Respond to this request!
51 ✗ this->respondToRequest(value, Fw::CmdResponse::OK);
52 }
53 ✗ }
54
55 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respond_ERROR(
56 SmId smId,
57 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
58 const Svc::WasmSequencer_RequestContext& value) {
59 ✗ this->respondToRequest(value, Fw::CmdResponse::EXECUTION_ERROR);
60
61 // Respond to all wait requests
62 ✗ this->respondToWaiting(Fw::CmdResponse::EXECUTION_ERROR);
63
64 // Respond to port requests
65 ✗ this->reportSeqAborted(value, Fw::CmdResponse::EXECUTION_ERROR);
66 ✗ }
67
68 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_incrementSequenceFailure(
69 SmId smId,
70 Svc_WasmSequencer_ControllerStateMachine::Signal signal) {
71 ✗ this->m_tlm.sequencesFailed++;
72 ✗ }
73
74 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_setCancelRequested(
75 SmId smId,
76 Svc_WasmSequencer_ControllerStateMachine::Signal signal) {
77 ✗ this->m_cancelRequested = true;
78 ✗ }
79
80 1 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_clearCancelRequested(
81 SmId smId,
82 Svc_WasmSequencer_ControllerStateMachine::Signal signal) {
83 1 this->m_cancelRequested = false;
84 1 }
85
86 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_cancelPendingRequest(
87 SmId smId,
88 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
89 const Svc::WasmSequencer_RequestContext& value) {
90 ✗ this->m_tlm.sequencesCancelled++;
91 ✗ this->respondToRequest(value, Fw::CmdResponse::EXECUTION_ERROR);
92 ✗ this->respondToWaiting(Fw::CmdResponse::EXECUTION_ERROR);
93
94 // Respond to port requests
95 ✗ this->reportSeqAborted(value, Fw::CmdResponse::EXECUTION_ERROR);
96 ✗ }
97
98 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respondInvoke_BUSY(
99 SmId smId,
100 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
101 const Svc::WasmSequencer_InvokeRequest& value) {
102 ✗ this->log_WARNING_LO_ControllerBusy(value.get_context().get_source(), this->controller_getState());
103 ✗ this->respondToRequest(value.get_context(), Fw::CmdResponse::BUSY);
104 ✗ }
105
106 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respondInvoke_ERROR(
107 SmId smId,
108 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
109 const Svc::WasmSequencer_InvokeRequest& value) {
110 ✗ this->log_WARNING_LO_ControllerCannotInvoke();
111 ✗ this->respondToRequest(value.get_context(), Fw::CmdResponse::EXECUTION_ERROR);
112 ✗ }
113
114 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respondLoad_BUSY(
115 SmId smId,
116 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
117 const Svc::WasmSequencer_LoadRequest& value) {
118 ✗ this->log_WARNING_LO_ControllerBusy(value.get_context().get_source(), this->controller_getState());
119 ✗ this->respondToRequest(value.get_context(), Fw::CmdResponse::BUSY);
120
121 // Respond to port requests
122 ✗ this->reportSeqAborted(value.get_context(), Fw::CmdResponse::BUSY);
123 ✗ }
124
125 ✗ 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 ✗ if (value.get_block() == Svc::BlockState::BLOCK) {
131 // Respond to this request!
132 ✗ this->respondToRequest(value, Fw::CmdResponse::OK);
133 }
134
135 // Respond to all wait requests
136 ✗ this->respondToWaiting(Fw::CmdResponse::OK);
137
138 // If this concluded an active RUN, report the done to internal callers.
139 ✗ this->reportSeqDone(value, Fw::CmdResponse::OK);
140 ✗ }
141
142 ✗ 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 ✗ if (value.get_block() == Svc::BlockState::BLOCK) {
148 // Respond to this request!
149 ✗ this->respondToRequest(value, Fw::CmdResponse::EXECUTION_ERROR);
150 }
151
152 // Respond to all wait requests
153 ✗ this->respondToWaiting(Fw::CmdResponse::EXECUTION_ERROR);
154
155 // If this concluded an active RUN, report the done to internal callers.
156 ✗ this->reportSeqDone(value, Fw::CmdResponse::EXECUTION_ERROR);
157 ✗ }
158
159 ✗ bool WasmSequencer ::resolveSequencePath(const Fw::StringBase& fileName, Fw::String& filePath) {
160 // Resolve the requested path against the SEQ_BASE_DIR parameter
161 ✗ Fw::ParamValid baseDirValid;
162 ✗ const Fw::ParamString baseDir = this->paramGet_SEQ_BASE_DIR(baseDirValid);
163
164 ✗ if (baseDir.length() == 0) {
165 ✗ filePath = fileName;
166 ✗ 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 ✗ if (WasmSequencer::pathHasParentTraversal(fileName)) {
174 ✗ this->log_WARNING_HI_SequenceFilePathNotContained(baseDir, fileName);
175 ✗ 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 ✗ const FwSizeType baseLen = static_cast<FwSizeType>(baseDir.length());
185 ✗ const char* const separator = (baseLen > 0 && baseDir.toChar()[baseLen - 1] == '/') ? "" : "/";
186
187 ✗ const Fw::FormatStatus fmtStatus = filePath.format("%s%s%s", baseDir.toChar(), separator, fileName.toChar());
188 ✗ if (fmtStatus != Fw::FormatStatus::SUCCESS) {
189 ✗ FW_ASSERT(fmtStatus == Fw::FormatStatus::OVERFLOWED, static_cast<FwAssertArgType>(fmtStatus));
190 ✗ this->log_WARNING_HI_SequenceFilePathTooLong(baseDir, fileName);
191 ✗ return false;
192 }
193
194 ✗ return true;
195 ✗ }
196
197 namespace {
198 struct WasmFileReader {
199 ✗ explicit WasmFileReader(Os::File& loadFile) : m_loadFile(loadFile) {}
200
201 ✗ spacewasm_read_result_t readChunk(const U8** outBuf, std::size_t* outLen) {
202 ✗ FwSizeType size = sizeof(this->m_readBuf);
203 ✗ const Os::File::Status status = this->m_loadFile.read(this->m_readBuf, size);
204
205 spacewasm_read_result_t readStatus;
206 ✗ 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 ✗ *outBuf = this->m_readBuf;
212 ✗ *outLen = static_cast<std::size_t>(size);
213
214 ✗ if (size == 0) {
215 ✗ readStatus = SPACEWASM_READ_EOF;
216 } else {
217 ✗ readStatus = SPACEWASM_READ_OK;
218 }
219 }
220
221 ✗ return readStatus;
222 }
223
224 ✗ static spacewasm_read_result_t readChunkCallback(void* userdata, const U8** outBuf, size_t* outLen) {
225 ✗ FW_ASSERT(userdata != nullptr);
226 ✗ 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 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_load(
238 SmId smId,
239 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
240 const Svc::WasmSequencer_LoadRequest& value) {
241 ✗ FW_ASSERT(this->m_wasm != nullptr);
242 ✗ FW_ASSERT(this->m_guest_allocator != nullptr);
243
244 // Resolve the sequence file path against SEQ_BASE_DIR
245 ✗ Fw::String filePath;
246 ✗ if (!this->resolveSequencePath(value.get_fileName(), filePath)) {
247 ✗ this->controller_sendSignal_loadFailed(value.get_context());
248 ✗ return;
249 }
250
251 // Record the sequence name for telemetry (module name, or filename stem).
252 ✗ this->setSequenceName(filePath, value.get_moduleName());
253
254 ✗ Os::File file;
255 ✗ const Os::File::Status openStatus = file.open(filePath.toChar(), Os::File::OPEN_READ);
256 ✗ if (openStatus != Os::File::Status::OP_OK) {
257 ✗ this->log_WARNING_HI_FileOpenError(filePath, openStatus);
258 ✗ this->controller_sendSignal_loadFailed(value.get_context());
259 ✗ return;
260 }
261
262 ✗ this->m_lastLoadFileName = value.get_fileName();
263
264 ✗ this->takeAllocatorLock();
265
266 ✗ U32 moduleIndex = 0;
267 ✗ Svc::WasmSequencer_RequestContext next = value.get_context();
268
269 ✗ WasmFileReader reader(file);
270
271 auto status =
272 ✗ spacewasm_load_module(this->m_wasm, value.get_moduleName().toChar(), &WasmFileReader::readChunkCallback,
273 &reader, this->m_guest_allocator, &moduleIndex);
274
275 ✗ next.set_moduleIdx(static_cast<WasmSequencer_ModuleIdx>(moduleIndex));
276
277 ✗ this->releaseAllocatorLock();
278
279 ✗ file.close();
280
281 ✗ if (status == SPACEWASM_OK) {
282 ✗ this->controller_sendSignal_loadSucceeded(next);
283 } else {
284 ✗ this->log_WARNING_HI_ModuleLoadFailed(WasmSequencer_Status(status));
285 ✗ this->controller_sendSignal_loadFailed(value.get_context());
286 }
287 ✗ }
288
289 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_invokeStart(
290 SmId smId,
291 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
292 const Svc::WasmSequencer_RequestContext& value) {
293 U32 start_module_idx;
294 U32 start_function_idx;
295
296 // Get the module's start function WasmRef
297 ✗ auto status = spacewasm_module_start(this->m_wasm, value.get_moduleIdx(), &start_module_idx, &start_function_idx);
298 ✗ FW_ASSERT(status == SPACEWASM_OK, status);
299
300 ✗ this->m_invokeStatus = spacewasm_invoke(this->m_wasm, start_module_idx, start_function_idx, nullptr, 0);
301 ✗ }
302
303 ✗ 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 ✗ U32 funcIndex = 0;
309 ✗ 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 ✗ FW_ASSERT(status == SPACEWASM_OK, status);
313
314 ✗ this->m_invokeStatus =
315 ✗ spacewasm_invoke(this->m_wasm, static_cast<U32>(value.get_moduleIdx()), funcIndex, nullptr, 0);
316 ✗ }
317 ✗ 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 ✗ auto problemStatus = this->validateModuleMain(value.get_moduleIdx());
323 ✗ this->log_WARNING_HI_InvalidModuleEntrypoint(value.get_moduleIdx(), WasmSequencer_Status(problemStatus));
324 ✗ }
325
326 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleMainInvokeFailed(
327 SmId smId,
328 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
329 const Svc::WasmSequencer_RequestContext& value) {
330 ✗ this->log_WARNING_HI_ModuleMainInvokeFailed(WasmSequencer_Status(this->m_invokeStatus));
331 ✗ }
332
333 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStartInvokeFailed(
334 SmId smId,
335 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
336 const Svc::WasmSequencer_RequestContext& value) {
337 ✗ this->log_WARNING_HI_ModuleStartInvokeFailed(WasmSequencer_Status(this->m_invokeStatus));
338 ✗ }
339
340 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStarted(
341 SmId smId,
342 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
343 const Svc::WasmSequencer_RequestContext& value) {
344 ✗ this->log_ACTIVITY_HI_SequenceStarting(value.get_moduleIdx());
345 ✗ if (value.get_source() == Svc::WasmSequencer_SignalSource::COMMAND_RUN ||
346 ✗ value.get_source() == Svc::WasmSequencer_SignalSource::PORT_RUN) {
347 ✗ if (this->isConnected_seqStartOut_OutputPort(0)) {
348 ✗ this->seqStartOut_out(0, this->m_lastLoadFileName, Svc::SeqArgs{});
349 }
350 }
351 ✗ }
352
353 1 void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_resetStore(
354 SmId smId,
355 Svc_WasmSequencer_ControllerStateMachine::Signal signal) {
356
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (this->m_wasm == nullptr) {
357 // The store has not been created yet.
358 // This should be the initial transition
359 1 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 ✗ this->destroyStore();
365 ✗ this->createStore();
366 }
367 1 }
368
369 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_runEngine(
370 SmId smId,
371 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
372 const Svc::WasmSequencer_RequestContext& value) {
373 ✗ this->interpreter_sendSignal_run(value);
374 ✗ }
375
376 ✗ void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleSucceeded(
377 SmId smId,
378 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
379 const Svc::WasmSequencer_RequestContext& value) {
380 ✗ this->m_tlm.sequencesSucceeded++;
381 ✗ this->log_ACTIVITY_HI_SequenceSucceeded(value.get_moduleIdx());
382 ✗ }
383
384 ✗ 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 ✗ this->reportSequenceRuntimeFailure(value.get_moduleIdx(), WasmSequencer_SequencePhase::START);
391 ✗ }
392
393 ✗ 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 ✗ this->reportSequenceRuntimeFailure(value.get_moduleIdx(), WasmSequencer_SequencePhase::MAIN);
399 ✗ }
400
401 ✗ void WasmSequencer ::reportSequenceRuntimeFailure(WasmSequencer_ModuleIdx moduleIdx,
402 WasmSequencer_SequencePhase phase) {
403 ✗ switch (this->m_exit.reason) {
404 ✗ case WasmSequencer_ExitReason::CANCEL:
405 ✗ this->m_tlm.sequencesCancelled++;
406 ✗ this->log_ACTIVITY_HI_SequenceCancelled(moduleIdx, phase);
407 ✗ break;
408 ✗ case WasmSequencer_ExitReason::HOST_PANIC:
409 ✗ this->m_tlm.sequencesFailed++;
410 ✗ this->log_WARNING_HI_SequencePanic(moduleIdx, phase, this->m_exit.code);
411 ✗ break;
412 ✗ case WasmSequencer_ExitReason::INTERPRETER_TRAP:
413 ✗ this->m_tlm.sequencesFailed++;
414 ✗ this->log_WARNING_HI_SequenceTrapped(moduleIdx, phase, this->m_exit.lastTrapReason);
415 ✗ break;
416 ✗ 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 ✗ this->m_tlm.sequencesFailed++;
421 ✗ this->log_WARNING_HI_SequenceExited(moduleIdx, phase, this->m_exit.code);
422 ✗ break;
423 ✗ 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 ✗ this->m_tlm.sequencesFailed++;
430 ✗ this->log_WARNING_HI_SequenceHostFailure(moduleIdx, phase, this->m_exit.reason,
431 ✗ this->m_exit.lastHostFunction);
432 ✗ break;
433 }
434 ✗ }
435
436 // ----------------------------------------------------------------------
437 // Implementations for internal state machine guards
438 // ----------------------------------------------------------------------
439
440 ✗ bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_moduleHasStart(
441 SmId smId,
442 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
443 const Svc::WasmSequencer_RequestContext& value) const {
444 U32 start_module_idx;
445 U32 start_function_idx;
446 ✗ auto status = spacewasm_module_start(this->m_wasm, static_cast<U32>(value.get_moduleIdx()), &start_module_idx,
447 &start_function_idx);
448
449 ✗ switch (status) {
450 ✗ case SPACEWASM_OK:
451 ✗ return true;
452 ✗ case SPACEWASM_ERR_NOT_FOUND:
453 ✗ 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 ✗ bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_moduleHasValidMain(
462 SmId smId,
463 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
464 const Svc::WasmSequencer_RequestContext& value) const {
465 ✗ return this->validateModuleMain(value.get_moduleIdx()) == SPACEWASM_OK;
466 }
467
468 ✗ bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_invokeSucceeded(
469 SmId smId,
470 Svc_WasmSequencer_ControllerStateMachine::Signal signal,
471 const Svc::WasmSequencer_RequestContext& value) const {
472 ✗ return this->m_invokeStatus == SPACEWASM_OK;
473 }
474
475 ✗ 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 ✗ switch (this->m_exit.reason) {
483 ✗ case WasmSequencer_ExitReason::INTERPRETER_FINISHED:
484 case WasmSequencer_ExitReason::HOST_EXIT:
485 ✗ return this->m_exit.code == 0;
486 ✗ default:
487 ✗ return false;
488 }
489 }
490
491 ✗ bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_cancelRequested(
492 SmId smId,
493 Svc_WasmSequencer_ControllerStateMachine::Signal signal) const {
494 ✗ return this->m_cancelRequested;
495 }
496
497 } // namespace Svc
498