| 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 | // Store the arguments for the ARGS host function round trip and carry the | ||
| 39 | // resolved module index forward in the request context. | ||
| 40 |
1/1✓ Branch 10 taken 9 times.
|
9 | this->m_args = value.get_args(); |
| 41 |
1/1✓ Branch 6 taken 9 times.
|
9 | Svc::WasmSequencer_RequestContext context = value.get_context(); |
| 42 |
1/1✓ Branch 2 taken 9 times.
|
9 | context.set_moduleIdx(static_cast<WasmSequencer_ModuleIdx>(moduleIdx)); |
| 43 |
1/1✓ Branch 5 taken 9 times.
|
9 | this->controller_sendSignal_invoked(context); |
| 44 | 9 | } | |
| 45 | 11 | } | |
| 46 | |||
| 47 | 142 | 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 |
2/2✓ Branch 4 taken 29 times.
✓ Branch 5 taken 113 times.
|
142 | if (value.get_block() == Svc::BlockState::NO_BLOCK) { |
| 53 | // Respond to this request! | ||
| 54 |
2/2✓ Branch 5 taken 29 times.
✓ Branch 9 taken 29 times.
|
29 | this->respondToRequest(value, Fw::CmdResponse::OK); |
| 55 | } | ||
| 56 | 142 | } | |
| 57 | |||
| 58 | 28 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respond_ERROR( | |
| 59 | SmId smId, | ||
| 60 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 61 | const Svc::WasmSequencer_RequestContext& value) { | ||
| 62 |
2/2✓ Branch 5 taken 28 times.
✓ Branch 9 taken 28 times.
|
28 | this->respondToRequest(value, Fw::CmdResponse::EXECUTION_ERROR); |
| 63 | |||
| 64 | // Respond to all wait requests | ||
| 65 |
2/2✓ Branch 5 taken 28 times.
✓ Branch 9 taken 28 times.
|
28 | this->respondToWaiting(Fw::CmdResponse::EXECUTION_ERROR); |
| 66 | |||
| 67 | // Respond to port requests | ||
| 68 |
2/2✓ Branch 5 taken 28 times.
✓ Branch 9 taken 28 times.
|
28 | this->reportSeqAborted(value, Fw::CmdResponse::EXECUTION_ERROR); |
| 69 | 28 | } | |
| 70 | |||
| 71 | 24 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_incrementSequenceFailure( | |
| 72 | SmId smId, | ||
| 73 | Svc_WasmSequencer_ControllerStateMachine::Signal signal) { | ||
| 74 | 24 | this->m_tlm.sequencesFailed++; | |
| 75 | 24 | } | |
| 76 | |||
| 77 | 8 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_setCancelRequested( | |
| 78 | SmId smId, | ||
| 79 | Svc_WasmSequencer_ControllerStateMachine::Signal signal) { | ||
| 80 | 8 | this->m_cancelRequested = true; | |
| 81 | 8 | } | |
| 82 | |||
| 83 | 450 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_clearCancelRequested( | |
| 84 | SmId smId, | ||
| 85 | Svc_WasmSequencer_ControllerStateMachine::Signal signal) { | ||
| 86 | 450 | this->m_cancelRequested = false; | |
| 87 | 450 | } | |
| 88 | |||
| 89 | 7 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_cancelPendingRequest( | |
| 90 | SmId smId, | ||
| 91 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 92 | const Svc::WasmSequencer_RequestContext& value) { | ||
| 93 | 7 | this->m_tlm.sequencesCancelled++; | |
| 94 |
2/2✓ Branch 5 taken 7 times.
✓ Branch 9 taken 7 times.
|
7 | this->respondToRequest(value, Fw::CmdResponse::EXECUTION_ERROR); |
| 95 |
2/2✓ Branch 5 taken 7 times.
✓ Branch 9 taken 7 times.
|
7 | this->respondToWaiting(Fw::CmdResponse::EXECUTION_ERROR); |
| 96 | |||
| 97 | // Respond to port requests | ||
| 98 |
2/2✓ Branch 5 taken 7 times.
✓ Branch 9 taken 7 times.
|
7 | this->reportSeqAborted(value, Fw::CmdResponse::EXECUTION_ERROR); |
| 99 | 7 | } | |
| 100 | |||
| 101 | 1 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respondInvoke_BUSY( | |
| 102 | SmId smId, | ||
| 103 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 104 | const Svc::WasmSequencer_InvokeRequest& value) { | ||
| 105 |
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()); |
| 106 |
2/2✓ Branch 5 taken 1 times.
✓ Branch 13 taken 1 times.
|
1 | this->respondToRequest(value.get_context(), Fw::CmdResponse::BUSY); |
| 107 | 1 | } | |
| 108 | |||
| 109 | 1 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respondInvoke_ERROR( | |
| 110 | SmId smId, | ||
| 111 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 112 | const Svc::WasmSequencer_InvokeRequest& value) { | ||
| 113 | 1 | this->log_WARNING_LO_ControllerCannotInvoke(); | |
| 114 |
2/2✓ Branch 5 taken 1 times.
✓ Branch 13 taken 1 times.
|
1 | this->respondToRequest(value.get_context(), Fw::CmdResponse::EXECUTION_ERROR); |
| 115 | 1 | } | |
| 116 | |||
| 117 | 3 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_respondLoad_BUSY( | |
| 118 | SmId smId, | ||
| 119 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 120 | const Svc::WasmSequencer_LoadRequest& value) { | ||
| 121 |
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()); |
| 122 |
2/2✓ Branch 5 taken 3 times.
✓ Branch 13 taken 3 times.
|
3 | this->respondToRequest(value.get_context(), Fw::CmdResponse::BUSY); |
| 123 | |||
| 124 | // Respond to port requests | ||
| 125 |
2/2✓ Branch 5 taken 3 times.
✓ Branch 13 taken 3 times.
|
3 | this->reportSeqAborted(value.get_context(), Fw::CmdResponse::BUSY); |
| 126 | 3 | } | |
| 127 | |||
| 128 | 110 | 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 |
2/2✓ Branch 4 taken 96 times.
✓ Branch 5 taken 14 times.
|
110 | if (value.get_block() == Svc::BlockState::BLOCK) { |
| 134 | // Respond to this request! | ||
| 135 |
2/2✓ Branch 5 taken 96 times.
✓ Branch 9 taken 96 times.
|
96 | this->respondToRequest(value, Fw::CmdResponse::OK); |
| 136 | } | ||
| 137 | |||
| 138 | // Respond to all wait requests | ||
| 139 |
2/2✓ Branch 5 taken 110 times.
✓ Branch 9 taken 110 times.
|
110 | this->respondToWaiting(Fw::CmdResponse::OK); |
| 140 | |||
| 141 | // If this concluded an active RUN, report the done to internal callers. | ||
| 142 |
2/2✓ Branch 5 taken 110 times.
✓ Branch 9 taken 110 times.
|
110 | this->reportSeqDone(value, Fw::CmdResponse::OK); |
| 143 | 110 | } | |
| 144 | |||
| 145 | 77 | 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 |
2/2✓ Branch 4 taken 62 times.
✓ Branch 5 taken 15 times.
|
77 | if (value.get_block() == Svc::BlockState::BLOCK) { |
| 151 | // Respond to this request! | ||
| 152 |
2/2✓ Branch 5 taken 62 times.
✓ Branch 9 taken 62 times.
|
62 | this->respondToRequest(value, Fw::CmdResponse::EXECUTION_ERROR); |
| 153 | } | ||
| 154 | |||
| 155 | // Respond to all wait requests | ||
| 156 |
2/2✓ Branch 5 taken 77 times.
✓ Branch 9 taken 77 times.
|
77 | this->respondToWaiting(Fw::CmdResponse::EXECUTION_ERROR); |
| 157 | |||
| 158 | // If this concluded an active RUN, report the done to internal callers. | ||
| 159 |
2/2✓ Branch 5 taken 77 times.
✓ Branch 9 taken 77 times.
|
77 | this->reportSeqDone(value, Fw::CmdResponse::EXECUTION_ERROR); |
| 160 | 77 | } | |
| 161 | |||
| 162 | 212 | bool WasmSequencer ::resolveSequencePath(const Fw::StringBase& fileName, Fw::String& filePath) { | |
| 163 | // Resolve the requested path against the SEQ_BASE_DIR parameter | ||
| 164 |
1/1✓ Branch 2 taken 212 times.
|
212 | Fw::ParamValid baseDirValid; |
| 165 |
1/1✓ Branch 3 taken 212 times.
|
212 | const Fw::ParamString baseDir = this->paramGet_SEQ_BASE_DIR(baseDirValid); |
| 166 | |||
| 167 |
3/3✓ Branch 2 taken 212 times.
✓ Branch 4 taken 207 times.
✓ Branch 5 taken 5 times.
|
212 | if (baseDir.length() == 0) { |
| 168 |
1/1✓ Branch 7 taken 207 times.
|
207 | filePath = fileName; |
| 169 | 207 | 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 |
3/3✓ Branch 1 taken 5 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 4 times.
|
5 | if (WasmSequencer::pathHasParentTraversal(fileName)) { |
| 177 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_SequenceFilePathNotContained(baseDir, fileName); |
| 178 | 1 | 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 |
1/1✓ Branch 2 taken 4 times.
|
4 | const FwSizeType baseLen = static_cast<FwSizeType>(baseDir.length()); |
| 188 |
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] == '/') ? "" : "/"; |
| 189 | |||
| 190 |
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()); |
| 191 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (fmtStatus != Fw::FormatStatus::SUCCESS) { |
| 192 | 1 | FW_ASSERT(fmtStatus == Fw::FormatStatus::OVERFLOWED, static_cast<FwAssertArgType>(fmtStatus)); | |
| 193 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_SequenceFilePathTooLong(baseDir, fileName); |
| 194 | 1 | return false; | |
| 195 | } | ||
| 196 | |||
| 197 | 3 | return true; | |
| 198 | 212 | } | |
| 199 | |||
| 200 | namespace { | ||
| 201 | struct WasmFileReader { | ||
| 202 | 204 | explicit WasmFileReader(Os::File& loadFile) : m_loadFile(loadFile) {} | |
| 203 | |||
| 204 | 402 | spacewasm_read_result_t readChunk(const U8** outBuf, std::size_t* outLen) { | |
| 205 | 402 | FwSizeType size = sizeof(this->m_readBuf); | |
| 206 |
1/1✓ Branch 7 taken 402 times.
|
402 | const Os::File::Status status = this->m_loadFile.read(this->m_readBuf, size); |
| 207 | |||
| 208 | spacewasm_read_result_t readStatus; | ||
| 209 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 402 times.
|
402 | 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 | 402 | *outBuf = this->m_readBuf; | |
| 215 | 402 | *outLen = static_cast<std::size_t>(size); | |
| 216 | |||
| 217 |
2/2✓ Branch 0 taken 198 times.
✓ Branch 1 taken 204 times.
|
402 | if (size == 0) { |
| 218 | 198 | readStatus = SPACEWASM_READ_EOF; | |
| 219 | } else { | ||
| 220 | 204 | readStatus = SPACEWASM_READ_OK; | |
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | 402 | return readStatus; | |
| 225 | } | ||
| 226 | |||
| 227 | 402 | static spacewasm_read_result_t readChunkCallback(void* userdata, const U8** outBuf, size_t* outLen) { | |
| 228 | 402 | FW_ASSERT(userdata != nullptr); | |
| 229 | 402 | 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 | 212 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_load( | |
| 241 | SmId smId, | ||
| 242 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 243 | const Svc::WasmSequencer_LoadRequest& value) { | ||
| 244 | 212 | FW_ASSERT(this->m_wasm != nullptr); | |
| 245 | 212 | FW_ASSERT(this->m_guest_allocator != nullptr); | |
| 246 | |||
| 247 |
1/1✓ Branch 10 taken 212 times.
|
212 | this->m_args = value.get_args(); |
| 248 | |||
| 249 | // Resolve the sequence file path against SEQ_BASE_DIR | ||
| 250 |
1/1✓ Branch 2 taken 212 times.
|
212 | Fw::String filePath; |
| 251 |
3/3✓ Branch 10 taken 212 times.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 210 times.
|
212 | if (!this->resolveSequencePath(value.get_fileName(), filePath)) { |
| 252 |
1/1✓ Branch 9 taken 2 times.
|
2 | this->controller_sendSignal_loadFailed(value.get_context()); |
| 253 | 2 | return; | |
| 254 | } | ||
| 255 | |||
| 256 | // Record the sequence name for telemetry (module name, or filename stem). | ||
| 257 |
1/1✓ Branch 10 taken 210 times.
|
210 | this->setSequenceName(filePath, value.get_moduleName()); |
| 258 | |||
| 259 |
1/1✓ Branch 2 taken 210 times.
|
210 | Os::File file; |
| 260 |
1/1✓ Branch 4 taken 210 times.
|
210 | const Os::File::Status openStatus = file.open(filePath.toChar(), Os::File::OPEN_READ); |
| 261 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 204 times.
|
210 | if (openStatus != Os::File::Status::OP_OK) { |
| 262 |
1/1✓ Branch 5 taken 6 times.
|
6 | this->log_WARNING_HI_FileOpenError(filePath, openStatus); |
| 263 |
1/1✓ Branch 9 taken 6 times.
|
6 | this->controller_sendSignal_loadFailed(value.get_context()); |
| 264 | 6 | return; | |
| 265 | } | ||
| 266 | |||
| 267 |
1/1✓ Branch 12 taken 204 times.
|
204 | this->m_lastLoadFileName = value.get_fileName(); |
| 268 | |||
| 269 |
1/1✓ Branch 4 taken 204 times.
|
204 | this->takeAllocatorLock(); |
| 270 | |||
| 271 | 204 | U32 moduleIndex = 0; | |
| 272 |
1/1✓ Branch 6 taken 204 times.
|
204 | Svc::WasmSequencer_RequestContext next = value.get_context(); |
| 273 | |||
| 274 | 204 | WasmFileReader reader(file); | |
| 275 | |||
| 276 | auto status = | ||
| 277 |
1/1✓ Branch 15 taken 204 times.
|
204 | spacewasm_load_module(this->m_wasm, value.get_moduleName().toChar(), &WasmFileReader::readChunkCallback, |
| 278 | 204 | &reader, this->m_guest_allocator, &moduleIndex); | |
| 279 | |||
| 280 |
1/1✓ Branch 2 taken 204 times.
|
204 | next.set_moduleIdx(static_cast<WasmSequencer_ModuleIdx>(moduleIndex)); |
| 281 | |||
| 282 |
1/1✓ Branch 4 taken 204 times.
|
204 | this->releaseAllocatorLock(); |
| 283 | |||
| 284 |
1/1✓ Branch 2 taken 204 times.
|
204 | file.close(); |
| 285 | |||
| 286 |
2/2✓ Branch 0 taken 197 times.
✓ Branch 1 taken 7 times.
|
204 | if (status == SPACEWASM_OK) { |
| 287 |
1/1✓ Branch 5 taken 197 times.
|
197 | this->controller_sendSignal_loadSucceeded(next); |
| 288 | } else { | ||
| 289 |
2/2✓ Branch 6 taken 7 times.
✓ Branch 10 taken 7 times.
|
7 | this->log_WARNING_HI_ModuleLoadFailed(WasmSequencer_Status(status)); |
| 290 |
1/1✓ Branch 9 taken 7 times.
|
7 | this->controller_sendSignal_loadFailed(value.get_context()); |
| 291 | } | ||
| 292 | 218 | } | |
| 293 | |||
| 294 | 13 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_invokeStart( | |
| 295 | SmId smId, | ||
| 296 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 297 | const Svc::WasmSequencer_RequestContext& value) { | ||
| 298 | 13 | U32 start_module_idx; | |
| 299 | 13 | U32 start_function_idx; | |
| 300 | |||
| 301 | // Get the module's start function WasmRef | ||
| 302 |
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); |
| 303 | 13 | FW_ASSERT(status == SPACEWASM_OK, status); | |
| 304 | |||
| 305 |
1/1✓ Branch 7 taken 13 times.
|
13 | this->m_invokeStatus = spacewasm_invoke(this->m_wasm, start_module_idx, start_function_idx, nullptr, 0); |
| 306 | 13 | } | |
| 307 | |||
| 308 | 144 | 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 | 144 | U32 funcIndex = 0; | |
| 314 |
1/1✓ Branch 9 taken 144 times.
|
144 | 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 | 144 | FW_ASSERT(status == SPACEWASM_OK, status); | |
| 318 | |||
| 319 | 288 | this->m_invokeStatus = | |
| 320 |
1/1✓ Branch 10 taken 144 times.
|
288 | spacewasm_invoke(this->m_wasm, static_cast<U32>(value.get_moduleIdx()), funcIndex, nullptr, 0); |
| 321 | 144 | } | |
| 322 | 3 | 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 | 3 | auto problemStatus = this->validateModuleMain(value.get_moduleIdx()); | |
| 328 |
2/2✓ Branch 6 taken 3 times.
✓ Branch 14 taken 3 times.
|
3 | this->log_WARNING_HI_InvalidModuleEntrypoint(value.get_moduleIdx(), WasmSequencer_Status(problemStatus)); |
| 329 | 3 | } | |
| 330 | |||
| 331 | 2 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleMainInvokeFailed( | |
| 332 | SmId smId, | ||
| 333 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 334 | const Svc::WasmSequencer_RequestContext& value) { | ||
| 335 |
2/2✓ Branch 10 taken 2 times.
✓ Branch 14 taken 2 times.
|
2 | this->log_WARNING_HI_ModuleMainInvokeFailed(WasmSequencer_Status(this->m_invokeStatus)); |
| 336 | 2 | } | |
| 337 | |||
| 338 | 2 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStartInvokeFailed( | |
| 339 | SmId smId, | ||
| 340 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 341 | const Svc::WasmSequencer_RequestContext& value) { | ||
| 342 |
2/2✓ Branch 10 taken 2 times.
✓ Branch 14 taken 2 times.
|
2 | this->log_WARNING_HI_ModuleStartInvokeFailed(WasmSequencer_Status(this->m_invokeStatus)); |
| 343 | 2 | } | |
| 344 | |||
| 345 | 142 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStarted( | |
| 346 | SmId smId, | ||
| 347 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 348 | const Svc::WasmSequencer_RequestContext& value) { | ||
| 349 | 142 | this->log_ACTIVITY_HI_SequenceStarting(value.get_moduleIdx()); | |
| 350 |
6/6✓ Branch 4 taken 11 times.
✓ Branch 5 taken 131 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 134 times.
✓ Branch 9 taken 8 times.
|
153 | if (value.get_source() == Svc::WasmSequencer_SignalSource::COMMAND_RUN || |
| 351 | 11 | value.get_source() == Svc::WasmSequencer_SignalSource::PORT_RUN) { | |
| 352 |
2/2✓ Branch 5 taken 133 times.
✓ Branch 6 taken 1 times.
|
134 | if (this->isConnected_seqStartOut_OutputPort(0)) { |
| 353 | 133 | this->seqStartOut_out(0, this->m_lastLoadFileName, this->m_args); | |
| 354 | } | ||
| 355 | } | ||
| 356 | 142 | } | |
| 357 | |||
| 358 | 341 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_resetStore( | |
| 359 | SmId smId, | ||
| 360 | Svc_WasmSequencer_ControllerStateMachine::Signal signal) { | ||
| 361 |
2/2✓ Branch 4 taken 224 times.
✓ Branch 5 taken 117 times.
|
341 | if (this->m_wasm == nullptr) { |
| 362 | // The store has not been created yet. | ||
| 363 | // This should be the initial transition | ||
| 364 | 224 | 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 | 117 | this->destroyStore(); | |
| 370 | 117 | this->createStore(); | |
| 371 | } | ||
| 372 | 341 | } | |
| 373 | |||
| 374 | 153 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_runEngine( | |
| 375 | SmId smId, | ||
| 376 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 377 | const Svc::WasmSequencer_RequestContext& value) { | ||
| 378 | 153 | this->interpreter_sendSignal_run(value); | |
| 379 | 153 | } | |
| 380 | |||
| 381 | 64 | void WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_action_reportModuleSucceeded( | |
| 382 | SmId smId, | ||
| 383 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 384 | const Svc::WasmSequencer_RequestContext& value) { | ||
| 385 | 64 | this->m_tlm.sequencesSucceeded++; | |
| 386 | 64 | this->log_ACTIVITY_HI_SequenceSucceeded(value.get_moduleIdx()); | |
| 387 | 64 | } | |
| 388 | |||
| 389 | 4 | 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 |
2/2✓ Branch 5 taken 4 times.
✓ Branch 12 taken 4 times.
|
4 | this->reportSequenceRuntimeFailure(value.get_moduleIdx(), WasmSequencer_SequencePhase::START); |
| 396 | 4 | } | |
| 397 | |||
| 398 | 77 | 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 |
2/2✓ Branch 5 taken 77 times.
✓ Branch 12 taken 77 times.
|
77 | this->reportSequenceRuntimeFailure(value.get_moduleIdx(), WasmSequencer_SequencePhase::MAIN); |
| 404 | 77 | } | |
| 405 | |||
| 406 | 81 | void WasmSequencer ::reportSequenceRuntimeFailure(WasmSequencer_ModuleIdx moduleIdx, | |
| 407 | WasmSequencer_SequencePhase phase) { | ||
| 408 |
5/5✓ Branch 6 taken 15 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 35 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 27 times.
|
81 | switch (this->m_exit.reason) { |
| 409 | 15 | case WasmSequencer_ExitReason::CANCEL: | |
| 410 | 15 | this->m_tlm.sequencesCancelled++; | |
| 411 | 15 | this->log_ACTIVITY_HI_SequenceCancelled(moduleIdx, phase); | |
| 412 | 15 | break; | |
| 413 | 2 | case WasmSequencer_ExitReason::HOST_PANIC: | |
| 414 | 2 | this->m_tlm.sequencesFailed++; | |
| 415 | 2 | this->log_WARNING_HI_SequencePanic(moduleIdx, phase, this->m_exit.code); | |
| 416 | 2 | break; | |
| 417 | 35 | case WasmSequencer_ExitReason::INTERPRETER_TRAP: | |
| 418 | 35 | this->m_tlm.sequencesFailed++; | |
| 419 | 35 | this->log_WARNING_HI_SequenceTrapped(moduleIdx, phase, this->m_exit.lastTrapReason); | |
| 420 | 35 | break; | |
| 421 | 2 | 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 | 2 | this->m_tlm.sequencesFailed++; | |
| 426 | 2 | this->log_WARNING_HI_SequenceExited(moduleIdx, phase, this->m_exit.code); | |
| 427 | 2 | break; | |
| 428 | 27 | 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 | 27 | this->m_tlm.sequencesFailed++; | |
| 435 | 54 | this->log_WARNING_HI_SequenceHostFailure(moduleIdx, phase, this->m_exit.reason, | |
| 436 | 27 | this->m_exit.lastHostFunction); | |
| 437 | 27 | break; | |
| 438 | } | ||
| 439 | 81 | } | |
| 440 | |||
| 441 | // ---------------------------------------------------------------------- | ||
| 442 | // Implementations for internal state machine guards | ||
| 443 | // ---------------------------------------------------------------------- | ||
| 444 | |||
| 445 | 190 | bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_moduleHasStart( | |
| 446 | SmId smId, | ||
| 447 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 448 | const Svc::WasmSequencer_RequestContext& value) const { | ||
| 449 | 190 | U32 start_module_idx; | |
| 450 | 190 | U32 start_function_idx; | |
| 451 |
1/1✓ Branch 9 taken 190 times.
|
190 | auto status = spacewasm_module_start(this->m_wasm, static_cast<U32>(value.get_moduleIdx()), &start_module_idx, |
| 452 | &start_function_idx); | ||
| 453 | |||
| 454 |
2/3✓ Branch 0 taken 13 times.
✓ Branch 1 taken 177 times.
✗ Branch 2 not taken.
|
190 | switch (status) { |
| 455 | 13 | case SPACEWASM_OK: | |
| 456 | 13 | return true; | |
| 457 | 177 | case SPACEWASM_ERR_NOT_FOUND: | |
| 458 | 177 | 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 | 153 | bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_moduleHasValidMain( | |
| 467 | SmId smId, | ||
| 468 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 469 | const Svc::WasmSequencer_RequestContext& value) const { | ||
| 470 | 153 | return this->validateModuleMain(value.get_moduleIdx()) == SPACEWASM_OK; | |
| 471 | } | ||
| 472 | |||
| 473 | 157 | bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_invokeSucceeded( | |
| 474 | SmId smId, | ||
| 475 | Svc_WasmSequencer_ControllerStateMachine::Signal signal, | ||
| 476 | const Svc::WasmSequencer_RequestContext& value) const { | ||
| 477 | 157 | return this->m_invokeStatus == SPACEWASM_OK; | |
| 478 | } | ||
| 479 | |||
| 480 | 152 | 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 |
2/2✓ Branch 11 taken 73 times.
✓ Branch 12 taken 79 times.
|
152 | switch (this->m_exit.reason) { |
| 488 | 73 | case WasmSequencer_ExitReason::INTERPRETER_FINISHED: | |
| 489 | case WasmSequencer_ExitReason::HOST_EXIT: | ||
| 490 | 73 | return this->m_exit.code == 0; | |
| 491 | 79 | default: | |
| 492 | 79 | return false; | |
| 493 | } | ||
| 494 | } | ||
| 495 | |||
| 496 | 209 | bool WasmSequencer ::Svc_WasmSequencer_ControllerStateMachine_guard_cancelRequested( | |
| 497 | SmId smId, | ||
| 498 | Svc_WasmSequencer_ControllerStateMachine::Signal signal) const { | ||
| 499 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 209 times.
|
209 | return this->m_cancelRequested; |
| 500 | } | ||
| 501 | |||
| 502 | } // namespace Svc | ||
| 503 |