...
1 package wasm
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7
8 "github.com/tetratelabs/wazero/api"
9 "github.com/tetratelabs/wazero/sys"
10 )
11
12
13 func (m *ModuleInstance) FailIfClosed() (err error) {
14 if closed := m.Closed.Load(); closed != 0 {
15 switch closed & exitCodeFlagMask {
16 case exitCodeFlagResourceClosed:
17 case exitCodeFlagResourceNotClosed:
18
19
20 _ = m.ensureResourcesClosed(context.Background())
21 }
22 return sys.NewExitError(uint32(closed >> 32))
23 }
24 return nil
25 }
26
27
28
29
30
31
32 func (m *ModuleInstance) CloseModuleOnCanceledOrTimeout(ctx context.Context) context.CancelFunc {
33
34
35
36
37
38 cancelChan := make(chan struct{})
39 go m.closeModuleOnCanceledOrTimeout(ctx, cancelChan)
40 return func() { close(cancelChan) }
41 }
42
43
44 func (m *ModuleInstance) closeModuleOnCanceledOrTimeout(ctx context.Context, cancelChan <-chan struct{}) {
45 select {
46 case <-ctx.Done():
47 select {
48 case <-cancelChan:
49
50
51
52
53 default:
54
55
56 switch {
57 case errors.Is(ctx.Err(), context.Canceled):
58
59 _ = m.closeWithExitCodeWithoutClosingResource(sys.ExitCodeContextCanceled)
60 case errors.Is(ctx.Err(), context.DeadlineExceeded):
61
62 _ = m.closeWithExitCodeWithoutClosingResource(sys.ExitCodeDeadlineExceeded)
63 }
64 }
65 case <-cancelChan:
66 }
67 }
68
69
70
71
72
73 func (m *ModuleInstance) CloseWithCtxErr(ctx context.Context) {
74 switch {
75 case errors.Is(ctx.Err(), context.Canceled):
76
77 _ = m.CloseWithExitCode(ctx, sys.ExitCodeContextCanceled)
78 case errors.Is(ctx.Err(), context.DeadlineExceeded):
79
80 _ = m.CloseWithExitCode(ctx, sys.ExitCodeDeadlineExceeded)
81 }
82 }
83
84
85 func (m *ModuleInstance) Name() string {
86 return m.ModuleName
87 }
88
89
90 func (m *ModuleInstance) String() string {
91 return fmt.Sprintf("Module[%s]", m.Name())
92 }
93
94
95 func (m *ModuleInstance) Close(ctx context.Context) (err error) {
96 return m.CloseWithExitCode(ctx, 0)
97 }
98
99
100 func (m *ModuleInstance) CloseWithExitCode(ctx context.Context, exitCode uint32) (err error) {
101 if !m.setExitCode(exitCode, exitCodeFlagResourceClosed) {
102 return nil
103 }
104 _ = m.s.deleteModule(m)
105 return m.ensureResourcesClosed(ctx)
106 }
107
108
109 func (m *ModuleInstance) IsClosed() bool {
110 return m.Closed.Load() != 0
111 }
112
113 func (m *ModuleInstance) closeWithExitCodeWithoutClosingResource(exitCode uint32) (err error) {
114 if !m.setExitCode(exitCode, exitCodeFlagResourceNotClosed) {
115 return nil
116 }
117 _ = m.s.deleteModule(m)
118 return nil
119 }
120
121
122 func (m *ModuleInstance) closeWithExitCode(ctx context.Context, exitCode uint32) (err error) {
123 if !m.setExitCode(exitCode, exitCodeFlagResourceClosed) {
124 return nil
125 }
126 return m.ensureResourcesClosed(ctx)
127 }
128
129 type exitCodeFlag = uint64
130
131 const exitCodeFlagMask = 0xff
132
133 const (
134
135 exitCodeFlagResourceClosed = 1 << iota
136
137 exitCodeFlagResourceNotClosed
138 )
139
140 func (m *ModuleInstance) setExitCode(exitCode uint32, flag exitCodeFlag) bool {
141 closed := flag | uint64(exitCode)<<32
142 return m.Closed.CompareAndSwap(0, closed)
143 }
144
145
146
147 func (m *ModuleInstance) ensureResourcesClosed(ctx context.Context) (err error) {
148 if closeNotifier := m.CloseNotifier; closeNotifier != nil {
149 closeNotifier.CloseNotify(ctx, uint32(m.Closed.Load()>>32))
150 m.CloseNotifier = nil
151 }
152
153 if sysCtx := m.Sys; sysCtx != nil {
154 if err = sysCtx.FS().Close(); err != nil {
155 return err
156 }
157 m.Sys = nil
158 }
159
160 if m.CodeCloser == nil {
161 return
162 }
163 if e := m.CodeCloser.Close(ctx); e != nil && err == nil {
164 err = e
165 }
166 m.CodeCloser = nil
167 return
168 }
169
170
171 func (m *ModuleInstance) Memory() api.Memory {
172 return m.MemoryInstance
173 }
174
175
176 func (m *ModuleInstance) ExportedMemory(name string) api.Memory {
177 _, err := m.getExport(name, ExternTypeMemory)
178 if err != nil {
179 return nil
180 }
181
182 return m.MemoryInstance
183 }
184
185
186
187 func (m *ModuleInstance) ExportedMemoryDefinitions() map[string]api.MemoryDefinition {
188
189 if mem := m.MemoryInstance; mem != nil {
190
191 for name, exp := range m.Exports {
192 if exp.Type == ExternTypeMemory {
193 return map[string]api.MemoryDefinition{name: mem.definition}
194 }
195 }
196 }
197 return map[string]api.MemoryDefinition{}
198 }
199
200
201 func (m *ModuleInstance) ExportedFunction(name string) api.Function {
202 exp, err := m.getExport(name, ExternTypeFunc)
203 if err != nil {
204 return nil
205 }
206 return m.Engine.NewFunction(exp.Index)
207 }
208
209
210
211 func (m *ModuleInstance) ExportedFunctionDefinitions() map[string]api.FunctionDefinition {
212 result := map[string]api.FunctionDefinition{}
213 for name, exp := range m.Exports {
214 if exp.Type == ExternTypeFunc {
215 result[name] = m.Source.FunctionDefinition(exp.Index)
216 }
217 }
218 return result
219 }
220
221
222 func (m *ModuleInstance) GlobalVal(idx Index) uint64 {
223 return m.Globals[idx].Val
224 }
225
226
227 func (m *ModuleInstance) ExportedGlobal(name string) api.Global {
228 exp, err := m.getExport(name, ExternTypeGlobal)
229 if err != nil {
230 return nil
231 }
232 g := m.Globals[exp.Index]
233 if g.Type.Mutable {
234 return mutableGlobal{g: g}
235 }
236 return constantGlobal{g: g}
237 }
238
239
240 func (m *ModuleInstance) NumGlobal() int {
241 return len(m.Globals)
242 }
243
244
245 func (m *ModuleInstance) Global(idx int) api.Global {
246 return constantGlobal{g: m.Globals[idx]}
247 }
248
View as plain text