/src/WasmEdge/lib/executor/engine/threadInstr.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | #include "executor/executor.h" |
5 | | |
6 | | namespace WasmEdge { |
7 | | namespace Executor { |
8 | | |
9 | | Expect<void> |
10 | | Executor::runAtomicNotifyOp(Runtime::StackManager &StackMgr, |
11 | | Runtime::Instance::MemoryInstance &MemInst, |
12 | 0 | const AST::Instruction &Instr) { |
13 | 0 | ValVariant RawCount = StackMgr.pop(); |
14 | 0 | ValVariant &RawAddress = StackMgr.getTop(); |
15 | 0 | const auto AddrType = MemInst.getMemoryType().getLimit().getAddrType(); |
16 | 0 | uint64_t Address = extractAddr(RawAddress, AddrType); |
17 | 0 | EXPECTED_TRY(checkOffsetOverflow(MemInst, Instr, Address, sizeof(uint32_t))); |
18 | 0 | Address += Instr.getMemoryOffset(); |
19 | 0 | uint32_t Align = |
20 | 0 | AddrType == AddressType::I32 ? sizeof(uint32_t) : sizeof(uint64_t); |
21 | |
|
22 | 0 | if (Address % Align != 0) { |
23 | 0 | spdlog::error(ErrCode::Value::UnalignedAtomicAccess); |
24 | 0 | spdlog::error( |
25 | 0 | ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); |
26 | 0 | return Unexpect(ErrCode::Value::UnalignedAtomicAccess); |
27 | 0 | } |
28 | | |
29 | 0 | uint64_t Count = extractAddr(RawCount, AddrType); |
30 | 0 | EXPECTED_TRY( |
31 | 0 | auto Total, |
32 | 0 | atomicNotify(MemInst, Address, Count).map_error([&Instr](auto E) { |
33 | 0 | spdlog::error(E); |
34 | 0 | spdlog::error( |
35 | 0 | ErrInfo::InfoInstruction(Instr.getOpCode(), Instr.getOffset())); |
36 | 0 | return E; |
37 | 0 | })); |
38 | 0 | RawAddress = emplaceAddr(Total, AddrType); |
39 | 0 | return {}; |
40 | 0 | } |
41 | | |
42 | 0 | Expect<void> Executor::runMemoryFenceOp() { |
43 | 0 | std::atomic_thread_fence(std::memory_order_release); |
44 | 0 | return {}; |
45 | 0 | } |
46 | | |
47 | | Expect<uint64_t> |
48 | | Executor::atomicNotify(Runtime::Instance::MemoryInstance &MemInst, |
49 | 0 | uint64_t Address, uint64_t Count) noexcept { |
50 | | // The error message should be handled by the caller, or the AOT mode will |
51 | | // produce the duplicated messages. |
52 | 0 | if (auto *AtomicObj = MemInst.getPointer<std::atomic<uint64_t> *>(Address); |
53 | 0 | !AtomicObj) { |
54 | 0 | return Unexpect(ErrCode::Value::MemoryOutOfBounds); |
55 | 0 | } |
56 | | |
57 | 0 | auto &WaiterMapMtx = MemInst.getWaiterMapMutex(); |
58 | 0 | auto &WaiterMap = MemInst.getWaiterMap(); |
59 | 0 | std::unique_lock<std::mutex> Locker(WaiterMapMtx); |
60 | 0 | uint64_t Total = 0; |
61 | 0 | auto Range = WaiterMap.equal_range(Address); |
62 | 0 | for (auto Iterator = Range.first; Total < Count && Iterator != Range.second; |
63 | 0 | ++Iterator) { |
64 | 0 | { |
65 | 0 | std::unique_lock<std::mutex> WaiterLocker(Iterator->second.Mutex); |
66 | 0 | Iterator->second.Notified = true; |
67 | 0 | } |
68 | 0 | Iterator->second.Cond.notify_all(); |
69 | 0 | ++Total; |
70 | 0 | } |
71 | 0 | return Total; |
72 | 0 | } |
73 | | |
74 | 0 | void Executor::atomicNotifyAll() noexcept { |
75 | 0 | if (auto *MemInst = WaitingMemory.load(std::memory_order_acquire)) { |
76 | 0 | MemInst->notifyAllWaiters(); |
77 | 0 | } |
78 | 0 | } |
79 | | |
80 | | } // namespace Executor |
81 | | } // namespace WasmEdge |