/src/WasmEdge/include/runtime/storemgr.h
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | //===-- wasmedge/runtime/storemgr.h - Store Manager definition ------------===// |
5 | | // |
6 | | // Part of the WasmEdge Project. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | /// |
10 | | /// \file |
11 | | /// This file contains the definition of Store Manager. |
12 | | /// |
13 | | //===----------------------------------------------------------------------===// |
14 | | #pragma once |
15 | | |
16 | | #include "runtime/instance/component/component.h" |
17 | | #include "runtime/instance/module.h" |
18 | | |
19 | | #include <mutex> |
20 | | #include <shared_mutex> |
21 | | #include <vector> |
22 | | |
23 | | namespace WasmEdge { |
24 | | |
25 | | namespace Executor { |
26 | | class Executor; |
27 | | } |
28 | | |
29 | | namespace Runtime { |
30 | | |
31 | | class StoreManager { |
32 | | public: |
33 | 0 | StoreManager() = default; |
34 | 0 | ~StoreManager() { |
35 | | // When destroying this store manager, unlink all the registered module |
36 | | // instances. |
37 | 0 | reset(); |
38 | 0 | } |
39 | | |
40 | | /// Get the length of the list of registered modules. |
41 | 0 | uint32_t getModuleListSize() const noexcept { |
42 | 0 | std::shared_lock Lock(Mutex); |
43 | 0 | return static_cast<uint32_t>(NamedMod.size()); |
44 | 0 | } |
45 | | |
46 | | /// Get list of registered modules. |
47 | 0 | template <typename CallbackT> auto getModuleList(CallbackT &&CallBack) const { |
48 | 0 | std::shared_lock Lock(Mutex); |
49 | 0 | return std::forward<CallbackT>(CallBack)(NamedMod); |
50 | 0 | } Unexecuted instantiation: auto WasmEdge::Runtime::StoreManager::getModuleList<WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}>(WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}) constUnexecuted instantiation: wasmedge.cpp:auto WasmEdge::Runtime::StoreManager::getModuleList<WasmEdge_StoreListModule::$_0>(WasmEdge_StoreListModule::$_0&&) const Unexecuted instantiation: wasmedge.cpp:auto WasmEdge::Runtime::StoreManager::getModuleList<WasmEdge_VMListRegisteredModule::$_0>(WasmEdge_VMListRegisteredModule::$_0&&) const Unexecuted instantiation: module.cpp:auto WasmEdge::Runtime::StoreManager::getModuleList<WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}>(WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}) const |
51 | | |
52 | | /// Run Callback with the named module instance (or nullptr) while holding the |
53 | | /// shared lock, so the caller can pin a dependency before a concurrent |
54 | | /// unregisterModule destroys it. |
55 | | template <typename CallbackT> |
56 | 0 | auto withModuleLocked(std::string_view Name, CallbackT &&Callback) const { |
57 | 0 | return getModuleList([&](const auto &Mods) { |
58 | 0 | const Instance::ModuleInstance *Found = nullptr; |
59 | 0 | if (auto Iter = Mods.find(Name); likely(Iter != Mods.cend())) { |
60 | 0 | Found = Iter->second; |
61 | 0 | } |
62 | 0 | return std::forward<CallbackT>(Callback)(Found); |
63 | 0 | }); Unexecuted instantiation: auto WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}::operator()<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, WasmEdge::Runtime::Instance::ModuleInstance const*, std::__1::less<void>, std::__1::map<std::__1::pair<std::__1::allocator const, WasmEdge::Runtime::Instance::ModuleInstance const*> > > >(WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const) constUnexecuted instantiation: module.cpp:auto WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const::{lambda(WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const&)#1}::operator()<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, WasmEdge::Runtime::Instance::ModuleInstance const*, std::__1::less<void>, std::__1::map<std::__1::pair<std::__1::allocator const, WasmEdge::Runtime::Instance::ModuleInstance const*> > > >(WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1} const) const |
64 | 0 | } Unexecuted instantiation: auto WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Runtime::StoreManager::findModule(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) constUnexecuted instantiation: module.cpp:auto WasmEdge::Runtime::StoreManager::withModuleLocked<WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, WasmEdge::Executor::Executor::instantiate(WasmEdge::Runtime::StoreManager&, WasmEdge::AST::Module const&, std::__1::optional<std::__1::basic_string_view<char, std::__1::char_traits<char> > >)::$_0::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const::{lambda(WasmEdge::Runtime::Instance::ModuleInstance const*)#1}&&) const |
65 | | |
66 | | /// Find module by name. Returns the pointer with the lock already released; |
67 | | /// use withModuleLocked to pin or dereference the result race-free. |
68 | 0 | const Instance::ModuleInstance *findModule(std::string_view Name) const { |
69 | 0 | return withModuleLocked( |
70 | 0 | Name, [](const Instance::ModuleInstance *Found) { return Found; }); |
71 | 0 | } |
72 | | |
73 | | /// Find component by name. |
74 | | const Instance::ComponentInstance * |
75 | 0 | findComponent(std::string_view Name) const { |
76 | 0 | std::shared_lock Lock(Mutex); |
77 | 0 | if (auto Iter = NamedComp.find(Name); likely(Iter != NamedComp.cend())) { |
78 | 0 | return Iter->second; |
79 | 0 | } |
80 | 0 | return nullptr; |
81 | 0 | } |
82 | | |
83 | | /// Reset this store manager and unlink all the registered module instances. |
84 | 0 | void reset() noexcept { |
85 | 0 | std::unique_lock Lock(Mutex); |
86 | 0 | for (auto &&[Name, ModInst] : NamedMod) { |
87 | 0 | (const_cast<Instance::ModuleInstance *>(ModInst)) |
88 | 0 | ->unlinkStore(this, Name); |
89 | 0 | } |
90 | 0 | NamedMod.clear(); |
91 | 0 | NamedComp.clear(); |
92 | 0 | } |
93 | | |
94 | | /// Register a named module in this store. |
95 | 0 | Expect<void> registerModule(const Instance::ModuleInstance *ModInst) { |
96 | 0 | return registerModule(ModInst, ModInst->getModuleName()); |
97 | 0 | } |
98 | | |
99 | | /// Register a module instance in this store under the given alias name. |
100 | | Expect<void> registerModule(const Instance::ModuleInstance *ModInst, |
101 | 0 | std::string_view Name) { |
102 | 0 | std::unique_lock Lock(Mutex); |
103 | 0 | auto Iter = NamedMod.find(Name); |
104 | 0 | if (likely(Iter != NamedMod.cend())) { |
105 | 0 | return Unexpect(ErrCode::Value::ModuleNameConflict); |
106 | 0 | } |
107 | 0 | NamedMod.emplace(std::string(Name), ModInst); |
108 | | // Link the module instance to this store manager. |
109 | 0 | (const_cast<Instance::ModuleInstance *>(ModInst)) |
110 | 0 | ->linkStore(this, Name, |
111 | 0 | [](const Instance::ModuleInstance::LinkedStoreKey &Key, |
112 | 0 | const Instance::ModuleInstance *) { |
113 | | // The unlink callback: erase the alias name from the |
114 | | // store. |
115 | 0 | std::unique_lock CallbackLock(Key.first->Mutex); |
116 | 0 | (Key.first->NamedMod).erase(Key.second); |
117 | 0 | }); |
118 | 0 | return {}; |
119 | 0 | } |
120 | | |
121 | | /// Unregister a named module from this store. |
122 | 0 | Expect<void> unregisterModule(std::string_view Name) { |
123 | 0 | std::unique_lock Lock(Mutex); |
124 | 0 | auto Iter = NamedMod.find(Name); |
125 | 0 | if (Iter == NamedMod.cend()) { |
126 | 0 | return Unexpect(ErrCode::Value::UnknownImport); |
127 | 0 | } |
128 | 0 | (const_cast<Instance::ModuleInstance *>(Iter->second)) |
129 | 0 | ->unlinkStore(this, Name); |
130 | 0 | NamedMod.erase(Iter); |
131 | 0 | return {}; |
132 | 0 | } |
133 | | |
134 | | /// Register a named component in this store. |
135 | 0 | Expect<void> registerComponent(const Instance::ComponentInstance *CompInst) { |
136 | 0 | std::unique_lock Lock(Mutex); |
137 | 0 | auto Iter = NamedComp.find(CompInst->getComponentName()); |
138 | 0 | if (likely(Iter != NamedComp.cend())) { |
139 | 0 | return Unexpect(ErrCode::Value::ModuleNameConflict); |
140 | 0 | } |
141 | 0 | NamedComp.emplace(CompInst->getComponentName(), CompInst); |
142 | 0 | return {}; |
143 | 0 | } |
144 | | |
145 | | private: |
146 | | friend class Executor::Executor; |
147 | | |
148 | | /// \name Mutex for thread-safe. |
149 | | mutable std::shared_mutex Mutex; |
150 | | |
151 | | /// Collect the instantiation failed module. |
152 | 0 | void recycleModule(std::unique_ptr<Instance::ModuleInstance> &&Mod) { |
153 | 0 | if (FailedMod) { |
154 | 0 | auto *OldMod = FailedMod.release(); |
155 | 0 | if (OldMod) { |
156 | 0 | OldMod->terminate(); |
157 | 0 | } |
158 | 0 | } |
159 | 0 | FailedMod = std::move(Mod); |
160 | 0 | } |
161 | | |
162 | | /// \name Module name mapping. |
163 | | std::map<std::string, const Instance::ModuleInstance *, std::less<>> NamedMod; |
164 | | /// \name Component name mapping. |
165 | | std::map<std::string, const Instance::ComponentInstance *, std::less<>> |
166 | | NamedComp; |
167 | | |
168 | | /// \name Last instantiation failed module. |
169 | | /// According to the current spec, instances should remain referenceable even |
170 | | /// if instantiation failed. Therefore, store the failed module instance here |
171 | | /// to keep the instances alive. |
172 | | /// FIXME: Is this necessary to be a vector? |
173 | | std::unique_ptr<Instance::ModuleInstance> FailedMod; |
174 | | }; |
175 | | |
176 | | } // namespace Runtime |
177 | | } // namespace WasmEdge |