package wasm
import (
"context"
"errors"
"fmt"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/sys"
)
func (m *ModuleInstance ) FailIfClosed () (err error ) {
if closed := m .Closed .Load (); closed != 0 {
switch closed & exitCodeFlagMask {
case exitCodeFlagResourceClosed :
case exitCodeFlagResourceNotClosed :
_ = m .ensureResourcesClosed (context .Background ())
}
return sys .NewExitError (uint32 (closed >> 32 ))
}
return nil
}
func (m *ModuleInstance ) CloseModuleOnCanceledOrTimeout (ctx context .Context ) context .CancelFunc {
cancelChan := make (chan struct {})
go m .closeModuleOnCanceledOrTimeout (ctx , cancelChan )
return func () { close (cancelChan ) }
}
func (m *ModuleInstance ) closeModuleOnCanceledOrTimeout (ctx context .Context , cancelChan <-chan struct {}) {
select {
case <- ctx .Done ():
select {
case <- cancelChan :
default :
switch {
case errors .Is (ctx .Err (), context .Canceled ):
_ = m .closeWithExitCodeWithoutClosingResource (sys .ExitCodeContextCanceled )
case errors .Is (ctx .Err (), context .DeadlineExceeded ):
_ = m .closeWithExitCodeWithoutClosingResource (sys .ExitCodeDeadlineExceeded )
}
}
case <- cancelChan :
}
}
func (m *ModuleInstance ) CloseWithCtxErr (ctx context .Context ) {
switch {
case errors .Is (ctx .Err (), context .Canceled ):
_ = m .CloseWithExitCode (ctx , sys .ExitCodeContextCanceled )
case errors .Is (ctx .Err (), context .DeadlineExceeded ):
_ = m .CloseWithExitCode (ctx , sys .ExitCodeDeadlineExceeded )
}
}
func (m *ModuleInstance ) Name () string {
return m .ModuleName
}
func (m *ModuleInstance ) String () string {
return fmt .Sprintf ("Module[%s]" , m .Name ())
}
func (m *ModuleInstance ) Close (ctx context .Context ) (err error ) {
return m .CloseWithExitCode (ctx , 0 )
}
func (m *ModuleInstance ) CloseWithExitCode (ctx context .Context , exitCode uint32 ) (err error ) {
if !m .setExitCode (exitCode , exitCodeFlagResourceClosed ) {
return nil
}
_ = m .s .deleteModule (m )
return m .ensureResourcesClosed (ctx )
}
func (m *ModuleInstance ) IsClosed () bool {
return m .Closed .Load () != 0
}
func (m *ModuleInstance ) closeWithExitCodeWithoutClosingResource (exitCode uint32 ) (err error ) {
if !m .setExitCode (exitCode , exitCodeFlagResourceNotClosed ) {
return nil
}
_ = m .s .deleteModule (m )
return nil
}
func (m *ModuleInstance ) closeWithExitCode (ctx context .Context , exitCode uint32 ) (err error ) {
if !m .setExitCode (exitCode , exitCodeFlagResourceClosed ) {
return nil
}
return m .ensureResourcesClosed (ctx )
}
type exitCodeFlag = uint64
const exitCodeFlagMask = 0xff
const (
exitCodeFlagResourceClosed = 1 << iota
exitCodeFlagResourceNotClosed
)
func (m *ModuleInstance ) setExitCode (exitCode uint32 , flag exitCodeFlag ) bool {
closed := flag | uint64 (exitCode )<<32
return m .Closed .CompareAndSwap (0 , closed )
}
func (m *ModuleInstance ) ensureResourcesClosed (ctx context .Context ) (err error ) {
if closeNotifier := m .CloseNotifier ; closeNotifier != nil {
closeNotifier .CloseNotify (ctx , uint32 (m .Closed .Load ()>>32 ))
m .CloseNotifier = nil
}
if sysCtx := m .Sys ; sysCtx != nil {
err = sysCtx .FS ().Close ()
m .Sys = nil
}
if mem := m .MemoryInstance ; mem != nil {
if mem .expBuffer != nil {
mem .expBuffer .Free ()
mem .expBuffer = nil
}
}
if m .CodeCloser != nil {
if e := m .CodeCloser .Close (ctx ); err == nil {
err = e
}
m .CodeCloser = nil
}
return err
}
func (m *ModuleInstance ) Memory () api .Memory {
return m .MemoryInstance
}
func (m *ModuleInstance ) ExportedMemory (name string ) api .Memory {
_ , err := m .getExport (name , ExternTypeMemory )
if err != nil {
return nil
}
return m .MemoryInstance
}
func (m *ModuleInstance ) ExportedMemoryDefinitions () map [string ]api .MemoryDefinition {
if mem := m .MemoryInstance ; mem != nil {
for name , exp := range m .Exports {
if exp .Type == ExternTypeMemory {
return map [string ]api .MemoryDefinition {name : mem .definition }
}
}
}
return map [string ]api .MemoryDefinition {}
}
func (m *ModuleInstance ) ExportedFunction (name string ) api .Function {
exp , err := m .getExport (name , ExternTypeFunc )
if err != nil {
return nil
}
return m .Engine .NewFunction (exp .Index )
}
func (m *ModuleInstance ) ExportedFunctionDefinitions () map [string ]api .FunctionDefinition {
result := map [string ]api .FunctionDefinition {}
for name , exp := range m .Exports {
if exp .Type == ExternTypeFunc {
result [name ] = m .Source .FunctionDefinition (exp .Index )
}
}
return result
}
func (m *ModuleInstance ) GlobalVal (idx Index ) uint64 {
return m .Globals [idx ].Val
}
func (m *ModuleInstance ) ExportedGlobal (name string ) api .Global {
exp , err := m .getExport (name , ExternTypeGlobal )
if err != nil {
return nil
}
g := m .Globals [exp .Index ]
if g .Type .Mutable {
return mutableGlobal {g : g }
}
return constantGlobal {g : g }
}
func (m *ModuleInstance ) NumGlobal () int {
return len (m .Globals )
}
func (m *ModuleInstance ) Global (idx int ) api .Global {
return constantGlobal {g : m .Globals [idx ]}
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .