wasi: Implements wasi_snapshot_preview1.poll_oneoff for relative clock events (#629)
This implements wasi_snapshot_preview1.poll_oneoff for relative clock events, and in doing so stubs `Nanosleep` which defaults to noop, but can be configured to `time.Sleep`. Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
30
RATIONALE.md
30
RATIONALE.md
@@ -417,7 +417,7 @@ is to satisfy WASI:
|
||||
|
||||
See https://github.com/WebAssembly/wasi-clocks
|
||||
|
||||
## Why default to fake time?
|
||||
### Why default to fake time?
|
||||
|
||||
WebAssembly has an implicit design pattern of capabilities based security. By
|
||||
defaulting to a fake time, we reduce the chance of timing attacks, at the cost
|
||||
@@ -425,7 +425,7 @@ of requiring configuration to opt-into real clocks.
|
||||
|
||||
See https://gruss.cc/files/fantastictimers.pdf for an example attacks.
|
||||
|
||||
## Why does fake time increase on reading?
|
||||
### Why does fake time increase on reading?
|
||||
|
||||
Both the fake nanotime and walltime increase by 1ms on reading. Particularly in
|
||||
the case of nanotime, this prevents spinning. For example, when Go compiles
|
||||
@@ -433,7 +433,7 @@ the case of nanotime, this prevents spinning. For example, when Go compiles
|
||||
never increases, the gouroutine is mistaken for being busy. This would be worse
|
||||
if a compiler implement sleep using nanotime, yet doesn't check for spinning!
|
||||
|
||||
## Why not `time.Clock`?
|
||||
### Why not `time.Clock`?
|
||||
|
||||
wazero can't use `time.Clock` as a plugin for clock implementation as it is
|
||||
only substitutable with build flags (`faketime`) and conflates wall and
|
||||
@@ -473,6 +473,30 @@ to a POSIX method.
|
||||
Writing assembly would allow making syscalls without CGO, but comes with the cost that it will require implementations
|
||||
across many combinations of OS and architecture.
|
||||
|
||||
## sys.Nanosleep
|
||||
|
||||
All major programming languages have a `sleep` mechanism to block for a
|
||||
duration. Sleep is typically implemented by a WASI `poll_oneoff` relative clock
|
||||
subscription.
|
||||
|
||||
For example, the below ends up calling `wasi_snapshot_preview1.poll_oneoff`:
|
||||
|
||||
```zig
|
||||
const std = @import("std");
|
||||
pub fn main() !void {
|
||||
std.time.sleep(std.time.ns_per_s * 5);
|
||||
}
|
||||
```
|
||||
|
||||
Besides Zig, this is also the case with TinyGo (`-target=wasi`) and Rust
|
||||
(`--target wasm32-wasi`). This isn't the case with Go (`GOOS=js GOARCH=wasm`),
|
||||
though. In the latter case, wasm loops on `sys.Nanotime`.
|
||||
|
||||
We decided to expose `sys.Nanosleep` to allow overriding the implementation
|
||||
used in the common case, even if it isn't used by Go, because this gives an
|
||||
easy and efficient closure over a common program function. We also documented
|
||||
`sys.Nanotime` to warn users that some compilers don't optimize sleep.
|
||||
|
||||
## Signed encoding of integer global constant initializers
|
||||
wazero treats integer global constant initializers signed as their interpretation is not known at declaration time. For
|
||||
example, there is no signed integer [value type](https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#value-types%E2%91%A0).
|
||||
|
||||
46
config.go
46
config.go
@@ -487,8 +487,11 @@ type ModuleConfig interface {
|
||||
// return clock.nanotime()
|
||||
// }, sys.ClockResolution(time.Microsecond.Nanoseconds()))
|
||||
//
|
||||
// Note: This does not default to time.Since as that violates sandboxing.
|
||||
// Use WithSysNanotime for a usable implementation.
|
||||
// Notes:
|
||||
// * This does not default to time.Since as that violates sandboxing.
|
||||
// * Some compilers implement sleep by looping on sys.Nanotime (ex. Go).
|
||||
// * If you set this, you should probably set WithNanosleep also.
|
||||
// * Use WithSysNanotime for a usable implementation.
|
||||
WithNanotime(sys.Nanotime, sys.ClockResolution) ModuleConfig
|
||||
|
||||
// WithSysNanotime uses time.Now for sys.Nanotime with a resolution of 1us.
|
||||
@@ -496,6 +499,31 @@ type ModuleConfig interface {
|
||||
// See WithNanotime
|
||||
WithSysNanotime() ModuleConfig
|
||||
|
||||
// WithNanosleep configures the how to pause the current goroutine for at
|
||||
// least the configured nanoseconds. Defaults to return immediately.
|
||||
//
|
||||
// Ex. To override with your own sleep function:
|
||||
// moduleConfig = moduleConfig.
|
||||
// WithNanosleep(func(ctx context.Context, ns int64) {
|
||||
// rel := unix.NsecToTimespec(ns)
|
||||
// remain := unix.Timespec{}
|
||||
// for { // loop until no more time remaining
|
||||
// err := unix.ClockNanosleep(unix.CLOCK_MONOTONIC, 0, &rel, &remain)
|
||||
// --snip--
|
||||
//
|
||||
// Notes:
|
||||
// * This primarily supports `poll_oneoff` for relative clock events.
|
||||
// * This does not default to time.Sleep as that violates sandboxing.
|
||||
// * Some compilers implement sleep by looping on sys.Nanotime (ex. Go).
|
||||
// * If you set this, you should probably set WithNanotime also.
|
||||
// * Use WithSysNanosleep for a usable implementation.
|
||||
WithNanosleep(sys.Nanosleep) ModuleConfig
|
||||
|
||||
// WithSysNanosleep uses time.Sleep for sys.Nanosleep.
|
||||
//
|
||||
// See WithNanosleep
|
||||
WithSysNanosleep() ModuleConfig
|
||||
|
||||
// WithRandSource configures a source of random bytes. Defaults to crypto/rand.Reader.
|
||||
//
|
||||
// This reader is most commonly used by the functions like "random_get" in "wasi_snapshot_preview1" or "seed" in
|
||||
@@ -530,6 +558,7 @@ type moduleConfig struct {
|
||||
walltimeResolution sys.ClockResolution
|
||||
nanotime *sys.Nanotime
|
||||
nanotimeResolution sys.ClockResolution
|
||||
nanosleep *sys.Nanosleep
|
||||
args []string
|
||||
// environ is pair-indexed to retain order similar to os.Environ.
|
||||
environ []string
|
||||
@@ -650,6 +679,18 @@ func (c *moduleConfig) WithSysNanotime() ModuleConfig {
|
||||
return c.WithNanotime(platform.Nanotime, sys.ClockResolution(1))
|
||||
}
|
||||
|
||||
// WithNanosleep implements ModuleConfig.WithNanosleep
|
||||
func (c *moduleConfig) WithNanosleep(nanosleep sys.Nanosleep) ModuleConfig {
|
||||
ret := *c // copy
|
||||
ret.nanosleep = &nanosleep
|
||||
return &ret
|
||||
}
|
||||
|
||||
// WithSysNanosleep implements ModuleConfig.WithSysNanosleep
|
||||
func (c *moduleConfig) WithSysNanosleep() ModuleConfig {
|
||||
return c.WithNanosleep(platform.Nanosleep)
|
||||
}
|
||||
|
||||
// WithRandSource implements ModuleConfig.WithRandSource
|
||||
func (c *moduleConfig) WithRandSource(source io.Reader) ModuleConfig {
|
||||
ret := c.clone()
|
||||
@@ -698,6 +739,7 @@ func (c *moduleConfig) toSysContext() (sysCtx *internalsys.Context, err error) {
|
||||
c.randSource,
|
||||
c.walltime, c.walltimeResolution,
|
||||
c.nanotime, c.nanotimeResolution,
|
||||
c.nanosleep,
|
||||
preopens,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -325,6 +325,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
),
|
||||
},
|
||||
@@ -341,7 +342,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
),
|
||||
},
|
||||
@@ -358,7 +359,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
),
|
||||
},
|
||||
@@ -375,7 +376,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
),
|
||||
},
|
||||
@@ -392,7 +393,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
),
|
||||
},
|
||||
@@ -409,6 +410,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
),
|
||||
},
|
||||
@@ -425,7 +427,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
),
|
||||
},
|
||||
@@ -442,7 +444,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
),
|
||||
},
|
||||
@@ -459,7 +461,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
),
|
||||
},
|
||||
@@ -476,7 +478,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
|
||||
nil, // nanosleep
|
||||
map[uint32]*internalsys.FileEntry{ // openedFiles
|
||||
3: {Path: "/", FS: testFS},
|
||||
4: {Path: ".", FS: testFS},
|
||||
@@ -496,6 +498,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
nil, // nanosleep
|
||||
map[uint32]*internalsys.FileEntry{ // openedFiles
|
||||
3: {Path: "/", FS: testFS2},
|
||||
4: {Path: ".", FS: testFS2},
|
||||
@@ -515,6 +518,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
nil, // nanosleep
|
||||
map[uint32]*internalsys.FileEntry{ // openedFiles
|
||||
3: {Path: ".", FS: testFS},
|
||||
},
|
||||
@@ -533,6 +537,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
nil, // nanosleep
|
||||
map[uint32]*internalsys.FileEntry{ // openedFiles
|
||||
3: {Path: "/", FS: testFS},
|
||||
4: {Path: ".", FS: testFS2},
|
||||
@@ -552,6 +557,7 @@ func TestModuleConfig_toSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
&wt, 1, // walltime, walltimeResolution
|
||||
&nt, 1, // nanotime, nanotimeResolution
|
||||
nil, // nanosleep
|
||||
map[uint32]*internalsys.FileEntry{ // openedFiles
|
||||
3: {Path: ".", FS: testFS},
|
||||
4: {Path: "/", FS: testFS2},
|
||||
@@ -715,6 +721,18 @@ func TestModuleConfig_toSysContext_WithNanotime(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestModuleConfig_toSysContext_WithNanosleep has to test differently because
|
||||
// we can't compare function pointers when functions are passed by value.
|
||||
func TestModuleConfig_toSysContext_WithNanosleep(t *testing.T) {
|
||||
sysCtx, err := NewModuleConfig().
|
||||
WithNanosleep(func(ctx context.Context, ns int64) {
|
||||
require.Equal(t, testCtx, ctx)
|
||||
}).(*moduleConfig).toSysContext()
|
||||
require.NoError(t, err)
|
||||
// If below pass, the context was correct!
|
||||
sysCtx.Nanosleep(testCtx, 2)
|
||||
}
|
||||
|
||||
func TestModuleConfig_toSysContext_Errors(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -820,6 +838,7 @@ func requireSysContext(
|
||||
randSource io.Reader,
|
||||
walltime *sys.Walltime, walltimeResolution sys.ClockResolution,
|
||||
nanotime *sys.Nanotime, nanotimeResolution sys.ClockResolution,
|
||||
nanosleep *sys.Nanosleep,
|
||||
openedFiles map[uint32]*internalsys.FileEntry,
|
||||
) *internalsys.Context {
|
||||
sysCtx, err := internalsys.NewContext(
|
||||
@@ -832,6 +851,7 @@ func requireSysContext(
|
||||
randSource,
|
||||
walltime, walltimeResolution,
|
||||
nanotime, nanotimeResolution,
|
||||
nanosleep,
|
||||
openedFiles,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -37,6 +37,10 @@ func NewFakeNanotime() *sys.Nanotime {
|
||||
return &nt
|
||||
}
|
||||
|
||||
// FakeNanosleep implements sys.Nanosleep by returning without sleeping.
|
||||
func FakeNanosleep(context.Context, int64) {
|
||||
}
|
||||
|
||||
// Walltime implements sys.Walltime with time.Now.
|
||||
//
|
||||
// Note: This is only notably less efficient than it could be is reading
|
||||
@@ -66,3 +70,8 @@ func nanotimePortable() int64 {
|
||||
func Nanotime(context.Context) int64 {
|
||||
return nanotime()
|
||||
}
|
||||
|
||||
// Nanosleep implements sys.Nanosleep with time.Sleep.
|
||||
func Nanosleep(_ context.Context, ns int64) {
|
||||
time.Sleep(time.Duration(ns))
|
||||
}
|
||||
|
||||
@@ -67,3 +67,13 @@ func Test_Nanotime(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Nanosleep(t *testing.T) {
|
||||
ns := int64(50 * time.Millisecond)
|
||||
start := Nanotime(context.Background())
|
||||
Nanosleep(context.Background(), ns)
|
||||
|
||||
duration := Nanotime(context.Background()) - start
|
||||
max := ns * 2 // max scheduling delay
|
||||
require.True(t, duration > 0 && duration < max, "Nanosleep(%d) slept for %d", ns, duration)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ type Context struct {
|
||||
walltimeResolution sys.ClockResolution
|
||||
nanotime *sys.Nanotime
|
||||
nanotimeResolution sys.ClockResolution
|
||||
nanosleep *sys.Nanosleep
|
||||
randSource io.Reader
|
||||
|
||||
fs *FSContext
|
||||
@@ -103,8 +104,21 @@ func (c *Context) NanotimeResolution() sys.ClockResolution {
|
||||
return c.nanotimeResolution
|
||||
}
|
||||
|
||||
// Nanosleep implements sys.Nanosleep.
|
||||
func (c *Context) Nanosleep(ctx context.Context, ns int64) {
|
||||
(*(c.nanosleep))(ctx, ns)
|
||||
}
|
||||
|
||||
// FS returns the file system context.
|
||||
func (c *Context) FS() *FSContext {
|
||||
func (c *Context) FS(ctx context.Context) *FSContext {
|
||||
// Override Context when it is passed via context
|
||||
if fsValue := ctx.Value(FSKey{}); fsValue != nil {
|
||||
fsCtx, ok := fsValue.(*FSContext)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("unsupported fs key: %v", fsValue))
|
||||
}
|
||||
return fsCtx
|
||||
}
|
||||
return c.fs
|
||||
}
|
||||
|
||||
@@ -128,7 +142,7 @@ func (eofReader) Read([]byte) (int, error) {
|
||||
// Note: This isn't a constant because Context.openedFiles is currently mutable even when empty.
|
||||
// TODO: Make it an error to open or close files when no FS was assigned.
|
||||
func DefaultContext() *Context {
|
||||
if sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, nil); err != nil {
|
||||
if sysCtx, err := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, nil, nil); err != nil {
|
||||
panic(fmt.Errorf("BUG: DefaultContext should never error: %w", err))
|
||||
} else {
|
||||
return sysCtx
|
||||
@@ -136,6 +150,7 @@ func DefaultContext() *Context {
|
||||
}
|
||||
|
||||
var _ = DefaultContext() // Force panic on bug.
|
||||
var ns sys.Nanosleep = platform.FakeNanosleep
|
||||
|
||||
// NewContext is a factory function which helps avoid needing to know defaults or exporting all fields.
|
||||
// Note: max is exposed for testing. max is only used for env/args validation.
|
||||
@@ -147,6 +162,7 @@ func NewContext(
|
||||
randSource io.Reader,
|
||||
walltime *sys.Walltime, walltimeResolution sys.ClockResolution,
|
||||
nanotime *sys.Nanotime, nanotimeResolution sys.ClockResolution,
|
||||
nanosleep *sys.Nanosleep,
|
||||
openedFiles map[uint32]*FileEntry,
|
||||
) (sysCtx *Context, err error) {
|
||||
sysCtx = &Context{args: args, environ: environ}
|
||||
@@ -205,6 +221,12 @@ func NewContext(
|
||||
sysCtx.nanotimeResolution = sys.ClockResolution(time.Nanosecond)
|
||||
}
|
||||
|
||||
if nanosleep != nil {
|
||||
sysCtx.nanosleep = nanosleep
|
||||
} else {
|
||||
sysCtx.nanosleep = &ns
|
||||
}
|
||||
|
||||
sysCtx.fs = NewFSContext(openedFiles)
|
||||
|
||||
return
|
||||
|
||||
@@ -2,6 +2,7 @@ package sys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"testing"
|
||||
@@ -23,6 +24,7 @@ func TestDefaultSysContext(t *testing.T) {
|
||||
nil, // randSource
|
||||
nil, 0, // walltime, walltimeResolution
|
||||
nil, 0, // nanotime, nanotimeResolution
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@@ -41,8 +43,9 @@ func TestDefaultSysContext(t *testing.T) {
|
||||
require.Equal(t, sys.ClockResolution(1_000), sysCtx.WalltimeResolution())
|
||||
require.Zero(t, sysCtx.Nanotime(testCtx)) // See above on functions.
|
||||
require.Equal(t, sys.ClockResolution(1), sysCtx.NanotimeResolution())
|
||||
require.Equal(t, &ns, sysCtx.nanosleep)
|
||||
require.Equal(t, rand.Reader, sysCtx.RandSource())
|
||||
require.Equal(t, NewFSContext(map[uint32]*FileEntry{}), sysCtx.FS())
|
||||
require.Equal(t, NewFSContext(map[uint32]*FileEntry{}), sysCtx.FS(testCtx))
|
||||
}
|
||||
|
||||
func TestNewContext_Args(t *testing.T) {
|
||||
@@ -93,6 +96,7 @@ func TestNewContext_Args(t *testing.T) {
|
||||
nil, // randSource
|
||||
nil, 0, // walltime, walltimeResolution
|
||||
nil, 0, // nanotime, nanotimeResolution
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
)
|
||||
if tc.expectedErr == "" {
|
||||
@@ -154,6 +158,7 @@ func TestNewContext_Environ(t *testing.T) {
|
||||
nil, // randSource
|
||||
nil, 0, // walltime, walltimeResolution
|
||||
nil, 0, // nanotime, nanotimeResolution
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
)
|
||||
if tc.expectedErr == "" {
|
||||
@@ -201,6 +206,7 @@ func TestNewContext_Walltime(t *testing.T) {
|
||||
nil, // randSource
|
||||
tc.time, tc.resolution, // walltime, walltimeResolution
|
||||
nil, 0, // nanotime, nanotimeResolution
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
)
|
||||
if tc.expectedErr == "" {
|
||||
@@ -248,6 +254,7 @@ func TestNewContext_Nanotime(t *testing.T) {
|
||||
nil, // randSource
|
||||
nil, 0, // nanotime, nanotimeResolution
|
||||
tc.time, tc.resolution, // nanotime, nanotimeResolution
|
||||
nil, // nanosleep
|
||||
nil, // openedFiles
|
||||
)
|
||||
if tc.expectedErr == "" {
|
||||
@@ -291,3 +298,23 @@ func Test_clockResolutionInvalid(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewContext_Nanosleep(t *testing.T) {
|
||||
var aNs sys.Nanosleep = func(context.Context, int64) {
|
||||
}
|
||||
sysCtx, err := NewContext(
|
||||
0, // max
|
||||
nil, // args
|
||||
nil,
|
||||
nil, // stdin
|
||||
nil, // stdout
|
||||
nil, // stderr
|
||||
nil, // randSource
|
||||
nil, 0, // Nanosleep, NanosleepResolution
|
||||
nil, 0, // Nanosleep, NanosleepResolution
|
||||
&aNs, // nanosleep
|
||||
nil, // openedFiles
|
||||
)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, &aNs, sysCtx.nanosleep)
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ func (m *CallContext) close(ctx context.Context, exitCode uint32) (c bool, err e
|
||||
return false, nil
|
||||
}
|
||||
if sysCtx := m.Sys; sysCtx != nil { // ex nil if from ModuleBuilder
|
||||
return true, sysCtx.FS().Close(ctx)
|
||||
return true, sysCtx.FS(ctx).Close(ctx)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -144,14 +144,15 @@ func TestCallContext_Close(t *testing.T) {
|
||||
|
||||
t.Run("calls Context.Close()", func(t *testing.T) {
|
||||
sysCtx := sys.DefaultContext()
|
||||
sysCtx.FS().OpenFile(&sys.FileEntry{Path: "."})
|
||||
fsCtx := sysCtx.FS(testCtx)
|
||||
|
||||
fsCtx.OpenFile(&sys.FileEntry{Path: "."})
|
||||
|
||||
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We use side effects to determine if Close in fact called Context.Close (without repeating sys_test.go).
|
||||
// One side effect of Context.Close is that it clears the openedFiles map. Verify our base case.
|
||||
fsCtx := sysCtx.FS()
|
||||
_, ok := fsCtx.OpenedFile(3)
|
||||
require.True(t, ok, "sysCtx.openedFiles was empty")
|
||||
|
||||
@@ -169,7 +170,9 @@ func TestCallContext_Close(t *testing.T) {
|
||||
t.Run("error closing", func(t *testing.T) {
|
||||
// Right now, the only way to err closing the sys context is if a File.Close erred.
|
||||
sysCtx := sys.DefaultContext()
|
||||
sysCtx.FS().OpenFile(&sys.FileEntry{Path: ".", File: &testFile{errors.New("error closing")}})
|
||||
fsCtx := sysCtx.FS(testCtx)
|
||||
|
||||
fsCtx.OpenFile(&sys.FileEntry{Path: ".", File: &testFile{errors.New("error closing")}})
|
||||
|
||||
m, err := s.Instantiate(context.Background(), ns, &Module{}, t.Name(), sysCtx, nil)
|
||||
require.NoError(t, err)
|
||||
@@ -177,7 +180,7 @@ func TestCallContext_Close(t *testing.T) {
|
||||
require.EqualError(t, m.Close(testCtx), "error closing")
|
||||
|
||||
// Verify our intended side-effect
|
||||
_, ok := sysCtx.FS().OpenedFile(3)
|
||||
_, ok := fsCtx.OpenedFile(3)
|
||||
require.False(t, ok, "expected no opened files")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -157,6 +157,7 @@ func (m *MemoryInstance) WriteUint16Le(_ context.Context, offset uint32, v uint1
|
||||
|
||||
// WriteUint32Le implements the same method as documented on api.Memory.
|
||||
func (m *MemoryInstance) WriteUint32Le(_ context.Context, offset, v uint32) bool {
|
||||
// Note: If you use the context.Context param, don't forget to coerce nil to context.Background()!
|
||||
|
||||
return m.writeUint32Le(offset, v)
|
||||
}
|
||||
|
||||
@@ -163,7 +163,9 @@ func TestNamespace_CloseWithExitCode(t *testing.T) {
|
||||
|
||||
t.Run("error closing", func(t *testing.T) {
|
||||
sysCtx := sys.DefaultContext()
|
||||
sysCtx.FS().OpenFile(&sys.FileEntry{Path: ".", File: &testFile{errors.New("error closing")}})
|
||||
fsCtx := sysCtx.FS(testCtx)
|
||||
|
||||
fsCtx.OpenFile(&sys.FileEntry{Path: ".", File: &testFile{errors.New("error closing")}})
|
||||
|
||||
ns, m1, m2 := newTestNamespace()
|
||||
m1.CallCtx.Sys = sysCtx // This should err, but both should close
|
||||
|
||||
@@ -76,53 +76,53 @@ your use case (ex which language you are using to compile, a.k.a. target Wasm).
|
||||
<details><summary>Click to see the full list of supported WASI functions</summary>
|
||||
<p>
|
||||
|
||||
| Function | Status | Known Usage |
|
||||
|:------------------------|:------:|---------------:|
|
||||
| args_get | ✅ | TinyGo |
|
||||
| args_sizes_get | ✅ | TinyGo |
|
||||
| environ_get | ✅ | TinyGo |
|
||||
| environ_sizes_get | ✅ | TinyGo |
|
||||
| clock_res_get | ✅ | |
|
||||
| clock_time_get | ✅ | TinyGo |
|
||||
| fd_advise | ❌ | |
|
||||
| fd_allocate | ❌ | |
|
||||
| fd_close | ✅ | TinyGo |
|
||||
| fd_datasync | ❌ | |
|
||||
| fd_fdstat_get | ✅ | TinyGo |
|
||||
| fd_fdstat_set_flags | ❌ | |
|
||||
| fd_fdstat_set_rights | ❌ | |
|
||||
| fd_filestat_get | ❌ | |
|
||||
| fd_filestat_set_size | ❌ | |
|
||||
| fd_filestat_set_times | ❌ | |
|
||||
| fd_pread | ❌ | |
|
||||
| fd_prestat_get | ✅ | TinyGo |
|
||||
| fd_prestat_dir_name | ✅ | TinyGo |
|
||||
| fd_pwrite | ❌ | |
|
||||
| fd_read | ✅ | TinyGo |
|
||||
| fd_readdir | ❌ | |
|
||||
| fd_renumber | ❌ | |
|
||||
| fd_seek | ✅ | TinyGo |
|
||||
| fd_sync | ❌ | |
|
||||
| fd_tell | ❌ | |
|
||||
| fd_write | ✅ | |
|
||||
| path_create_directory | ❌ | |
|
||||
| path_filestat_get | ❌ | |
|
||||
| path_filestat_set_times | ❌ | |
|
||||
| path_link | ❌ | |
|
||||
| path_open | ✅ | TinyGo |
|
||||
| path_readlink | ❌ | |
|
||||
| path_remove_directory | ❌ | |
|
||||
| path_rename | ❌ | |
|
||||
| path_symlink | ❌ | |
|
||||
| path_unlink_file | ❌ | |
|
||||
| poll_oneoff | ✅ | TinyGo |
|
||||
| proc_exit | ✅ | AssemblyScript |
|
||||
| proc_raise | ❌ | |
|
||||
| sched_yield | ❌ | |
|
||||
| random_get | ✅ | |
|
||||
| sock_recv | ❌ | |
|
||||
| sock_send | ❌ | |
|
||||
| sock_shutdown | ❌ | |
|
||||
| Function | Status | Known Usage |
|
||||
|:------------------------|:------:|----------------:|
|
||||
| args_get | ✅ | TinyGo |
|
||||
| args_sizes_get | ✅ | TinyGo |
|
||||
| environ_get | ✅ | TinyGo |
|
||||
| environ_sizes_get | ✅ | TinyGo |
|
||||
| clock_res_get | ✅ | |
|
||||
| clock_time_get | ✅ | TinyGo |
|
||||
| fd_advise | ❌ | |
|
||||
| fd_allocate | ❌ | |
|
||||
| fd_close | ✅ | TinyGo |
|
||||
| fd_datasync | ❌ | |
|
||||
| fd_fdstat_get | ✅ | TinyGo |
|
||||
| fd_fdstat_set_flags | ❌ | |
|
||||
| fd_fdstat_set_rights | ❌ | |
|
||||
| fd_filestat_get | ❌ | |
|
||||
| fd_filestat_set_size | ❌ | |
|
||||
| fd_filestat_set_times | ❌ | |
|
||||
| fd_pread | ❌ | |
|
||||
| fd_prestat_get | ✅ | TinyGo |
|
||||
| fd_prestat_dir_name | ✅ | TinyGo |
|
||||
| fd_pwrite | ❌ | |
|
||||
| fd_read | ✅ | TinyGo |
|
||||
| fd_readdir | ❌ | |
|
||||
| fd_renumber | ❌ | |
|
||||
| fd_seek | ✅ | TinyGo |
|
||||
| fd_sync | ❌ | |
|
||||
| fd_tell | ❌ | |
|
||||
| fd_write | ✅ | |
|
||||
| path_create_directory | ❌ | |
|
||||
| path_filestat_get | ❌ | |
|
||||
| path_filestat_set_times | ❌ | |
|
||||
| path_link | ❌ | |
|
||||
| path_open | ✅ | TinyGo |
|
||||
| path_readlink | ❌ | |
|
||||
| path_remove_directory | ❌ | |
|
||||
| path_rename | ❌ | |
|
||||
| path_symlink | ❌ | |
|
||||
| path_unlink_file | ❌ | |
|
||||
| poll_oneoff | ✅ | Rust,TinyGo,Zig |
|
||||
| proc_exit | ✅ | AssemblyScript |
|
||||
| proc_raise | ❌ | |
|
||||
| sched_yield | ❌ | |
|
||||
| random_get | ✅ | |
|
||||
| sock_recv | ❌ | |
|
||||
| sock_send | ❌ | |
|
||||
| sock_shutdown | ❌ | |
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
@@ -19,3 +19,6 @@ type Walltime func(context.Context) (sec int64, nsec int32)
|
||||
// Note: There are no constraints on the value return except that it
|
||||
// increments. For example, -1 is a valid if the next value is >= 0.
|
||||
type Nanotime func(context.Context) int64
|
||||
|
||||
// Nanosleep puts the current goroutine to sleep for at least ns nanoseconds.
|
||||
type Nanosleep func(ctx context.Context, ns int64)
|
||||
|
||||
123
wasi_snapshot_preview1/clock.go
Normal file
123
wasi_snapshot_preview1/clock.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
const (
|
||||
// functionClockResGet returns the resolution of a clock.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_res_getid-clockid---errno-timestamp
|
||||
functionClockResGet = "clock_res_get"
|
||||
|
||||
// importClockResGet is the WebAssembly 1.0 Text format import of functionClockResGet.
|
||||
importClockResGet = `(import "wasi_snapshot_preview1" "clock_res_get"
|
||||
(func $wasi.clock_res_get (param $id i32) (param $result.resolution i32) (result (;errno;) i32)))`
|
||||
|
||||
// functionClockTimeGet returns the time value of a clock.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_time_getid-clockid-precision-timestamp---errno-timestamp
|
||||
functionClockTimeGet = "clock_time_get"
|
||||
|
||||
// importClockTimeGet is the WebAssembly 1.0 Text format import of functionClockTimeGet.
|
||||
importClockTimeGet = `(import "wasi_snapshot_preview1" "clock_time_get"
|
||||
(func $wasi.clock_time_get (param $id i32) (param $precision i64) (param $result.timestamp i32) (result (;errno;) i32)))`
|
||||
)
|
||||
|
||||
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clockid-enumu32
|
||||
const (
|
||||
// clockIDRealtime is the clock ID named "realtime" associated with sys.Walltime
|
||||
clockIDRealtime = iota
|
||||
// clockIDMonotonic is the clock ID named "monotonic" with sys.Nanotime
|
||||
clockIDMonotonic
|
||||
// clockIDProcessCputime is the unsupported clock ID named "process_cputime_id"
|
||||
clockIDProcessCputime
|
||||
// clockIDThreadCputime is the unsupported clock ID named "thread_cputime_id"
|
||||
clockIDThreadCputime
|
||||
)
|
||||
|
||||
// ClockResGet is the WASI function named functionClockResGet that returns the resolution of time values returned by ClockTimeGet.
|
||||
//
|
||||
// * id - The clock id for which to return the time.
|
||||
// * resultResolution - the offset to write the resolution to mod.Memory
|
||||
// * the resolution is an uint64 little-endian encoding.
|
||||
//
|
||||
// For example, if the resolution is 100ns, this function writes the below to `mod.Memory`:
|
||||
//
|
||||
// uint64le
|
||||
// +-------------------------------------+
|
||||
// | |
|
||||
// []byte{?, 0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ?}
|
||||
// resultResolution --^
|
||||
//
|
||||
// Note: importClockResGet shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// Note: This is similar to `clock_getres` in POSIX.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_res_getid-clockid---errno-timestamp
|
||||
// See https://linux.die.net/man/3/clock_getres
|
||||
func (a *wasi) ClockResGet(ctx context.Context, mod api.Module, id uint32, resultResolution uint32) Errno {
|
||||
sysCtx := getSysCtx(mod)
|
||||
|
||||
var resolution uint64 // ns
|
||||
switch id {
|
||||
case clockIDRealtime:
|
||||
resolution = uint64(sysCtx.WalltimeResolution())
|
||||
case clockIDMonotonic:
|
||||
resolution = uint64(sysCtx.NanotimeResolution())
|
||||
case clockIDProcessCputime, clockIDThreadCputime:
|
||||
// Similar to many other runtimes, we only support realtime and monotonic clocks. Other types
|
||||
// are slated to be removed from the next version of WASI.
|
||||
return ErrnoNotsup
|
||||
default:
|
||||
return ErrnoInval
|
||||
}
|
||||
if !mod.Memory().WriteUint64Le(ctx, resultResolution, resolution) {
|
||||
return ErrnoFault
|
||||
}
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
// ClockTimeGet is the WASI function named functionClockTimeGet that returns the time value of a clock (time.Now).
|
||||
//
|
||||
// * id - The clock id for which to return the time.
|
||||
// * precision - The maximum lag (exclusive) that the returned time value may have, compared to its actual value.
|
||||
// * resultTimestamp - the offset to write the timestamp to mod.Memory
|
||||
// * the timestamp is epoch nanoseconds encoded as a uint64 little-endian encoding.
|
||||
//
|
||||
// For example, if time.Now returned exactly midnight UTC 2022-01-01 (1640995200000000000), and
|
||||
// parameters resultTimestamp=1, this function writes the below to `mod.Memory`:
|
||||
//
|
||||
// uint64le
|
||||
// +------------------------------------------+
|
||||
// | |
|
||||
// []byte{?, 0x0, 0x0, 0x1f, 0xa6, 0x70, 0xfc, 0xc5, 0x16, ?}
|
||||
// resultTimestamp --^
|
||||
//
|
||||
// Note: importClockTimeGet shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// Note: This is similar to `clock_gettime` in POSIX.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_time_getid-clockid-precision-timestamp---errno-timestamp
|
||||
// See https://linux.die.net/man/3/clock_gettime
|
||||
func (a *wasi) ClockTimeGet(ctx context.Context, mod api.Module, id uint32, precision uint64, resultTimestamp uint32) Errno {
|
||||
// TODO: precision is currently ignored.
|
||||
sysCtx := getSysCtx(mod)
|
||||
|
||||
var val uint64
|
||||
switch id {
|
||||
case clockIDRealtime:
|
||||
sec, nsec := sysCtx.Walltime(ctx)
|
||||
val = (uint64(sec) * uint64(time.Second.Nanoseconds())) + uint64(nsec)
|
||||
case clockIDMonotonic:
|
||||
val = uint64(sysCtx.Nanotime(ctx))
|
||||
case clockIDProcessCputime, clockIDThreadCputime:
|
||||
// Similar to many other runtimes, we only support realtime and monotonic clocks. Other types
|
||||
// are slated to be removed from the next version of WASI.
|
||||
return ErrnoNotsup
|
||||
default:
|
||||
return ErrnoInval
|
||||
}
|
||||
|
||||
if !mod.Memory().WriteUint64Le(ctx, resultTimestamp, val) {
|
||||
return ErrnoFault
|
||||
}
|
||||
return ErrnoSuccess
|
||||
}
|
||||
278
wasi_snapshot_preview1/clock_test.go
Normal file
278
wasi_snapshot_preview1/clock_test.go
Normal file
@@ -0,0 +1,278 @@
|
||||
package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
|
||||
// Test_ClockResGet only tests it is stubbed for GrainLang per #271
|
||||
func Test_ClockResGet(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionClockResGet, importClockResGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
resultResolution := uint32(1) // arbitrary offset
|
||||
|
||||
expectedMemoryMicro := []byte{
|
||||
'?', // resultResolution is after this
|
||||
0xe8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // little endian-encoded resolution (fixed to 1000).
|
||||
'?', // stopped after encoding
|
||||
}
|
||||
|
||||
expectedMemoryNano := []byte{
|
||||
'?', // resultResolution is after this
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // little endian-encoded resolution (fixed to 1000).
|
||||
'?', // stopped after encoding
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
clockID uint64
|
||||
expectedMemory []byte
|
||||
invocation func(clockID uint64) Errno
|
||||
}{
|
||||
{
|
||||
name: "wasi.ClockResGet",
|
||||
clockID: 0,
|
||||
expectedMemory: expectedMemoryMicro,
|
||||
invocation: func(clockID uint64) Errno {
|
||||
return a.ClockResGet(testCtx, mod, uint32(clockID), resultResolution)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "wasi.ClockResGet",
|
||||
clockID: 1,
|
||||
expectedMemory: expectedMemoryNano,
|
||||
invocation: func(clockID uint64) Errno {
|
||||
return a.ClockResGet(testCtx, mod, uint32(clockID), resultResolution)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: functionClockResGet,
|
||||
clockID: 0,
|
||||
expectedMemory: expectedMemoryMicro,
|
||||
invocation: func(clockID uint64) Errno {
|
||||
results, err := fn.Call(testCtx, clockID, uint64(resultResolution))
|
||||
require.NoError(t, err)
|
||||
return Errno(results[0]) // results[0] is the errno
|
||||
},
|
||||
},
|
||||
{
|
||||
name: functionClockResGet,
|
||||
clockID: 1,
|
||||
expectedMemory: expectedMemoryNano,
|
||||
invocation: func(clockID uint64) Errno {
|
||||
results, err := fn.Call(testCtx, clockID, uint64(resultResolution))
|
||||
require.NoError(t, err)
|
||||
return Errno(results[0]) // results[0] is the errno
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
|
||||
t.Run(fmt.Sprintf("%v/clockID=%v", tc.name, tc.clockID), func(t *testing.T) {
|
||||
maskMemory(t, testCtx, mod, len(tc.expectedMemory))
|
||||
|
||||
errno := tc.invocation(tc.clockID)
|
||||
require.Equal(t, ErrnoSuccess, errno, ErrnoName(errno))
|
||||
|
||||
actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(tc.expectedMemory)))
|
||||
require.True(t, ok)
|
||||
require.Equal(t, tc.expectedMemory, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ClockResGet_Unsupported(t *testing.T) {
|
||||
resultResolution := uint32(1) // arbitrary offset
|
||||
mod, fn := instantiateModule(testCtx, t, functionClockResGet, importClockResGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
clockID uint64
|
||||
expectedErrno Errno
|
||||
}{
|
||||
{
|
||||
name: "process cputime",
|
||||
clockID: 2,
|
||||
expectedErrno: ErrnoNotsup,
|
||||
},
|
||||
{
|
||||
name: "thread cputime",
|
||||
clockID: 3,
|
||||
expectedErrno: ErrnoNotsup,
|
||||
},
|
||||
{
|
||||
name: "undefined",
|
||||
clockID: 100,
|
||||
expectedErrno: ErrnoInval,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
results, err := fn.Call(testCtx, tc.clockID, uint64(resultResolution))
|
||||
require.NoError(t, err)
|
||||
errno := Errno(results[0]) // results[0] is the errno
|
||||
require.Equal(t, tc.expectedErrno, errno, ErrnoName(errno))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ClockTimeGet(t *testing.T) {
|
||||
resultTimestamp := uint32(1) // arbitrary offset
|
||||
|
||||
mod, fn := instantiateModule(testCtx, t, functionClockTimeGet, importClockTimeGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
clocks := []struct {
|
||||
clock string
|
||||
id uint32
|
||||
expectedMemory []byte
|
||||
}{
|
||||
{
|
||||
clock: "Realtime",
|
||||
id: clockIDRealtime,
|
||||
expectedMemory: []byte{
|
||||
'?', // resultTimestamp is after this
|
||||
0x0, 0x0, 0x1f, 0xa6, 0x70, 0xfc, 0xc5, 0x16, // little endian-encoded epochNanos
|
||||
'?', // stopped after encoding
|
||||
},
|
||||
},
|
||||
{
|
||||
clock: "Monotonic",
|
||||
id: clockIDMonotonic,
|
||||
expectedMemory: []byte{
|
||||
'?', // resultTimestamp is after this
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // fake nanotime starts at zero
|
||||
'?', // stopped after encoding
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range clocks {
|
||||
cc := c
|
||||
t.Run(cc.clock, func(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
invocation func() Errno
|
||||
}{
|
||||
{
|
||||
name: "wasi.ClockTimeGet",
|
||||
invocation: func() Errno {
|
||||
return a.ClockTimeGet(testCtx, mod, cc.id, 0 /* TODO: precision */, resultTimestamp)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: functionClockTimeGet,
|
||||
invocation: func() Errno {
|
||||
results, err := fn.Call(testCtx, uint64(cc.id), 0 /* TODO: precision */, uint64(resultTimestamp))
|
||||
require.NoError(t, err)
|
||||
errno := Errno(results[0]) // results[0] is the errno
|
||||
return errno
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Reset the fake clock
|
||||
sysCtx, err := newSysContext(nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
mod.(*wasm.CallContext).Sys = sysCtx
|
||||
|
||||
maskMemory(t, testCtx, mod, len(cc.expectedMemory))
|
||||
|
||||
errno := tc.invocation()
|
||||
require.Zero(t, errno, ErrnoName(errno))
|
||||
|
||||
actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(cc.expectedMemory)))
|
||||
require.True(t, ok)
|
||||
require.Equal(t, cc.expectedMemory, actual)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ClockTimeGet_Unsupported(t *testing.T) {
|
||||
resultTimestamp := uint32(1) // arbitrary offset
|
||||
mod, fn := instantiateModule(testCtx, t, functionClockTimeGet, importClockTimeGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
clockID uint64
|
||||
expectedErrno Errno
|
||||
}{
|
||||
{
|
||||
name: "process cputime",
|
||||
clockID: 2,
|
||||
expectedErrno: ErrnoNotsup,
|
||||
},
|
||||
{
|
||||
name: "thread cputime",
|
||||
clockID: 3,
|
||||
expectedErrno: ErrnoNotsup,
|
||||
},
|
||||
{
|
||||
name: "undefined",
|
||||
clockID: 100,
|
||||
expectedErrno: ErrnoInval,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
results, err := fn.Call(testCtx, tc.clockID, 0 /* TODO: precision */, uint64(resultTimestamp))
|
||||
require.NoError(t, err)
|
||||
errno := Errno(results[0]) // results[0] is the errno
|
||||
require.Equal(t, tc.expectedErrno, errno, ErrnoName(errno))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ClockTimeGet_Errors(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionClockTimeGet, importClockTimeGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
memorySize := mod.Memory().Size(testCtx)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
resultTimestamp uint32
|
||||
argvBufSize uint32
|
||||
}{
|
||||
{
|
||||
name: "resultTimestamp out-of-memory",
|
||||
resultTimestamp: memorySize,
|
||||
},
|
||||
|
||||
{
|
||||
name: "resultTimestamp exceeds the maximum valid address by 1",
|
||||
resultTimestamp: memorySize - 4 + 1, // 4 is the size of uint32, the type of the count of args
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
results, err := fn.Call(testCtx, 0 /* TODO: id */, 0 /* TODO: precision */, uint64(tc.resultTimestamp))
|
||||
require.NoError(t, err)
|
||||
errno := Errno(results[0]) // results[0] is the errno
|
||||
require.Equal(t, ErrnoFault, errno, ErrnoName(errno))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
//
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-errno-enumu16 and
|
||||
// https://linux.die.net/man/3/errno
|
||||
type Errno = uint32 // alias for parity with wasm.ValueType
|
||||
type Errno = uint32 // neither uint16 nor an alias for parity with wasm.ValueType
|
||||
|
||||
// ErrnoName returns the POSIX error code name, except ErrnoSuccess, which is not an error. Ex. Errno2big -> "E2BIG"
|
||||
func ErrnoName(errno Errno) string {
|
||||
|
||||
135
wasi_snapshot_preview1/poll.go
Normal file
135
wasi_snapshot_preview1/poll.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-eventtype-enumu8
|
||||
const (
|
||||
// eventTypeClock is the timeout event named "clock".
|
||||
eventTypeClock = iota
|
||||
// eventTypeFdRead is the data available event named "fd_read".
|
||||
eventTypeFdRead
|
||||
// eventTypeFdWrite is the capacity available event named "fd_write".
|
||||
eventTypeFdWrite
|
||||
)
|
||||
|
||||
// PollOneoff is the WASI function named functionPollOneoff that concurrently
|
||||
// polls for the occurrence of a set of events.
|
||||
//
|
||||
// Parameters
|
||||
//
|
||||
// * in - pointer to the subscriptions (48 bytes each)
|
||||
// * out - pointer to the resulting events (32 bytes each)
|
||||
// * nsubscriptions - count of subscriptions, zero returns ErrnoInval.
|
||||
// * resultNevents - count of events.
|
||||
//
|
||||
// Result (Errno)
|
||||
//
|
||||
// The return value is ErrnoSuccess except the following error conditions:
|
||||
// * ErrnoInval - If the parameters are invalid
|
||||
// * ErrnoNotsup - If a parameters is valid, but not yet supported.
|
||||
// * ErrnoFault - if there is not enough memory to read the subscriptions or write results.
|
||||
//
|
||||
// Notes
|
||||
//
|
||||
// * Since the `out` pointer nests Errno, the result is always ErrnoSuccess.
|
||||
// * importPollOneoff shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// * This is similar to `poll` in POSIX.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#poll_oneoff
|
||||
// See https://linux.die.net/man/3/poll
|
||||
func (a *wasi) PollOneoff(ctx context.Context, mod api.Module, in, out, nsubscriptions, resultNevents uint32) Errno {
|
||||
if nsubscriptions == 0 {
|
||||
return ErrnoInval
|
||||
}
|
||||
|
||||
mem := mod.Memory()
|
||||
|
||||
// Ensure capacity prior to the read loop to reduce error handling.
|
||||
inBuf, ok := mem.Read(ctx, in, nsubscriptions*48)
|
||||
if !ok {
|
||||
return ErrnoFault
|
||||
}
|
||||
outBuf, ok := mem.Read(ctx, out, nsubscriptions*32)
|
||||
if !ok {
|
||||
return ErrnoFault
|
||||
}
|
||||
|
||||
// Eagerly write the number of events which will equal subscriptions unless
|
||||
// there's a fault in parsing (not processing).
|
||||
if !mod.Memory().WriteUint32Le(ctx, resultNevents, nsubscriptions) {
|
||||
return ErrnoFault
|
||||
}
|
||||
|
||||
// Loop through all subscriptions and write their output.
|
||||
for sub := uint32(0); sub < nsubscriptions; sub++ {
|
||||
inOffset := sub * 48
|
||||
outOffset := sub * 32
|
||||
|
||||
var errno Errno
|
||||
eventType := inBuf[inOffset+8] // +8 past userdata
|
||||
switch eventType {
|
||||
case eventTypeClock: // handle later
|
||||
// +8 past userdata +8 clock alignment
|
||||
errno = processClockEvent(ctx, mod, inBuf[inOffset+8+8:])
|
||||
case eventTypeFdRead, eventTypeFdWrite:
|
||||
// +8 past userdata +4 FD alignment
|
||||
errno = processFDEvent(ctx, mod, eventType, inBuf[inOffset+8+4:])
|
||||
default:
|
||||
return ErrnoInval
|
||||
}
|
||||
|
||||
// Write the event corresponding to the processed subscription.
|
||||
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-event-struct
|
||||
copy(outBuf, inBuf[inOffset:inOffset+8]) // userdata
|
||||
outBuf[outOffset+8] = byte(errno) // uint16, but safe as < 255
|
||||
outBuf[outOffset+9] = 0
|
||||
binary.LittleEndian.PutUint32(outBuf[outOffset+10:], uint32(eventType))
|
||||
// TODO: When FD events are supported, write outOffset+16
|
||||
}
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
// processClockEvent supports only relative clock events, as that's what's used
|
||||
// to implement sleep in various compilers including Rust, Zig and TinyGo.
|
||||
func processClockEvent(ctx context.Context, mod api.Module, inBuf []byte) Errno {
|
||||
_ /* ID */ = binary.LittleEndian.Uint32(inBuf[0:8]) // See below
|
||||
timeout := binary.LittleEndian.Uint64(inBuf[8:16]) // nanos if relative
|
||||
_ /* precision */ = binary.LittleEndian.Uint64(inBuf[16:24]) // Unused
|
||||
flags := binary.LittleEndian.Uint16(inBuf[24:32])
|
||||
|
||||
// subclockflags has only one flag defined: subscription_clock_abstime
|
||||
switch flags {
|
||||
case 0: // relative time
|
||||
case 1: // subscription_clock_abstime
|
||||
return ErrnoNotsup
|
||||
default: // subclockflags has only one flag defined.
|
||||
return ErrnoInval
|
||||
}
|
||||
|
||||
// https://linux.die.net/man/3/clock_settime says relative timers are
|
||||
// unaffected. Since this function only supports relative timeout, we can
|
||||
// skip clock ID validation and use a single sleep function.
|
||||
|
||||
getSysCtx(mod).Nanosleep(ctx, int64(timeout))
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
// processFDEvent returns a validation error or ErrnoNotsup as file or socket
|
||||
// subscriptions are not yet supported.
|
||||
func processFDEvent(ctx context.Context, mod api.Module, eventType byte, inBuf []byte) Errno {
|
||||
fd := binary.LittleEndian.Uint32(inBuf)
|
||||
|
||||
// Choose the best error, which falls back to unsupported, until we support files.
|
||||
errno := ErrnoNotsup
|
||||
if eventType == eventTypeFdRead && fdReader(ctx, mod, fd) == nil {
|
||||
errno = ErrnoBadf
|
||||
} else if eventType == eventTypeFdWrite && fdWriter(ctx, mod, fd) == nil {
|
||||
errno = ErrnoBadf
|
||||
}
|
||||
|
||||
return errno
|
||||
}
|
||||
163
wasi_snapshot_preview1/poll_test.go
Normal file
163
wasi_snapshot_preview1/poll_test.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package wasi_snapshot_preview1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||
"github.com/tetratelabs/wazero/internal/wasm"
|
||||
)
|
||||
|
||||
func Test_PollOneoff(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionPollOneoff, importPollOneoff, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
mem []byte
|
||||
expectedMem []byte // at offset out
|
||||
}{
|
||||
{
|
||||
name: "monotonic relative",
|
||||
mem: []byte{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
|
||||
eventTypeClock, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // event type and padding
|
||||
clockIDMonotonic, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // clockID
|
||||
0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // timeout (ns)
|
||||
0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // precision (ns)
|
||||
0x00, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // flags (relative)
|
||||
'?', // stopped after encoding
|
||||
},
|
||||
expectedMem: []byte{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
|
||||
byte(ErrnoSuccess), 0x0, // errno is 16 bit
|
||||
eventTypeClock, 0x0, 0x0, 0x0, // 4 bytes for type enum
|
||||
'?', // stopped after encoding
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
in := uint32(0) // past in
|
||||
out := uint32(128) // past in
|
||||
nsubscriptions := uint32(1)
|
||||
resultNevents := uint32(512) // past out
|
||||
|
||||
requireExpectedMem := func(expectedMem []byte) {
|
||||
outMem, ok := mod.Memory().Read(testCtx, out, uint32(len(expectedMem)))
|
||||
require.True(t, ok)
|
||||
require.Equal(t, expectedMem, outMem)
|
||||
|
||||
nevents, ok := mod.Memory().ReadUint32Le(testCtx, resultNevents)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, nsubscriptions, nevents)
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Run("wasi.PollOneoff", func(t *testing.T) {
|
||||
maskMemory(t, testCtx, mod, 1024)
|
||||
mod.Memory().Write(testCtx, in, tc.mem)
|
||||
|
||||
errno := a.PollOneoff(testCtx, mod, in, out, nsubscriptions, resultNevents)
|
||||
require.Equal(t, ErrnoSuccess, errno, ErrnoName(errno))
|
||||
requireExpectedMem(tc.expectedMem)
|
||||
})
|
||||
|
||||
t.Run(functionPollOneoff, func(t *testing.T) {
|
||||
maskMemory(t, testCtx, mod, 1024)
|
||||
mod.Memory().Write(testCtx, in, tc.mem)
|
||||
|
||||
results, err := fn.Call(testCtx, uint64(in), uint64(out), uint64(nsubscriptions), uint64(resultNevents))
|
||||
require.NoError(t, err)
|
||||
errno := Errno(results[0]) // results[0] is the errno
|
||||
require.Equal(t, ErrnoSuccess, errno, ErrnoName(errno))
|
||||
requireExpectedMem(tc.expectedMem)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PollOneoff_Errors(t *testing.T) {
|
||||
mod, _ := instantiateModule(testCtx, t, functionPollOneoff, importPollOneoff, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
in, out, nsubscriptions, resultNevents uint32
|
||||
mem []byte // at offset in
|
||||
expectedErrno Errno
|
||||
expectedMem []byte // at offset out
|
||||
}{
|
||||
{
|
||||
name: "in out of range",
|
||||
in: wasm.MemoryPageSize,
|
||||
nsubscriptions: 1,
|
||||
out: 128, // past in
|
||||
resultNevents: 512, //past out
|
||||
expectedErrno: ErrnoFault,
|
||||
},
|
||||
{
|
||||
name: "out out of range",
|
||||
out: wasm.MemoryPageSize,
|
||||
resultNevents: 512, //past out
|
||||
nsubscriptions: 1,
|
||||
expectedErrno: ErrnoFault,
|
||||
},
|
||||
{
|
||||
name: "resultNevents out of range",
|
||||
resultNevents: wasm.MemoryPageSize,
|
||||
nsubscriptions: 1,
|
||||
expectedErrno: ErrnoFault,
|
||||
},
|
||||
{
|
||||
name: "nsubscriptions zero",
|
||||
out: 128, // past in
|
||||
resultNevents: 512, //past out
|
||||
expectedErrno: ErrnoInval,
|
||||
},
|
||||
{
|
||||
name: "unsupported eventTypeFdRead",
|
||||
nsubscriptions: 1,
|
||||
mem: []byte{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
|
||||
eventTypeFdRead, 0x0, 0x0, 0x0,
|
||||
fdStdin, 0x0, 0x0, 0x0, // valid readable FD
|
||||
'?', // stopped after encoding
|
||||
},
|
||||
expectedErrno: ErrnoSuccess,
|
||||
out: 128, // past in
|
||||
resultNevents: 512, //past out
|
||||
expectedMem: []byte{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
|
||||
byte(ErrnoNotsup), 0x0, // errno is 16 bit
|
||||
eventTypeFdRead, 0x0, 0x0, 0x0, // 4 bytes for type enum
|
||||
'?', // stopped after encoding
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
maskMemory(t, testCtx, mod, 1024)
|
||||
|
||||
if tc.mem != nil {
|
||||
mod.Memory().Write(testCtx, tc.in, tc.mem)
|
||||
}
|
||||
|
||||
errno := a.PollOneoff(testCtx, mod, tc.in, tc.out, tc.nsubscriptions, tc.resultNevents)
|
||||
require.Equal(t, tc.expectedErrno, errno, ErrnoName(errno))
|
||||
|
||||
out, ok := mod.Memory().Read(testCtx, tc.out, uint32(len(tc.expectedMem)))
|
||||
require.True(t, ok)
|
||||
require.Equal(t, tc.expectedMem, out)
|
||||
|
||||
// Events should be written on success regardless of nested failure.
|
||||
if tc.expectedErrno == ErrnoSuccess {
|
||||
nevents, ok := mod.Memory().ReadUint32Le(testCtx, tc.resultNevents)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, uint32(1), nevents)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
// r := wazero.NewRuntime()
|
||||
// defer r.Close(ctx) // This closes everything this Runtime created.
|
||||
//
|
||||
// _, _ = wasi_snapshot_preview1.Instantiate(ctx, r)
|
||||
// _, _ = Instantiate(ctx, r)
|
||||
// mod, _ := r.InstantiateModuleFromBinary(ctx, wasm)
|
||||
//
|
||||
// See https://github.com/WebAssembly/WASI
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
@@ -85,7 +84,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-args_getargv-pointerpointeru8-argv_buf-pointeru8---errno
|
||||
functionArgsGet = "args_get"
|
||||
|
||||
// importArgsGet is the WebAssembly 1.0 (20191205) Text format import of functionArgsGet.
|
||||
// importArgsGet is the WebAssembly 1.0 Text format import of functionArgsGet.
|
||||
importArgsGet = `(import "wasi_snapshot_preview1" "args_get"
|
||||
(func $wasi.args_get (param $argv i32) (param $argv_buf i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -93,7 +92,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-args_sizes_get---errno-size-size
|
||||
functionArgsSizesGet = "args_sizes_get"
|
||||
|
||||
// importArgsSizesGet is the WebAssembly 1.0 (20191205) Text format import of functionArgsSizesGet.
|
||||
// importArgsSizesGet is the WebAssembly 1.0 Text format import of functionArgsSizesGet.
|
||||
importArgsSizesGet = `(import "wasi_snapshot_preview1" "args_sizes_get"
|
||||
(func $wasi.args_sizes_get (param $result.argc i32) (param $result.argv_buf_size i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -101,7 +100,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-environ_getenviron-pointerpointeru8-environ_buf-pointeru8---errno
|
||||
functionEnvironGet = "environ_get"
|
||||
|
||||
// importEnvironGet is the WebAssembly 1.0 (20191205) Text format import of functionEnvironGet.
|
||||
// importEnvironGet is the WebAssembly 1.0 Text format import of functionEnvironGet.
|
||||
importEnvironGet = `(import "wasi_snapshot_preview1" "environ_get"
|
||||
(func $wasi.environ_get (param $environ i32) (param $environ_buf i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -109,31 +108,15 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-environ_sizes_get---errno-size-size
|
||||
functionEnvironSizesGet = "environ_sizes_get"
|
||||
|
||||
// importEnvironSizesGet is the WebAssembly 1.0 (20191205) Text format import of functionEnvironSizesGet.
|
||||
// importEnvironSizesGet is the WebAssembly 1.0 Text format import of functionEnvironSizesGet.
|
||||
importEnvironSizesGet = `(import "wasi_snapshot_preview1" "environ_sizes_get"
|
||||
(func $wasi.environ_sizes_get (param $result.environc i32) (param $result.environBufSize i32) (result (;errno;) i32)))`
|
||||
|
||||
// functionClockResGet returns the resolution of a clock.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_res_getid-clockid---errno-timestamp
|
||||
functionClockResGet = "clock_res_get"
|
||||
|
||||
// importClockResGet is the WebAssembly 1.0 (20191205) Text format import of functionClockResGet.
|
||||
importClockResGet = `(import "wasi_snapshot_preview1" "clock_res_get"
|
||||
(func $wasi.clock_res_get (param $id i32) (param $result.resolution i32) (result (;errno;) i32)))`
|
||||
|
||||
// functionClockTimeGet returns the time value of a clock.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_time_getid-clockid-precision-timestamp---errno-timestamp
|
||||
functionClockTimeGet = "clock_time_get"
|
||||
|
||||
// importClockTimeGet is the WebAssembly 1.0 (20191205) Text format import of functionClockTimeGet.
|
||||
importClockTimeGet = `(import "wasi_snapshot_preview1" "clock_time_get"
|
||||
(func $wasi.clock_time_get (param $id i32) (param $precision i64) (param $result.timestamp i32) (result (;errno;) i32)))`
|
||||
|
||||
// functionFdAdvise provides file advisory information on a file descriptor.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_advisefd-fd-offset-filesize-len-filesize-advice-advice---errno
|
||||
functionFdAdvise = "fd_advise"
|
||||
|
||||
// importFdAdvise is the WebAssembly 1.0 (20191205) Text format import of functionFdAdvise.
|
||||
// importFdAdvise is the WebAssembly 1.0 Text format import of functionFdAdvise.
|
||||
importFdAdvise = `(import "wasi_snapshot_preview1" "fd_advise"
|
||||
(func $wasi.fd_advise (param $fd i32) (param $offset i64) (param $len i64) (param $result.advice i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -141,7 +124,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_allocatefd-fd-offset-filesize-len-filesize---errno
|
||||
functionFdAllocate = "fd_allocate"
|
||||
|
||||
// importFdAllocate is the WebAssembly 1.0 (20191205) Text format import of functionFdAllocate.
|
||||
// importFdAllocate is the WebAssembly 1.0 Text format import of functionFdAllocate.
|
||||
importFdAllocate = `(import "wasi_snapshot_preview1" "fd_allocate"
|
||||
(func $wasi.fd_allocate (param $fd i32) (param $offset i64) (param $len i64) (result (;errno;) i32)))`
|
||||
|
||||
@@ -149,7 +132,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_close
|
||||
functionFdClose = "fd_close"
|
||||
|
||||
// importFdClose is the WebAssembly 1.0 (20191205) Text format import of functionFdClose.
|
||||
// importFdClose is the WebAssembly 1.0 Text format import of functionFdClose.
|
||||
importFdClose = `(import "wasi_snapshot_preview1" "fd_close"
|
||||
(func $wasi.fd_close (param $fd i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -157,7 +140,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_close
|
||||
functionFdDatasync = "fd_datasync"
|
||||
|
||||
// importFdDatasync is the WebAssembly 1.0 (20191205) Text format import of functionFdDatasync.
|
||||
// importFdDatasync is the WebAssembly 1.0 Text format import of functionFdDatasync.
|
||||
importFdDatasync = `(import "wasi_snapshot_preview1" "fd_datasync"
|
||||
(func $wasi.fd_datasync (param $fd i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -165,15 +148,15 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_fdstat_getfd-fd---errno-fdstat
|
||||
functionFdFdstatGet = "fd_fdstat_get"
|
||||
|
||||
// importFdFdstatGet is the WebAssembly 1.0 (20191205) Text format import of functionFdFdstatGet.
|
||||
importFdFdstatGet = `(import "wasi_snapshot_preview1" "fd_fdstat_get"
|
||||
// importFdFdstatGet is the WebAssembly 1.0 Text format import of functionFdFdstatGet.
|
||||
_ = /* importFdFdstatGet */ `(import "wasi_snapshot_preview1" "fd_fdstat_get"
|
||||
(func $wasi.fd_fdstat_get (param $fd i32) (param $result.stat i32) (result (;errno;) i32)))` //nolint
|
||||
|
||||
// functionFdFdstatSetFlags adjusts the flags associated with a file descriptor.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_fdstat_set_flagsfd-fd-flags-fdflags---errno
|
||||
functionFdFdstatSetFlags = "fd_fdstat_set_flags"
|
||||
|
||||
// importFdFdstatSetFlags is the WebAssembly 1.0 (20191205) Text format import of functionFdFdstatSetFlags.
|
||||
// importFdFdstatSetFlags is the WebAssembly 1.0 Text format import of functionFdFdstatSetFlags.
|
||||
importFdFdstatSetFlags = `(import "wasi_snapshot_preview1" "fd_fdstat_set_flags"
|
||||
(func $wasi.fd_fdstat_set_flags (param $fd i32) (param $flags i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -181,7 +164,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_fdstat_set_rightsfd-fd-fs_rights_base-rights-fs_rights_inheriting-rights---errno
|
||||
functionFdFdstatSetRights = "fd_fdstat_set_rights"
|
||||
|
||||
// importFdFdstatSetRights is the WebAssembly 1.0 (20191205) Text format import of functionFdFdstatSetRights.
|
||||
// importFdFdstatSetRights is the WebAssembly 1.0 Text format import of functionFdFdstatSetRights.
|
||||
importFdFdstatSetRights = `(import "wasi_snapshot_preview1" "fd_fdstat_set_rights"
|
||||
(func $wasi.fd_fdstat_set_rights (param $fd i32) (param $fs_rights_base i64) (param $fs_rights_inheriting i64) (result (;errno;) i32)))`
|
||||
|
||||
@@ -189,7 +172,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_filestat_getfd-fd---errno-filestat
|
||||
functionFdFilestatGet = "fd_filestat_get"
|
||||
|
||||
// importFdFilestatGet is the WebAssembly 1.0 (20191205) Text format import of functionFdFilestatGet.
|
||||
// importFdFilestatGet is the WebAssembly 1.0 Text format import of functionFdFilestatGet.
|
||||
importFdFilestatGet = `(import "wasi_snapshot_preview1" "fd_filestat_get"
|
||||
(func $wasi.fd_filestat_get (param $fd i32) (param $result.buf i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -197,7 +180,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_filestat_set_sizefd-fd-size-filesize---errno
|
||||
functionFdFilestatSetSize = "fd_filestat_set_size"
|
||||
|
||||
// importFdFilestatSetSize is the WebAssembly 1.0 (20191205) Text format import of functionFdFilestatSetSize.
|
||||
// importFdFilestatSetSize is the WebAssembly 1.0 Text format import of functionFdFilestatSetSize.
|
||||
importFdFilestatSetSize = `(import "wasi_snapshot_preview1" "fd_filestat_set_size"
|
||||
(func $wasi.fd_filestat_set_size (param $fd i32) (param $size i64) (result (;errno;) i32)))`
|
||||
|
||||
@@ -205,7 +188,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_filestat_set_timesfd-fd-atim-timestamp-mtim-timestamp-fst_flags-fstflags---errno
|
||||
functionFdFilestatSetTimes = "fd_filestat_set_times"
|
||||
|
||||
// importFdFilestatSetTimes is the WebAssembly 1.0 (20191205) Text format import of functionFdFilestatSetTimes.
|
||||
// importFdFilestatSetTimes is the WebAssembly 1.0 Text format import of functionFdFilestatSetTimes.
|
||||
importFdFilestatSetTimes = `(import "wasi_snapshot_preview1" "fd_filestat_set_times"
|
||||
(func $wasi.fd_filestat_set_times (param $fd i32) (param $atim i64) (param $mtim i64) (param $fst_flags i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -213,7 +196,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_preadfd-fd-iovs-iovec_array-offset-filesize---errno-size
|
||||
functionFdPread = "fd_pread"
|
||||
|
||||
// importFdPread is the WebAssembly 1.0 (20191205) Text format import of functionFdPread.
|
||||
// importFdPread is the WebAssembly 1.0 Text format import of functionFdPread.
|
||||
importFdPread = `(import "wasi_snapshot_preview1" "fd_pread"
|
||||
(func $wasi.fd_pread (param $fd i32) (param $iovs i32) (param $iovs_len i32) (param $offset i64) (param $result.nread i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -221,7 +204,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_prestat_get
|
||||
functionFdPrestatGet = "fd_prestat_get"
|
||||
|
||||
// importFdPrestatGet is the WebAssembly 1.0 (20191205) Text format import of functionFdPrestatGet.
|
||||
// importFdPrestatGet is the WebAssembly 1.0 Text format import of functionFdPrestatGet.
|
||||
importFdPrestatGet = `(import "wasi_snapshot_preview1" "fd_prestat_get"
|
||||
(func $wasi.fd_prestat_get (param $fd i32) (param $result.prestat i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -229,7 +212,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_prestat_dir_name
|
||||
functionFdPrestatDirName = "fd_prestat_dir_name"
|
||||
|
||||
// importFdPrestatDirName is the WebAssembly 1.0 (20191205) Text format import of functionFdPrestatDirName.
|
||||
// importFdPrestatDirName is the WebAssembly 1.0 Text format import of functionFdPrestatDirName.
|
||||
importFdPrestatDirName = `(import "wasi_snapshot_preview1" "fd_prestat_dir_name"
|
||||
(func $wasi.fd_prestat_dir_name (param $fd i32) (param $path i32) (param $path_len i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -237,7 +220,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_pwritefd-fd-iovs-ciovec_array-offset-filesize---errno-size
|
||||
functionFdPwrite = "fd_pwrite"
|
||||
|
||||
// importFdPwrite is the WebAssembly 1.0 (20191205) Text format import of functionFdPwrite.
|
||||
// importFdPwrite is the WebAssembly 1.0 Text format import of functionFdPwrite.
|
||||
importFdPwrite = `(import "wasi_snapshot_preview1" "fd_pwrite"
|
||||
(func $wasi.fd_pwrite (param $fd i32) (param $iovs i32) (param $iovs_len i32) (param $offset i64) (param $result.nwritten i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -245,7 +228,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_read
|
||||
functionFdRead = "fd_read"
|
||||
|
||||
// importFdRead is the WebAssembly 1.0 (20191205) Text format import of functionFdRead.
|
||||
// importFdRead is the WebAssembly 1.0 Text format import of functionFdRead.
|
||||
importFdRead = `(import "wasi_snapshot_preview1" "fd_read"
|
||||
(func $wasi.fd_read (param $fd i32) (param $iovs i32) (param $iovs_len i32) (param $result.size i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -253,7 +236,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_readdirfd-fd-buf-pointeru8-buf_len-size-cookie-dircookie---errno-size
|
||||
functionFdReaddir = "fd_readdir"
|
||||
|
||||
// importFdReaddir is the WebAssembly 1.0 (20191205) Text format import of functionFdReaddir.
|
||||
// importFdReaddir is the WebAssembly 1.0 Text format import of functionFdReaddir.
|
||||
importFdReaddir = `(import "wasi_snapshot_preview1" "fd_readdir"
|
||||
(func $wasi.fd_readdir (param $fd i32) (param $buf i32) (param $buf_len i32) (param $cookie i64) (param $result.bufused i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -261,7 +244,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_renumberfd-fd-to-fd---errno
|
||||
functionFdRenumber = "fd_renumber"
|
||||
|
||||
// importFdRenumber is the WebAssembly 1.0 (20191205) Text format import of functionFdRenumber.
|
||||
// importFdRenumber is the WebAssembly 1.0 Text format import of functionFdRenumber.
|
||||
importFdRenumber = `(import "wasi_snapshot_preview1" "fd_renumber"
|
||||
(func $wasi.fd_renumber (param $fd i32) (param $to i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -269,7 +252,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_seekfd-fd-offset-filedelta-whence-whence---errno-filesize
|
||||
functionFdSeek = "fd_seek"
|
||||
|
||||
// importFdSeek is the WebAssembly 1.0 (20191205) Text format import of functionFdSeek.
|
||||
// importFdSeek is the WebAssembly 1.0 Text format import of functionFdSeek.
|
||||
importFdSeek = `(import "wasi_snapshot_preview1" "fd_seek"
|
||||
(func $wasi.fd_seek (param $fd i32) (param $offset i64) (param $whence i32) (param $result.newoffset i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -277,7 +260,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_syncfd-fd---errno
|
||||
functionFdSync = "fd_sync"
|
||||
|
||||
// importFdSync is the WebAssembly 1.0 (20191205) Text format import of functionFdSync.
|
||||
// importFdSync is the WebAssembly 1.0 Text format import of functionFdSync.
|
||||
importFdSync = `(import "wasi_snapshot_preview1" "fd_sync"
|
||||
(func $wasi.fd_sync (param $fd i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -285,7 +268,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_tellfd-fd---errno-filesize
|
||||
functionFdTell = "fd_tell"
|
||||
|
||||
// importFdTell is the WebAssembly 1.0 (20191205) Text format import of functionFdTell.
|
||||
// importFdTell is the WebAssembly 1.0 Text format import of functionFdTell.
|
||||
importFdTell = `(import "wasi_snapshot_preview1" "fd_tell"
|
||||
(func $wasi.fd_tell (param $fd i32) (param $result.offset i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -293,7 +276,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_write
|
||||
functionFdWrite = "fd_write"
|
||||
|
||||
// importFdWrite is the WebAssembly 1.0 (20191205) Text format import of functionFdWrite.
|
||||
// importFdWrite is the WebAssembly 1.0 Text format import of functionFdWrite.
|
||||
importFdWrite = `(import "wasi_snapshot_preview1" "fd_write"
|
||||
(func $wasi.fd_write (param $fd i32) (param $iovs i32) (param $iovs_len i32) (param $result.size i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -301,7 +284,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_create_directoryfd-fd-path-string---errno
|
||||
functionPathCreateDirectory = "path_create_directory"
|
||||
|
||||
// importPathCreateDirectory is the WebAssembly 1.0 (20191205) Text format import of functionPathCreateDirectory.
|
||||
// importPathCreateDirectory is the WebAssembly 1.0 Text format import of functionPathCreateDirectory.
|
||||
importPathCreateDirectory = `(import "wasi_snapshot_preview1" "path_create_directory"
|
||||
(func $wasi.path_create_directory (param $fd i32) (param $path i32) (param $path_len i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -309,7 +292,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_filestat_getfd-fd-flags-lookupflags-path-string---errno-filestat
|
||||
functionPathFilestatGet = "path_filestat_get"
|
||||
|
||||
// importPathFilestatGet is the WebAssembly 1.0 (20191205) Text format import of functionPathFilestatGet.
|
||||
// importPathFilestatGet is the WebAssembly 1.0 Text format import of functionPathFilestatGet.
|
||||
importPathFilestatGet = `(import "wasi_snapshot_preview1" "path_filestat_get"
|
||||
(func $wasi.path_filestat_get (param $fd i32) (param $flags i32) (param $path i32) (param $path_len i32) (param $result.buf i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -317,7 +300,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_filestat_set_timesfd-fd-flags-lookupflags-path-string-atim-timestamp-mtim-timestamp-fst_flags-fstflags---errno
|
||||
functionPathFilestatSetTimes = "path_filestat_set_times"
|
||||
|
||||
// importPathFilestatSetTimes is the WebAssembly 1.0 (20191205) Text format import of functionPathFilestatSetTimes.
|
||||
// importPathFilestatSetTimes is the WebAssembly 1.0 Text format import of functionPathFilestatSetTimes.
|
||||
importPathFilestatSetTimes = `(import "wasi_snapshot_preview1" "path_filestat_set_times"
|
||||
(func $wasi.path_filestat_set_times (param $fd i32) (param $flags i32) (param $path i32) (param $path_len i32) (param $atim i64) (param $mtim i64) (param $fst_flags i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -325,7 +308,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#path_link
|
||||
functionPathLink = "path_link"
|
||||
|
||||
// importPathLink is the WebAssembly 1.0 (20191205) Text format import of functionPathLink.
|
||||
// importPathLink is the WebAssembly 1.0 Text format import of functionPathLink.
|
||||
importPathLink = `(import "wasi_snapshot_preview1" "path_link"
|
||||
(func $wasi.path_link (param $old_fd i32) (param $old_flags i32) (param $old_path i32) (param $old_path_len i32) (param $new_fd i32) (param $new_path i32) (param $new_path_len i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -333,7 +316,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_openfd-fd-dirflags-lookupflags-path-string-oflags-oflags-fs_rights_base-rights-fs_rights_inheriting-rights-fdflags-fdflags---errno-fd
|
||||
functionPathOpen = "path_open"
|
||||
|
||||
// importPathOpen is the WebAssembly 1.0 (20191205) Text format import of functionPathOpen.
|
||||
// importPathOpen is the WebAssembly 1.0 Text format import of functionPathOpen.
|
||||
importPathOpen = `(import "wasi_snapshot_preview1" "path_open"
|
||||
(func $wasi.path_open (param $fd i32) (param $dirflags i32) (param $path i32) (param $path_len i32) (param $oflags i32) (param $fs_rights_base i64) (param $fs_rights_inheriting i64) (param $fdflags i32) (param $result.opened_fd i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -341,7 +324,7 @@ const (
|
||||
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_readlinkfd-fd-path-string-buf-pointeru8-buf_len-size---errno-size
|
||||
functionPathReadlink = "path_readlink"
|
||||
|
||||
// importPathReadlink is the WebAssembly 1.0 (20191205) Text format import of functionPathReadlink.
|
||||
// importPathReadlink is the WebAssembly 1.0 Text format import of functionPathReadlink.
|
||||
importPathReadlink = `(import "wasi_snapshot_preview1" "path_readlink"
|
||||
(func $wasi.path_readlink (param $fd i32) (param $path i32) (param $path_len i32) (param $buf i32) (param $buf_len i32) (param $result.bufused i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -349,7 +332,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_remove_directoryfd-fd-path-string---errno
|
||||
functionPathRemoveDirectory = "path_remove_directory"
|
||||
|
||||
// importPathRemoveDirectory is the WebAssembly 1.0 (20191205) Text format import of functionPathRemoveDirectory.
|
||||
// importPathRemoveDirectory is the WebAssembly 1.0 Text format import of functionPathRemoveDirectory.
|
||||
importPathRemoveDirectory = `(import "wasi_snapshot_preview1" "path_remove_directory"
|
||||
(func $wasi.path_remove_directory (param $fd i32) (param $path i32) (param $path_len i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -357,7 +340,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_renamefd-fd-old_path-string-new_fd-fd-new_path-string---errno
|
||||
functionPathRename = "path_rename"
|
||||
|
||||
// importPathRename is the WebAssembly 1.0 (20191205) Text format import of functionPathRename.
|
||||
// importPathRename is the WebAssembly 1.0 Text format import of functionPathRename.
|
||||
importPathRename = `(import "wasi_snapshot_preview1" "path_rename"
|
||||
(func $wasi.path_rename (param $fd i32) (param $old_path i32) (param $old_path_len i32) (param $new_fd i32) (param $new_path i32) (param $new_path_len i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -365,7 +348,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#path_symlink
|
||||
functionPathSymlink = "path_symlink"
|
||||
|
||||
// importPathSymlink is the WebAssembly 1.0 (20191205) Text format import of functionPathSymlink.
|
||||
// importPathSymlink is the WebAssembly 1.0 Text format import of functionPathSymlink.
|
||||
importPathSymlink = `(import "wasi_snapshot_preview1" "path_symlink"
|
||||
(func $wasi.path_symlink (param $old_path i32) (param $old_path_len i32) (param $fd i32) (param $new_path i32) (param $new_path_len i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -373,15 +356,15 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_unlink_filefd-fd-path-string---errno
|
||||
functionPathUnlinkFile = "path_unlink_file"
|
||||
|
||||
// importPathUnlinkFile is the WebAssembly 1.0 (20191205) Text format import of functionPathUnlinkFile.
|
||||
// importPathUnlinkFile is the WebAssembly 1.0 Text format import of functionPathUnlinkFile.
|
||||
importPathUnlinkFile = `(import "wasi_snapshot_preview1" "path_unlink_file"
|
||||
(func $wasi.path_unlink_file (param $fd i32) (param $path i32) (param $path_len i32) (result (;errno;) i32)))`
|
||||
|
||||
// functionPollOneoff unlinks a file.
|
||||
// functionPollOneoff concurrently polls for the occurrence of a set of events.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-poll_oneoffin-constpointersubscription-out-pointerevent-nsubscriptions-size---errno-size
|
||||
functionPollOneoff = "poll_oneoff"
|
||||
|
||||
// importPollOneoff is the WebAssembly 1.0 (20191205) Text format import of functionPollOneoff.
|
||||
// importPollOneoff is the WebAssembly 1.0 Text format import of functionPollOneoff.
|
||||
importPollOneoff = `(import "wasi_snapshot_preview1" "poll_oneoff"
|
||||
(func $wasi.poll_oneoff (param $in i32) (param $out i32) (param $nsubscriptions i32) (param $result.nevents i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -389,12 +372,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#proc_exit
|
||||
functionProcExit = "proc_exit"
|
||||
|
||||
// importProcExit is the WebAssembly 1.0 (20191205) Text format import of functionProcExit.
|
||||
//
|
||||
// See importProcExit
|
||||
// See wasi.ProcExit
|
||||
// See functionProcExit
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#proc_exit
|
||||
// importProcExit is the WebAssembly 1.0 Text format import of functionProcExit.
|
||||
importProcExit = `(import "wasi_snapshot_preview1" "proc_exit"
|
||||
(func $wasi.proc_exit (param $rval i32)))`
|
||||
|
||||
@@ -402,7 +380,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-proc_raisesig-signal---errno
|
||||
functionProcRaise = "proc_raise"
|
||||
|
||||
// importProcRaise is the WebAssembly 1.0 (20191205) Text format import of functionProcRaise.
|
||||
// importProcRaise is the WebAssembly 1.0 Text format import of functionProcRaise.
|
||||
importProcRaise = `(import "wasi_snapshot_preview1" "proc_raise"
|
||||
(func $wasi.proc_raise (param $sig i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -410,7 +388,7 @@ const (
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sched_yield---errno
|
||||
functionSchedYield = "sched_yield"
|
||||
|
||||
// importSchedYield is the WebAssembly 1.0 (20191205) Text format import of functionSchedYield.
|
||||
// importSchedYield is the WebAssembly 1.0 Text format import of functionSchedYield.
|
||||
importSchedYield = `(import "wasi_snapshot_preview1" "sched_yield"
|
||||
(func $wasi.sched_yield (result (;errno;) i32)))`
|
||||
|
||||
@@ -418,7 +396,7 @@ const (
|
||||
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno
|
||||
functionRandomGet = "random_get"
|
||||
|
||||
// importRandomGet is the WebAssembly 1.0 (20191205) Text format import of functionRandomGet.
|
||||
// importRandomGet is the WebAssembly 1.0 Text format import of functionRandomGet.
|
||||
importRandomGet = `(import "wasi_snapshot_preview1" "random_get"
|
||||
(func $wasi.random_get (param $buf i32) (param $buf_len i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -426,7 +404,7 @@ const (
|
||||
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_recvfd-fd-ri_data-iovec_array-ri_flags-riflags---errno-size-roflags
|
||||
functionSockRecv = "sock_recv"
|
||||
|
||||
// importSockRecv is the WebAssembly 1.0 (20191205) Text format import of functionSockRecv.
|
||||
// importSockRecv is the WebAssembly 1.0 Text format import of functionSockRecv.
|
||||
importSockRecv = `(import "wasi_snapshot_preview1" "sock_recv"
|
||||
(func $wasi.sock_recv (param $fd i32) (param $ri_data i32) (param $ri_data_count i32) (param $ri_flags i32) (param $result.ro_datalen i32) (param $result.ro_flags i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -434,7 +412,7 @@ const (
|
||||
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_sendfd-fd-si_data-ciovec_array-si_flags-siflags---errno-size
|
||||
functionSockSend = "sock_send"
|
||||
|
||||
// importSockSend is the WebAssembly 1.0 (20191205) Text format import of functionSockSend.
|
||||
// importSockSend is the WebAssembly 1.0 Text format import of functionSockSend.
|
||||
importSockSend = `(import "wasi_snapshot_preview1" "sock_send"
|
||||
(func $wasi.sock_send (param $fd i32) (param $si_data i32) (param $si_data_count i32) (param $si_flags i32) (param $result.so_datalen i32) (result (;errno;) i32)))`
|
||||
|
||||
@@ -442,29 +420,35 @@ const (
|
||||
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_shutdownfd-fd-how-sdflags---errno
|
||||
functionSockShutdown = "sock_shutdown"
|
||||
|
||||
// importSockShutdown is the WebAssembly 1.0 (20191205) Text format import of functionSockShutdown.
|
||||
// importSockShutdown is the WebAssembly 1.0 Text format import of functionSockShutdown.
|
||||
importSockShutdown = `(import "wasi_snapshot_preview1" "sock_shutdown"
|
||||
(func $wasi.sock_shutdown (param $fd i32) (param $how i32) (result (;errno;) i32)))`
|
||||
)
|
||||
|
||||
const (
|
||||
fdStdin = iota
|
||||
fdStdout
|
||||
fdStderr
|
||||
)
|
||||
|
||||
// wasi includes all host functions to export for WASI version "wasi_snapshot_preview1".
|
||||
//
|
||||
// ## Translation notes
|
||||
// ### String
|
||||
// WebAssembly 1.0 (20191205) has no string type, so any string input parameter expands to two uint32 parameters: offset
|
||||
// WebAssembly 1.0 has no string type, so any string input parameter expands to two uint32 parameters: offset
|
||||
// and length.
|
||||
//
|
||||
// ### iovec_array
|
||||
// `iovec_array` is encoded as two uin32le values (i32): offset and count.
|
||||
//
|
||||
// ### Result
|
||||
// Each result besides wasi_snapshot_preview1.Errno is always an uint32 parameter. WebAssembly 1.0 (20191205) can have up to one result,
|
||||
// which is already used by wasi_snapshot_preview1.Errno. This forces other results to be parameters. A result parameter is a memory
|
||||
// Each result besides Errno is always an uint32 parameter. WebAssembly 1.0 can have up to one result,
|
||||
// which is already used by Errno. This forces other results to be parameters. A result parameter is a memory
|
||||
// offset to write the result to. As memory offsets are uint32, each parameter representing a result is uint32.
|
||||
//
|
||||
// ### Errno
|
||||
// The WASI specification is sometimes ambiguous resulting in some runtimes interpreting the same function ways.
|
||||
// wasi_snapshot_preview1.Errno mappings are not defined in WASI, yet, so these mappings are best efforts by maintainers. When in doubt
|
||||
// Errno mappings are not defined in WASI, yet, so these mappings are best efforts by maintainers. When in doubt
|
||||
// about portability, first look at /RATIONALE.md and if needed an issue on
|
||||
// https://github.com/WebAssembly/WASI/issues
|
||||
//
|
||||
@@ -554,7 +538,7 @@ func wasiFunctions() map[string]interface{} {
|
||||
// offset that begins "a" --+ |
|
||||
// offset that begins "bc" --+
|
||||
//
|
||||
// Note: importArgsGet shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importArgsGet shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// See ArgsSizesGet
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#args_get
|
||||
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
@@ -585,7 +569,7 @@ func (a *wasi) ArgsGet(ctx context.Context, mod api.Module, argv, argvBuf uint32
|
||||
// resultArgvBufSize --|
|
||||
// len([]byte{'a',0,'b',c',0}) --+
|
||||
//
|
||||
// Note: importArgsSizesGet shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importArgsSizesGet shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// See ArgsGet
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#args_sizes_get
|
||||
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
@@ -624,7 +608,7 @@ func (a *wasi) ArgsSizesGet(ctx context.Context, mod api.Module, resultArgc, res
|
||||
// environ offset for "a=b" --+ |
|
||||
// environ offset for "b=cd" --+
|
||||
//
|
||||
// Note: importEnvironGet shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importEnvironGet shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// See EnvironSizesGet
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#environ_get
|
||||
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
@@ -656,7 +640,7 @@ func (a *wasi) EnvironGet(ctx context.Context, mod api.Module, environ uint32, e
|
||||
// len([]byte{'a','=','b',0, |
|
||||
// 'b','=','c','d',0}) --+
|
||||
//
|
||||
// Note: importEnvironGet shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importEnvironGet shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// See EnvironGet
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#environ_sizes_get
|
||||
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||
@@ -674,87 +658,6 @@ func (a *wasi) EnvironSizesGet(ctx context.Context, mod api.Module, resultEnviro
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
// ClockResGet is the WASI function named functionClockResGet that returns the resolution of time values returned by ClockTimeGet.
|
||||
//
|
||||
// * id - The clock id for which to return the time.
|
||||
// * resultResolution - the offset to write the resolution to mod.Memory
|
||||
// * the resolution is an uint64 little-endian encoding.
|
||||
//
|
||||
// For example, if the resolution is 100ns, this function writes the below to `mod.Memory`:
|
||||
//
|
||||
// uint64le
|
||||
// +-------------------------------------+
|
||||
// | |
|
||||
// []byte{?, 0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ?}
|
||||
// resultResolution --^
|
||||
//
|
||||
// Note: importClockResGet shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: This is similar to `clock_getres` in POSIX.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_res_getid-clockid---errno-timestamp
|
||||
// See https://linux.die.net/man/3/clock_getres
|
||||
func (a *wasi) ClockResGet(ctx context.Context, mod api.Module, id uint32, resultResolution uint32) Errno {
|
||||
sysCtx := getSysCtx(mod)
|
||||
|
||||
var resolution uint64 // ns
|
||||
switch id {
|
||||
case clockIDRealtime:
|
||||
resolution = uint64(sysCtx.WalltimeResolution())
|
||||
case clockIDMonotonic:
|
||||
resolution = uint64(sysCtx.NanotimeResolution())
|
||||
default:
|
||||
// Similar to many other runtimes, we only support realtime and monotonic clocks. Other types
|
||||
// are slated to be removed from the next version of WASI.
|
||||
return ErrnoNosys
|
||||
}
|
||||
if !mod.Memory().WriteUint64Le(ctx, resultResolution, resolution) {
|
||||
return ErrnoFault
|
||||
}
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
// ClockTimeGet is the WASI function named functionClockTimeGet that returns the time value of a clock (time.Now).
|
||||
//
|
||||
// * id - The clock id for which to return the time.
|
||||
// * precision - The maximum lag (exclusive) that the returned time value may have, compared to its actual value.
|
||||
// * resultTimestamp - the offset to write the timestamp to mod.Memory
|
||||
// * the timestamp is epoch nanoseconds encoded as a uint64 little-endian encoding.
|
||||
//
|
||||
// For example, if time.Now returned exactly midnight UTC 2022-01-01 (1640995200000000000), and
|
||||
// parameters resultTimestamp=1, this function writes the below to `mod.Memory`:
|
||||
//
|
||||
// uint64le
|
||||
// +------------------------------------------+
|
||||
// | |
|
||||
// []byte{?, 0x0, 0x0, 0x1f, 0xa6, 0x70, 0xfc, 0xc5, 0x16, ?}
|
||||
// resultTimestamp --^
|
||||
//
|
||||
// Note: importClockTimeGet shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: This is similar to `clock_gettime` in POSIX.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_time_getid-clockid-precision-timestamp---errno-timestamp
|
||||
// See https://linux.die.net/man/3/clock_gettime
|
||||
func (a *wasi) ClockTimeGet(ctx context.Context, mod api.Module, id uint32, precision uint64, resultTimestamp uint32) Errno {
|
||||
// TODO: precision is currently ignored.
|
||||
sysCtx := getSysCtx(mod)
|
||||
|
||||
var val uint64
|
||||
switch id {
|
||||
case clockIDRealtime:
|
||||
sec, nsec := sysCtx.Walltime(ctx)
|
||||
val = (uint64(sec) * uint64(time.Second.Nanoseconds())) + uint64(nsec)
|
||||
case clockIDMonotonic:
|
||||
val = uint64(sysCtx.Nanotime(ctx))
|
||||
default:
|
||||
// Similar to many other runtimes, we only support realtime and monotonic clocks. Other types
|
||||
// are slated to be removed from the next version of WASI.
|
||||
return ErrnoNosys
|
||||
}
|
||||
|
||||
if !mod.Memory().WriteUint64Le(ctx, resultTimestamp, val) {
|
||||
return ErrnoFault
|
||||
}
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
// FdAdvise is the WASI function named functionFdAdvise and is stubbed for GrainLang per #271
|
||||
func (a *wasi) FdAdvise(ctx context.Context, mod api.Module, fd uint32, offset, len uint64, resultAdvice uint32) Errno {
|
||||
return ErrnoNosys // stubbed for GrainLang per #271
|
||||
@@ -769,14 +672,12 @@ func (a *wasi) FdAllocate(ctx context.Context, mod api.Module, fd uint32, offset
|
||||
//
|
||||
// * fd - the file descriptor to close
|
||||
//
|
||||
// Note: importFdClose shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importFdClose shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// Note: This is similar to `close` in POSIX.
|
||||
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_close
|
||||
// See https://linux.die.net/man/3/close
|
||||
func (a *wasi) FdClose(ctx context.Context, mod api.Module, fd uint32) Errno {
|
||||
_, fsc := sysFSCtx(ctx, mod)
|
||||
|
||||
if ok, err := fsc.CloseFile(fd); err != nil {
|
||||
if ok, err := getSysCtx(mod).FS(ctx).CloseFile(fd); err != nil {
|
||||
return ErrnoIo
|
||||
} else if !ok {
|
||||
return ErrnoBadf
|
||||
@@ -795,9 +696,9 @@ func (a *wasi) FdDatasync(ctx context.Context, mod api.Module, fd uint32) Errno
|
||||
// * fd - the file descriptor to get the fdstat attributes data
|
||||
// * resultFdstat - the offset to write the result fdstat data
|
||||
//
|
||||
// The wasi_snapshot_preview1.Errno returned is wasi_snapshot_preview1.ErrnoSuccess except the following error conditions:
|
||||
// * wasi_snapshot_preview1.ErrnoBadf - if `fd` is invalid
|
||||
// * wasi_snapshot_preview1.ErrnoFault - if `resultFdstat` contains an invalid offset due to the memory constraint
|
||||
// The Errno returned is ErrnoSuccess except the following error conditions:
|
||||
// * ErrnoBadf - if `fd` is invalid
|
||||
// * ErrnoFault - if `resultFdstat` contains an invalid offset due to the memory constraint
|
||||
//
|
||||
// fdstat byte layout is 24-byte size, which as the following elements in order
|
||||
// * fs_filetype 1 byte, to indicate the file type
|
||||
@@ -817,15 +718,13 @@ func (a *wasi) FdDatasync(ctx context.Context, mod api.Module, fd uint32) Errno
|
||||
// |
|
||||
// +-- fs_filetype
|
||||
//
|
||||
// Note: importFdFdstatGet shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importFdFdstatGet shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// Note: FdFdstatGet returns similar flags to `fsync(fd, F_GETFL)` in POSIX, as well as additional fields.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fdstat
|
||||
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_fdstat_get
|
||||
// See https://linux.die.net/man/3/fsync
|
||||
func (a *wasi) FdFdstatGet(ctx context.Context, mod api.Module, fd uint32, resultStat uint32) Errno {
|
||||
_, fsc := sysFSCtx(ctx, mod)
|
||||
|
||||
if _, ok := fsc.OpenedFile(fd); !ok {
|
||||
if _, ok := getSysCtx(mod).FS(ctx).OpenedFile(fd); !ok {
|
||||
return ErrnoBadf
|
||||
}
|
||||
return ErrnoSuccess
|
||||
@@ -836,9 +735,9 @@ func (a *wasi) FdFdstatGet(ctx context.Context, mod api.Module, fd uint32, resul
|
||||
// * fd - the file descriptor to get the prestat
|
||||
// * resultPrestat - the offset to write the result prestat data
|
||||
//
|
||||
// The wasi_snapshot_preview1.Errno returned is wasi_snapshot_preview1.ErrnoSuccess except the following error conditions:
|
||||
// * wasi_snapshot_preview1.ErrnoBadf - if `fd` is invalid or the `fd` is not a pre-opened directory.
|
||||
// * wasi_snapshot_preview1.ErrnoFault - if `resultPrestat` is an invalid offset due to the memory constraint
|
||||
// The Errno returned is ErrnoSuccess except the following error conditions:
|
||||
// * ErrnoBadf - if `fd` is invalid or the `fd` is not a pre-opened directory.
|
||||
// * ErrnoFault - if `resultPrestat` is an invalid offset due to the memory constraint
|
||||
//
|
||||
// prestat byte layout is 8 bytes, beginning with an 8-bit tag and 3 pad bytes. The only valid tag is `prestat_dir`,
|
||||
// which is tag zero. This simplifies the byte layout to 4 empty bytes followed by the uint32le encoded path length.
|
||||
@@ -854,14 +753,12 @@ func (a *wasi) FdFdstatGet(ctx context.Context, mod api.Module, fd uint32, resul
|
||||
// tag --+ |
|
||||
// +-- size in bytes of the string "/tmp"
|
||||
//
|
||||
// Note: importFdPrestatGet shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importFdPrestatGet shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// See FdPrestatDirName
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#prestat
|
||||
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_prestat_get
|
||||
func (a *wasi) FdPrestatGet(ctx context.Context, mod api.Module, fd uint32, resultPrestat uint32) Errno {
|
||||
_, fsc := sysFSCtx(ctx, mod)
|
||||
|
||||
entry, ok := fsc.OpenedFile(fd)
|
||||
entry, ok := getSysCtx(mod).FS(ctx).OpenedFile(fd)
|
||||
if !ok {
|
||||
return ErrnoBadf
|
||||
}
|
||||
@@ -916,10 +813,10 @@ func (a *wasi) FdPread(ctx context.Context, mod api.Module, fd, iovs, iovsCount
|
||||
// * pathLen - the count of bytes to write to `path`
|
||||
// * This should match the uint32le FdPrestatGet writes to offset `resultPrestat`+4
|
||||
//
|
||||
// The wasi_snapshot_preview1.Errno returned is wasi_snapshot_preview1.ErrnoSuccess except the following error conditions:
|
||||
// * wasi_snapshot_preview1.ErrnoBadf - if `fd` is invalid
|
||||
// * wasi_snapshot_preview1.ErrnoFault - if `path` is an invalid offset due to the memory constraint
|
||||
// * wasi_snapshot_preview1.ErrnoNametoolong - if `pathLen` is longer than the actual length of the result path
|
||||
// The Errno returned is ErrnoSuccess except the following error conditions:
|
||||
// * ErrnoBadf - if `fd` is invalid
|
||||
// * ErrnoFault - if `path` is an invalid offset due to the memory constraint
|
||||
// * ErrnoNametoolong - if `pathLen` is longer than the actual length of the result path
|
||||
//
|
||||
// For example, the directory name corresponding with `fd` was "/tmp" and
|
||||
// parameters path=1 pathLen=4 (correct), this function will write the below to `mod.Memory`:
|
||||
@@ -930,13 +827,11 @@ func (a *wasi) FdPread(ctx context.Context, mod api.Module, fd, iovs, iovsCount
|
||||
// []byte{?, '/', 't', 'm', 'p', ?}
|
||||
// path --^
|
||||
//
|
||||
// Note: importFdPrestatDirName shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importFdPrestatDirName shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// See FdPrestatGet
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_prestat_dir_name
|
||||
func (a *wasi) FdPrestatDirName(ctx context.Context, mod api.Module, fd uint32, pathPtr uint32, pathLen uint32) Errno {
|
||||
_, fsc := sysFSCtx(ctx, mod)
|
||||
|
||||
f, ok := fsc.OpenedFile(fd)
|
||||
f, ok := getSysCtx(mod).FS(ctx).OpenedFile(fd)
|
||||
if !ok {
|
||||
return ErrnoBadf
|
||||
}
|
||||
@@ -966,10 +861,10 @@ func (a *wasi) FdPwrite(ctx context.Context, mod api.Module, fd, iovs, iovsCount
|
||||
// * iovsCount - the count of memory offset, size pairs to read sequentially starting at iovs.
|
||||
// * resultSize - the offset in `mod.Memory` to write the number of bytes read
|
||||
//
|
||||
// The wasi_snapshot_preview1.Errno returned is wasi_snapshot_preview1.ErrnoSuccess except the following error conditions:
|
||||
// * wasi_snapshot_preview1.ErrnoBadf - if `fd` is invalid
|
||||
// * wasi_snapshot_preview1.ErrnoFault - if `iovs` or `resultSize` contain an invalid offset due to the memory constraint
|
||||
// * wasi_snapshot_preview1.ErrnoIo - if an IO related error happens during the operation
|
||||
// The Errno returned is ErrnoSuccess except the following error conditions:
|
||||
// * ErrnoBadf - if `fd` is invalid
|
||||
// * ErrnoFault - if `iovs` or `resultSize` contain an invalid offset due to the memory constraint
|
||||
// * ErrnoIo - if an IO related error happens during the operation
|
||||
//
|
||||
// For example, this function needs to first read `iovs` to determine where to write contents. If
|
||||
// parameters iovs=1 iovsCount=2, this function reads two offset/length pairs from `mod.Memory`:
|
||||
@@ -995,23 +890,16 @@ func (a *wasi) FdPwrite(ctx context.Context, mod api.Module, fd, iovs, iovsCount
|
||||
// iovs[1].offset --+ |
|
||||
// resultSize --+
|
||||
//
|
||||
// Note: importFdRead shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importFdRead shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// Note: This is similar to `readv` in POSIX.
|
||||
// See FdWrite
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_read
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#iovec
|
||||
// See https://linux.die.net/man/3/readv
|
||||
func (a *wasi) FdRead(ctx context.Context, mod api.Module, fd, iovs, iovsCount, resultSize uint32) Errno {
|
||||
sysCtx, fsCtx := sysFSCtx(ctx, mod)
|
||||
|
||||
var reader io.Reader
|
||||
|
||||
if fd == fdStdin {
|
||||
reader = sysCtx.Stdin()
|
||||
} else if f, ok := fsCtx.OpenedFile(fd); !ok || f.File == nil {
|
||||
reader := fdReader(ctx, mod, fd)
|
||||
if reader == nil {
|
||||
return ErrnoBadf
|
||||
} else {
|
||||
reader = f.File
|
||||
}
|
||||
|
||||
var nread uint32
|
||||
@@ -1063,11 +951,11 @@ func (a *wasi) FdRenumber(ctx context.Context, mod api.Module, fd, to uint32) Er
|
||||
// * If io.SeekEnd, new offset == file size of `fd` + `offset`.
|
||||
// * resultNewoffset: the offset in `mod.Memory` to write the new offset to, relative to start of the file
|
||||
//
|
||||
// The wasi_snapshot_preview1.Errno returned is wasi_snapshot_preview1.ErrnoSuccess except the following error conditions:
|
||||
// * wasi_snapshot_preview1.ErrnoBadf - if `fd` is invalid
|
||||
// * wasi_snapshot_preview1.ErrnoFault - if `resultNewoffset` is an invalid offset in `mod.Memory` due to the memory constraint
|
||||
// * wasi_snapshot_preview1.ErrnoInval - if `whence` is an invalid value
|
||||
// * wasi_snapshot_preview1.ErrnoIo - if other error happens during the operation of the underying file system
|
||||
// The Errno returned is ErrnoSuccess except the following error conditions:
|
||||
// * ErrnoBadf - if `fd` is invalid
|
||||
// * ErrnoFault - if `resultNewoffset` is an invalid offset in `mod.Memory` due to the memory constraint
|
||||
// * ErrnoInval - if `whence` is an invalid value
|
||||
// * ErrnoIo - if other error happens during the operation of the underying file system
|
||||
//
|
||||
// For example, if fd 3 is a file with offset 0, and
|
||||
// parameters fd=3, offset=4, whence=0 (=io.SeekStart), resultNewOffset=1,
|
||||
@@ -1080,16 +968,14 @@ func (a *wasi) FdRenumber(ctx context.Context, mod api.Module, fd, to uint32) Er
|
||||
// resultNewoffset --^
|
||||
//
|
||||
// See io.Seeker
|
||||
// Note: importFdSeek shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importFdSeek shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// Note: This is similar to `lseek` in POSIX.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_seek
|
||||
// See https://linux.die.net/man/3/lseek
|
||||
func (a *wasi) FdSeek(ctx context.Context, mod api.Module, fd uint32, offset uint64, whence uint32, resultNewoffset uint32) Errno {
|
||||
_, fsc := sysFSCtx(ctx, mod)
|
||||
|
||||
var seeker io.Seeker
|
||||
// Check to see if the file descriptor is available
|
||||
if f, ok := fsc.OpenedFile(fd); !ok || f.File == nil {
|
||||
if f, ok := getSysCtx(mod).FS(ctx).OpenedFile(fd); !ok || f.File == nil {
|
||||
return ErrnoBadf
|
||||
// fs.FS doesn't declare io.Seeker, but implementations such as os.File implement it.
|
||||
} else if seeker, ok = f.File.(io.Seeker); !ok {
|
||||
@@ -1129,10 +1015,10 @@ func (a *wasi) FdTell(ctx context.Context, mod api.Module, fd, resultOffset uint
|
||||
// * iovsCount - the count of memory offset, size pairs to read sequentially starting at iovs.
|
||||
// * resultSize - the offset in `mod.Memory` to write the number of bytes written
|
||||
//
|
||||
// The wasi_snapshot_preview1.Errno returned is wasi_snapshot_preview1.ErrnoSuccess except the following error conditions:
|
||||
// * wasi_snapshot_preview1.ErrnoBadf - if `fd` is invalid
|
||||
// * wasi_snapshot_preview1.ErrnoFault - if `iovs` or `resultSize` contain an invalid offset due to the memory constraint
|
||||
// * wasi_snapshot_preview1.ErrnoIo - if an IO related error happens during the operation
|
||||
// The Errno returned is ErrnoSuccess except the following error conditions:
|
||||
// * ErrnoBadf - if `fd` is invalid
|
||||
// * ErrnoFault - if `iovs` or `resultSize` contain an invalid offset due to the memory constraint
|
||||
// * ErrnoIo - if an IO related error happens during the operation
|
||||
//
|
||||
// For example, this function needs to first read `iovs` to determine what to write to `fd`. If
|
||||
// parameters iovs=1 iovsCount=2, this function reads two offset/length pairs from `mod.Memory`:
|
||||
@@ -1164,30 +1050,16 @@ func (a *wasi) FdTell(ctx context.Context, mod api.Module, fd, resultOffset uint
|
||||
// []byte{ 0..24, ?, 6, 0, 0, 0', ? }
|
||||
// resultSize --^
|
||||
//
|
||||
// Note: importFdWrite shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importFdWrite shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// Note: This is similar to `writev` in POSIX.
|
||||
// See FdRead
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#ciovec
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_write
|
||||
// See https://linux.die.net/man/3/writev
|
||||
func (a *wasi) FdWrite(ctx context.Context, mod api.Module, fd, iovs, iovsCount, resultSize uint32) Errno {
|
||||
sysCtx, fsCtx := sysFSCtx(ctx, mod)
|
||||
|
||||
var writer io.Writer
|
||||
|
||||
switch fd {
|
||||
case fdStdout:
|
||||
writer = sysCtx.Stdout()
|
||||
case fdStderr:
|
||||
writer = sysCtx.Stderr()
|
||||
default:
|
||||
// Check to see if the file descriptor is available
|
||||
if f, ok := fsCtx.OpenedFile(fd); !ok || f.File == nil {
|
||||
return ErrnoBadf
|
||||
// fs.FS doesn't declare io.Writer, but implementations such as os.File implement it.
|
||||
} else if writer, ok = f.File.(io.Writer); !ok {
|
||||
return ErrnoBadf
|
||||
}
|
||||
writer := fdWriter(ctx, mod, fd)
|
||||
if writer == nil {
|
||||
return ErrnoBadf
|
||||
}
|
||||
|
||||
var nwritten uint32
|
||||
@@ -1217,6 +1089,39 @@ func (a *wasi) FdWrite(ctx context.Context, mod api.Module, fd, iovs, iovsCount,
|
||||
return ErrnoSuccess
|
||||
}
|
||||
|
||||
// fdReader returns a valid reader for the given file descriptor or nil if ErrnoBadf.
|
||||
func fdReader(ctx context.Context, mod api.Module, fd uint32) io.Reader {
|
||||
sysCtx := getSysCtx(mod)
|
||||
if fd == fdStdin {
|
||||
return sysCtx.Stdin()
|
||||
} else if f, ok := sysCtx.FS(ctx).OpenedFile(fd); !ok || f.File == nil {
|
||||
return nil
|
||||
} else {
|
||||
return f.File
|
||||
}
|
||||
}
|
||||
|
||||
// fdWriter returns a valid writer for the given file descriptor or nil if ErrnoBadf.
|
||||
func fdWriter(ctx context.Context, mod api.Module, fd uint32) io.Writer {
|
||||
sysCtx := getSysCtx(mod)
|
||||
switch fd {
|
||||
case fdStdout:
|
||||
return sysCtx.Stdout()
|
||||
case fdStderr:
|
||||
return sysCtx.Stderr()
|
||||
default:
|
||||
// Check to see if the file descriptor is available
|
||||
if f, ok := sysCtx.FS(ctx).OpenedFile(fd); !ok || f.File == nil {
|
||||
return nil
|
||||
// fs.FS doesn't declare io.Writer, but implementations such as os.File implement it.
|
||||
} else if writer, ok := f.File.(io.Writer); !ok {
|
||||
return nil
|
||||
} else {
|
||||
return writer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PathCreateDirectory is the WASI function named functionPathCreateDirectory
|
||||
func (a *wasi) PathCreateDirectory(ctx context.Context, mod api.Module, fd, path, pathLen uint32) Errno {
|
||||
return ErrnoNosys // stubbed for GrainLang per #271
|
||||
@@ -1250,13 +1155,13 @@ func (a *wasi) PathLink(ctx context.Context, mod api.Module, oldFd, oldFlags, ol
|
||||
// * resultOpenedFd - the offset in `mod.Memory` to write the newly created file descriptor to.
|
||||
// * The result FD value is guaranteed to be less than 2**31
|
||||
//
|
||||
// The wasi_snapshot_preview1.Errno returned is wasi_snapshot_preview1.ErrnoSuccess except the following error conditions:
|
||||
// * wasi_snapshot_preview1.ErrnoBadf - if `fd` is invalid
|
||||
// * wasi_snapshot_preview1.ErrnoFault - if `resultOpenedFd` contains an invalid offset due to the memory constraint
|
||||
// * wasi_snapshot_preview1.ErrnoNoent - if `path` does not exist.
|
||||
// * wasi_snapshot_preview1.ErrnoExist - if `path` exists, while `oFlags` requires that it must not.
|
||||
// * wasi_snapshot_preview1.ErrnoNotdir - if `path` is not a directory, while `oFlags` requires that it must be.
|
||||
// * wasi_snapshot_preview1.ErrnoIo - if other error happens during the operation of the underying file system.
|
||||
// The Errno returned is ErrnoSuccess except the following error conditions:
|
||||
// * ErrnoBadf - if `fd` is invalid
|
||||
// * ErrnoFault - if `resultOpenedFd` contains an invalid offset due to the memory constraint
|
||||
// * ErrnoNoent - if `path` does not exist.
|
||||
// * ErrnoExist - if `path` exists, while `oFlags` requires that it must not.
|
||||
// * ErrnoNotdir - if `path` is not a directory, while `oFlags` requires that it must be.
|
||||
// * ErrnoIo - if other error happens during the operation of the underying file system.
|
||||
//
|
||||
// For example, this function needs to first read `path` to determine the file to open.
|
||||
// If parameters `path` = 1, `pathLen` = 6, and the path is "wazero", PathOpen reads the path from `mod.Memory`:
|
||||
@@ -1276,7 +1181,7 @@ func (a *wasi) PathLink(ctx context.Context, mod api.Module, oldFd, oldFlags, ol
|
||||
// []byte{ 0..6, ?, 5, 0, 0, 0, ?}
|
||||
// resultOpenedFd --^
|
||||
//
|
||||
// Note: importPathOpen shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importPathOpen shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// Note: This is similar to `openat` in POSIX.
|
||||
// Note: The returned file descriptor is not guaranteed to be the lowest-numbered file
|
||||
// Note: Rights will never be implemented per https://github.com/WebAssembly/WASI/issues/469#issuecomment-1045251844
|
||||
@@ -1284,8 +1189,7 @@ func (a *wasi) PathLink(ctx context.Context, mod api.Module, oldFd, oldFlags, ol
|
||||
// See https://linux.die.net/man/3/openat
|
||||
func (a *wasi) PathOpen(ctx context.Context, mod api.Module, fd, dirflags, pathPtr, pathLen, oflags uint32, fsRightsBase,
|
||||
fsRightsInheriting uint64, fdflags, resultOpenedFd uint32) (errno Errno) {
|
||||
_, fsc := sysFSCtx(ctx, mod)
|
||||
|
||||
fsc := getSysCtx(mod).FS(ctx)
|
||||
dir, ok := fsc.OpenedFile(fd)
|
||||
if !ok || dir.FS == nil {
|
||||
return ErrnoBadf
|
||||
@@ -1339,11 +1243,6 @@ func (a *wasi) PathUnlinkFile(ctx context.Context, mod api.Module, fd, path, pat
|
||||
return ErrnoNosys // stubbed for GrainLang per #271
|
||||
}
|
||||
|
||||
// PollOneoff is the WASI function named functionPollOneoff
|
||||
func (a *wasi) PollOneoff(ctx context.Context, mod api.Module, in, out, nsubscriptions, resultNevents uint32) Errno {
|
||||
return ErrnoNosys // stubbed for GrainLang per #271
|
||||
}
|
||||
|
||||
// ProcExit is the WASI function that terminates the execution of the module with an exit code.
|
||||
// An exit code of 0 indicates successful termination. The meanings of other values are not defined by WASI.
|
||||
//
|
||||
@@ -1351,7 +1250,7 @@ func (a *wasi) PollOneoff(ctx context.Context, mod api.Module, in, out, nsubscri
|
||||
//
|
||||
// In wazero, this calls api.Module CloseWithExitCode.
|
||||
//
|
||||
// Note: importProcExit shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importProcExit shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#proc_exit
|
||||
func (a *wasi) ProcExit(ctx context.Context, mod api.Module, exitCode uint32) {
|
||||
_ = mod.CloseWithExitCode(ctx, exitCode)
|
||||
@@ -1380,7 +1279,7 @@ func (a *wasi) SchedYield(mod api.Module) Errno {
|
||||
// []byte{?, 0x53, 0x8c, 0x7f, 0x96, 0xb1, ?}
|
||||
// buf --^
|
||||
//
|
||||
// Note: importRandomGet shows this signature in the WebAssembly 1.0 (20191205) Text Format.
|
||||
// Note: importRandomGet shows this signature in the WebAssembly 1.0 Text Format.
|
||||
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-bufLen-size---errno
|
||||
func (a *wasi) RandomGet(ctx context.Context, mod api.Module, buf uint32, bufLen uint32) (errno Errno) {
|
||||
randSource := getSysCtx(mod).RandSource()
|
||||
@@ -1413,18 +1312,6 @@ func (a *wasi) SockShutdown(ctx context.Context, mod api.Module, fd, how uint32)
|
||||
return ErrnoNosys // stubbed for GrainLang per #271
|
||||
}
|
||||
|
||||
const (
|
||||
fdStdin = 0
|
||||
fdStdout = 1
|
||||
fdStderr = 2
|
||||
)
|
||||
|
||||
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clockid-enumu32
|
||||
const (
|
||||
clockIDRealtime = 0
|
||||
clockIDMonotonic = 1
|
||||
)
|
||||
|
||||
func getSysCtx(mod api.Module) *sys.Context {
|
||||
if internal, ok := mod.(*wasm.CallContext); !ok {
|
||||
panic(fmt.Errorf("unsupported wasm.Module implementation: %v", mod))
|
||||
@@ -1433,22 +1320,6 @@ func getSysCtx(mod api.Module) *sys.Context {
|
||||
}
|
||||
}
|
||||
|
||||
func sysFSCtx(ctx context.Context, mod api.Module) (*sys.Context, *sys.FSContext) {
|
||||
if internal, ok := mod.(*wasm.CallContext); !ok {
|
||||
panic(fmt.Errorf("unsupported wasm.Module implementation: %v", mod))
|
||||
} else {
|
||||
// Override Context when it is passed via context
|
||||
if fsValue := ctx.Value(sys.FSKey{}); fsValue != nil {
|
||||
fsCtx, ok := fsValue.(*sys.FSContext)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("unsupported fs key: %v", fsValue))
|
||||
}
|
||||
return internal.Sys, fsCtx
|
||||
}
|
||||
return internal.Sys, internal.Sys.FS()
|
||||
}
|
||||
}
|
||||
|
||||
func openFileEntry(rootFS fs.FS, pathName string) (*sys.FileEntry, Errno) {
|
||||
f, err := rootFS.Open(pathName)
|
||||
if err != nil {
|
||||
|
||||
@@ -21,11 +21,11 @@ var testMem = &wasm.MemoryInstance{
|
||||
},
|
||||
}
|
||||
|
||||
func Test_EnvironGet(t *testing.T) {
|
||||
sys, err := newSysContext(nil, []string{"a=b", "b=cd"}, nil)
|
||||
func Test_Benchmark_EnvironGet(t *testing.T) {
|
||||
sysCtx, err := newSysContext(nil, []string{"a=b", "b=cd"}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
mod := newModule(make([]byte, 20), sys)
|
||||
mod := newModule(make([]byte, 20), sysCtx)
|
||||
environGet := (&wasi{}).EnvironGet
|
||||
|
||||
require.Equal(t, ErrnoSuccess, environGet(testCtx, mod, 11, 1))
|
||||
@@ -33,7 +33,7 @@ func Test_EnvironGet(t *testing.T) {
|
||||
}
|
||||
|
||||
func Benchmark_EnvironGet(b *testing.B) {
|
||||
sys, err := newSysContext(nil, []string{"a=b", "b=cd"}, nil)
|
||||
sysCtx, err := newSysContext(nil, []string{"a=b", "b=cd"}, nil)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func Benchmark_EnvironGet(b *testing.B) {
|
||||
1, 0, 0, 0, // little endian-encoded offset of "a=b"
|
||||
5, 0, 0, 0, // little endian-encoded offset of "b=cd"
|
||||
0,
|
||||
}, sys)
|
||||
}, sysCtx)
|
||||
|
||||
environGet := (&wasi{}).EnvironGet
|
||||
b.Run("EnvironGet", func(b *testing.B) {
|
||||
|
||||
@@ -37,7 +37,7 @@ var testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary")
|
||||
|
||||
var a = &wasi{}
|
||||
|
||||
func TestSnapshotPreview1_ArgsGet(t *testing.T) {
|
||||
func Test_ArgsGet(t *testing.T) {
|
||||
sysCtx, err := newSysContext([]string{"a", "bc"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -81,7 +81,7 @@ func TestSnapshotPreview1_ArgsGet(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_ArgsGet_Errors(t *testing.T) {
|
||||
func Test_ArgsGet_Errors(t *testing.T) {
|
||||
sysCtx, err := newSysContext([]string{"a", "bc"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -131,7 +131,7 @@ func TestSnapshotPreview1_ArgsGet_Errors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_ArgsSizesGet(t *testing.T) {
|
||||
func Test_ArgsSizesGet(t *testing.T) {
|
||||
sysCtx, err := newSysContext([]string{"a", "bc"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -174,7 +174,7 @@ func TestSnapshotPreview1_ArgsSizesGet(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_ArgsSizesGet_Errors(t *testing.T) {
|
||||
func Test_ArgsSizesGet_Errors(t *testing.T) {
|
||||
sysCtx, err := newSysContext([]string{"a", "bc"}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -221,7 +221,7 @@ func TestSnapshotPreview1_ArgsSizesGet_Errors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_EnvironGet(t *testing.T) {
|
||||
func Test_EnvironGet(t *testing.T) {
|
||||
sysCtx, err := newSysContext(nil, []string{"a=b", "b=cd"}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -266,7 +266,7 @@ func TestSnapshotPreview1_EnvironGet(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_EnvironGet_Errors(t *testing.T) {
|
||||
func Test_EnvironGet_Errors(t *testing.T) {
|
||||
sysCtx, err := newSysContext(nil, []string{"a=bc", "b=cd"}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -315,7 +315,7 @@ func TestSnapshotPreview1_EnvironGet_Errors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_EnvironSizesGet(t *testing.T) {
|
||||
func Test_EnvironSizesGet(t *testing.T) {
|
||||
sysCtx, err := newSysContext(nil, []string{"a=b", "b=cd"}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -358,7 +358,7 @@ func TestSnapshotPreview1_EnvironSizesGet(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_EnvironSizesGet_Errors(t *testing.T) {
|
||||
func Test_EnvironSizesGet_Errors(t *testing.T) {
|
||||
sysCtx, err := newSysContext(nil, []string{"a=b", "b=cd"}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -405,268 +405,8 @@ func TestSnapshotPreview1_EnvironSizesGet_Errors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_ClockResGet only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_ClockResGet(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionClockResGet, importClockResGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
resultResolution := uint32(1) // arbitrary offset
|
||||
|
||||
expectedMemoryMicro := []byte{
|
||||
'?', // resultResolution is after this
|
||||
0xe8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // little endian-encoded resolution (fixed to 1000).
|
||||
'?', // stopped after encoding
|
||||
}
|
||||
|
||||
expectedMemoryNano := []byte{
|
||||
'?', // resultResolution is after this
|
||||
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // little endian-encoded resolution (fixed to 1000).
|
||||
'?', // stopped after encoding
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
clockID uint64
|
||||
expectedMemory []byte
|
||||
invocation func(clockID uint64) Errno
|
||||
}{
|
||||
{
|
||||
name: "wasi.ClockResGet",
|
||||
clockID: 0,
|
||||
expectedMemory: expectedMemoryMicro,
|
||||
invocation: func(clockID uint64) Errno {
|
||||
return a.ClockResGet(testCtx, mod, uint32(clockID), resultResolution)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "wasi.ClockResGet",
|
||||
clockID: 1,
|
||||
expectedMemory: expectedMemoryNano,
|
||||
invocation: func(clockID uint64) Errno {
|
||||
return a.ClockResGet(testCtx, mod, uint32(clockID), resultResolution)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: functionClockResGet,
|
||||
clockID: 0,
|
||||
expectedMemory: expectedMemoryMicro,
|
||||
invocation: func(clockID uint64) Errno {
|
||||
results, err := fn.Call(testCtx, clockID, uint64(resultResolution))
|
||||
require.NoError(t, err)
|
||||
return Errno(results[0]) // results[0] is the errno
|
||||
},
|
||||
},
|
||||
{
|
||||
name: functionClockResGet,
|
||||
clockID: 1,
|
||||
expectedMemory: expectedMemoryNano,
|
||||
invocation: func(clockID uint64) Errno {
|
||||
results, err := fn.Call(testCtx, clockID, uint64(resultResolution))
|
||||
require.NoError(t, err)
|
||||
return Errno(results[0]) // results[0] is the errno
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
|
||||
t.Run(fmt.Sprintf("%v/clockID=%v", tc.name, tc.clockID), func(t *testing.T) {
|
||||
maskMemory(t, testCtx, mod, len(tc.expectedMemory))
|
||||
|
||||
errno := tc.invocation(tc.clockID)
|
||||
require.Equal(t, ErrnoSuccess, errno, ErrnoName(errno))
|
||||
|
||||
actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(tc.expectedMemory)))
|
||||
require.True(t, ok)
|
||||
require.Equal(t, tc.expectedMemory, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_ClockResGet_Unsupported(t *testing.T) {
|
||||
resultResolution := uint32(1) // arbitrary offset
|
||||
mod, fn := instantiateModule(testCtx, t, functionClockResGet, importClockResGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
clockID uint64
|
||||
}{
|
||||
{
|
||||
name: "process cputime",
|
||||
clockID: 2,
|
||||
},
|
||||
{
|
||||
name: "thread cputime",
|
||||
clockID: 3,
|
||||
},
|
||||
{
|
||||
name: "undefined",
|
||||
clockID: 100,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
results, err := fn.Call(testCtx, tc.clockID, uint64(resultResolution))
|
||||
require.NoError(t, err)
|
||||
errno := Errno(results[0]) // results[0] is the errno
|
||||
require.Equal(t, ErrnoNosys, errno, ErrnoName(errno))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_ClockTimeGet(t *testing.T) {
|
||||
resultTimestamp := uint32(1) // arbitrary offset
|
||||
|
||||
mod, fn := instantiateModule(testCtx, t, functionClockTimeGet, importClockTimeGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
clocks := []struct {
|
||||
clock string
|
||||
id uint32
|
||||
expectedMemory []byte
|
||||
}{
|
||||
{
|
||||
clock: "Realtime",
|
||||
id: clockIDRealtime,
|
||||
expectedMemory: []byte{
|
||||
'?', // resultTimestamp is after this
|
||||
0x0, 0x0, 0x1f, 0xa6, 0x70, 0xfc, 0xc5, 0x16, // little endian-encoded epochNanos
|
||||
'?', // stopped after encoding
|
||||
},
|
||||
},
|
||||
{
|
||||
clock: "Monotonic",
|
||||
id: clockIDMonotonic,
|
||||
expectedMemory: []byte{
|
||||
'?', // resultTimestamp is after this
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // fake nanotime starts at zero
|
||||
'?', // stopped after encoding
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range clocks {
|
||||
cc := c
|
||||
t.Run(cc.clock, func(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
invocation func() Errno
|
||||
}{
|
||||
{
|
||||
name: "wasi.ClockTimeGet",
|
||||
invocation: func() Errno {
|
||||
return a.ClockTimeGet(testCtx, mod, cc.id, 0 /* TODO: precision */, resultTimestamp)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: functionClockTimeGet,
|
||||
invocation: func() Errno {
|
||||
results, err := fn.Call(testCtx, uint64(cc.id), 0 /* TODO: precision */, uint64(resultTimestamp))
|
||||
require.NoError(t, err)
|
||||
errno := Errno(results[0]) // results[0] is the errno
|
||||
return errno
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Reset the fake clock
|
||||
sysCtx, err := newSysContext(nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
mod.(*wasm.CallContext).Sys = sysCtx
|
||||
|
||||
maskMemory(t, testCtx, mod, len(cc.expectedMemory))
|
||||
|
||||
errno := tc.invocation()
|
||||
require.Zero(t, errno, ErrnoName(errno))
|
||||
|
||||
actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(cc.expectedMemory)))
|
||||
require.True(t, ok)
|
||||
require.Equal(t, cc.expectedMemory, actual)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_ClockTimeGet_Unsupported(t *testing.T) {
|
||||
resultTimestamp := uint32(1) // arbitrary offset
|
||||
mod, fn := instantiateModule(testCtx, t, functionClockTimeGet, importClockTimeGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
clockID uint64
|
||||
}{
|
||||
{
|
||||
name: "process cputime",
|
||||
clockID: 2,
|
||||
},
|
||||
{
|
||||
name: "thread cputime",
|
||||
clockID: 3,
|
||||
},
|
||||
{
|
||||
name: "undefined",
|
||||
clockID: 100,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
results, err := fn.Call(testCtx, tc.clockID, 0 /* TODO: precision */, uint64(resultTimestamp))
|
||||
require.NoError(t, err)
|
||||
errno := Errno(results[0]) // results[0] is the errno
|
||||
require.Equal(t, ErrnoNosys, errno, ErrnoName(errno))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_ClockTimeGet_Errors(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionClockTimeGet, importClockTimeGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
memorySize := mod.Memory().Size(testCtx)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
resultTimestamp uint32
|
||||
argvBufSize uint32
|
||||
}{
|
||||
{
|
||||
name: "resultTimestamp out-of-memory",
|
||||
resultTimestamp: memorySize,
|
||||
},
|
||||
|
||||
{
|
||||
name: "resultTimestamp exceeds the maximum valid address by 1",
|
||||
resultTimestamp: memorySize - 4 + 1, // 4 is the size of uint32, the type of the count of args
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tc := tt
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
results, err := fn.Call(testCtx, 0 /* TODO: id */, 0 /* TODO: precision */, uint64(tc.resultTimestamp))
|
||||
require.NoError(t, err)
|
||||
errno := Errno(results[0]) // results[0] is the errno
|
||||
require.Equal(t, ErrnoFault, errno, ErrnoName(errno))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdAdvise only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdAdvise(t *testing.T) {
|
||||
// Test_FdAdvise only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdAdvise(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdAdvise, importFdAdvise, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -683,8 +423,8 @@ func TestSnapshotPreview1_FdAdvise(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdAllocate only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdAllocate(t *testing.T) {
|
||||
// Test_FdAllocate only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdAllocate(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdAllocate, importFdAllocate, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -701,7 +441,7 @@ func TestSnapshotPreview1_FdAllocate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_FdClose(t *testing.T) {
|
||||
func Test_FdClose(t *testing.T) {
|
||||
fdToClose := uint32(3) // arbitrary fd
|
||||
fdToKeep := uint32(4) // another arbitrary fd
|
||||
|
||||
@@ -726,7 +466,7 @@ func TestSnapshotPreview1_FdClose(t *testing.T) {
|
||||
|
||||
verify := func(mod api.Module) {
|
||||
// Verify fdToClose is closed and removed from the opened FDs.
|
||||
_, fsc := sysFSCtx(testCtx, mod)
|
||||
fsc := getSysCtx(mod).FS(testCtx)
|
||||
_, ok := fsc.OpenedFile(fdToClose)
|
||||
require.False(t, ok)
|
||||
|
||||
@@ -764,8 +504,8 @@ func TestSnapshotPreview1_FdClose(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdDatasync only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdDatasync(t *testing.T) {
|
||||
// Test_FdDatasync only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdDatasync(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdDatasync, importFdDatasync, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -782,14 +522,10 @@ func TestSnapshotPreview1_FdDatasync(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: TestSnapshotPreview1_FdFdstatGet TestSnapshotPreview1_FdFdstatGet_Errors
|
||||
func TestSnapshotPreview1_FdFdstatGet(t *testing.T) {
|
||||
t.Skip("TODO")
|
||||
_ = importFdFdstatGet // stop linter complaint until we implement this
|
||||
}
|
||||
// TODO: Test_FdFdstatGet Test_FdFdstatGet_Errors
|
||||
|
||||
// TestSnapshotPreview1_FdFdstatSetFlags only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdFdstatSetFlags(t *testing.T) {
|
||||
// Test_FdFdstatSetFlags only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdFdstatSetFlags(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdFdstatSetFlags, importFdFdstatSetFlags, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -806,8 +542,8 @@ func TestSnapshotPreview1_FdFdstatSetFlags(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdFdstatSetRights only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdFdstatSetRights(t *testing.T) {
|
||||
// Test_FdFdstatSetRights only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdFdstatSetRights(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdFdstatSetRights, importFdFdstatSetRights, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -824,8 +560,8 @@ func TestSnapshotPreview1_FdFdstatSetRights(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdFilestatGet only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdFilestatGet(t *testing.T) {
|
||||
// Test_FdFilestatGet only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdFilestatGet(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdFilestatGet, importFdFilestatGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -842,8 +578,8 @@ func TestSnapshotPreview1_FdFilestatGet(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdFilestatSetSize only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdFilestatSetSize(t *testing.T) {
|
||||
// Test_FdFilestatSetSize only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdFilestatSetSize(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdFilestatSetSize, importFdFilestatSetSize, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -860,8 +596,8 @@ func TestSnapshotPreview1_FdFilestatSetSize(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdFilestatSetTimes only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdFilestatSetTimes(t *testing.T) {
|
||||
// Test_FdFilestatSetTimes only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdFilestatSetTimes(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdFilestatSetTimes, importFdFilestatSetTimes, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -878,8 +614,8 @@ func TestSnapshotPreview1_FdFilestatSetTimes(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdPread only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdPread(t *testing.T) {
|
||||
// Test_FdPread only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdPread(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdPread, importFdPread, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -896,7 +632,7 @@ func TestSnapshotPreview1_FdPread(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_FdPrestatGet(t *testing.T) {
|
||||
func Test_FdPrestatGet(t *testing.T) {
|
||||
fd := uint32(3) // arbitrary fd after 0, 1, and 2, that are stdin/out/err
|
||||
|
||||
pathName := "/tmp"
|
||||
@@ -941,7 +677,7 @@ func TestSnapshotPreview1_FdPrestatGet(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_FdPrestatGet_Errors(t *testing.T) {
|
||||
func Test_FdPrestatGet_Errors(t *testing.T) {
|
||||
fd := uint32(3) // fd 3 will be opened for the "/tmp" directory after 0, 1, and 2, that are stdin/out/err
|
||||
validAddress := uint32(0) // Arbitrary valid address as arguments to fd_prestat_get. We chose 0 here.
|
||||
|
||||
@@ -984,7 +720,7 @@ func TestSnapshotPreview1_FdPrestatGet_Errors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_FdPrestatDirName(t *testing.T) {
|
||||
func Test_FdPrestatDirName(t *testing.T) {
|
||||
fd := uint32(3) // arbitrary fd after 0, 1, and 2, that are stdin/out/err
|
||||
|
||||
sysCtx, err := newSysContext(nil, nil, map[uint32]*internalsys.FileEntry{fd: {Path: "/tmp"}})
|
||||
@@ -1026,7 +762,7 @@ func TestSnapshotPreview1_FdPrestatDirName(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_FdPrestatDirName_Errors(t *testing.T) {
|
||||
func Test_FdPrestatDirName_Errors(t *testing.T) {
|
||||
fd := uint32(3) // arbitrary fd after 0, 1, and 2, that are stdin/out/err
|
||||
sysCtx, err := newSysContext(nil, nil, map[uint32]*internalsys.FileEntry{fd: {Path: "/tmp"}})
|
||||
require.NoError(t, err)
|
||||
@@ -1086,8 +822,8 @@ func TestSnapshotPreview1_FdPrestatDirName_Errors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdPwrite only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdPwrite(t *testing.T) {
|
||||
// Test_FdPwrite only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdPwrite(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdPwrite, importFdPwrite, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1104,7 +840,7 @@ func TestSnapshotPreview1_FdPwrite(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_FdRead(t *testing.T) {
|
||||
func Test_FdRead(t *testing.T) {
|
||||
fd := uint32(3) // arbitrary fd after 0, 1, and 2, that are stdin/out/err
|
||||
iovs := uint32(1) // arbitrary offset
|
||||
initialMemory := []byte{
|
||||
@@ -1127,7 +863,7 @@ func TestSnapshotPreview1_FdRead(t *testing.T) {
|
||||
'?',
|
||||
)
|
||||
|
||||
// TestSnapshotPreview1_FdRead uses a matrix because setting up test files is complicated and has to be clean each time.
|
||||
// Test_FdRead uses a matrix because setting up test files is complicated and has to be clean each time.
|
||||
type fdReadFn func(ctx context.Context, mod api.Module, fd, iovs, iovsCount, resultSize uint32) Errno
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1173,7 +909,7 @@ func TestSnapshotPreview1_FdRead(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_FdRead_Errors(t *testing.T) {
|
||||
func Test_FdRead_Errors(t *testing.T) {
|
||||
validFD := uint32(3) // arbitrary valid fd after 0, 1, and 2, that are stdin/out/err
|
||||
file, testFS := createFile(t, "test_path", []byte{}) // file with empty contents
|
||||
|
||||
@@ -1265,8 +1001,8 @@ func TestSnapshotPreview1_FdRead_Errors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdReaddir only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdReaddir(t *testing.T) {
|
||||
// Test_FdReaddir only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdReaddir(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdReaddir, importFdReaddir, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1283,8 +1019,8 @@ func TestSnapshotPreview1_FdReaddir(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdRenumber only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdRenumber(t *testing.T) {
|
||||
// Test_FdRenumber only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdRenumber(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdRenumber, importFdRenumber, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1301,7 +1037,7 @@ func TestSnapshotPreview1_FdRenumber(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_FdSeek(t *testing.T) {
|
||||
func Test_FdSeek(t *testing.T) {
|
||||
fd := uint32(3) // arbitrary fd after 0, 1, and 2, that are stdin/out/err
|
||||
resultNewoffset := uint32(1) // arbitrary offset in `ctx.Memory` for the new offset value
|
||||
file, testFS := createFile(t, "test_path", []byte("wazero")) // arbitrary non-empty contents
|
||||
@@ -1311,12 +1047,12 @@ func TestSnapshotPreview1_FdSeek(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
fsCtx := sysCtx.FS()
|
||||
fsCtx := sysCtx.FS(testCtx)
|
||||
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdSeek, importFdSeek, sysCtx)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
// TestSnapshotPreview1_FdSeek uses a matrix because setting up test files is complicated and has to be clean each time.
|
||||
// Test_FdSeek uses a matrix because setting up test files is complicated and has to be clean each time.
|
||||
type fdSeekFn func(ctx context.Context, mod api.Module, fd uint32, offset uint64, whence, resultNewOffset uint32) Errno
|
||||
seekFns := []struct {
|
||||
name string
|
||||
@@ -1410,7 +1146,7 @@ func TestSnapshotPreview1_FdSeek(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_FdSeek_Errors(t *testing.T) {
|
||||
func Test_FdSeek_Errors(t *testing.T) {
|
||||
validFD := uint32(3) // arbitrary valid fd after 0, 1, and 2, that are stdin/out/err
|
||||
file, testFS := createFile(t, "test_path", []byte("wazero")) // arbitrary valid file with non-empty contents
|
||||
|
||||
@@ -1460,8 +1196,8 @@ func TestSnapshotPreview1_FdSeek_Errors(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdSync only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdSync(t *testing.T) {
|
||||
// Test_FdSync only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdSync(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdSync, importFdSync, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1478,8 +1214,8 @@ func TestSnapshotPreview1_FdSync(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_FdTell only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_FdTell(t *testing.T) {
|
||||
// Test_FdTell only tests it is stubbed for GrainLang per #271
|
||||
func Test_FdTell(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionFdTell, importFdTell, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1496,7 +1232,7 @@ func TestSnapshotPreview1_FdTell(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_FdWrite(t *testing.T) {
|
||||
func Test_FdWrite(t *testing.T) {
|
||||
fd := uint32(3) // arbitrary fd after 0, 1, and 2, that are stdin/out/err
|
||||
iovs := uint32(1) // arbitrary offset
|
||||
initialMemory := []byte{
|
||||
@@ -1519,7 +1255,7 @@ func TestSnapshotPreview1_FdWrite(t *testing.T) {
|
||||
'?',
|
||||
)
|
||||
|
||||
// TestSnapshotPreview1_FdWrite uses a matrix because setting up test files is complicated and has to be clean each time.
|
||||
// Test_FdWrite uses a matrix because setting up test files is complicated and has to be clean each time.
|
||||
type fdWriteFn func(ctx context.Context, mod api.Module, fd, iovs, iovsCount, resultSize uint32) Errno
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1573,7 +1309,7 @@ func TestSnapshotPreview1_FdWrite(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_FdWrite_Errors(t *testing.T) {
|
||||
func Test_FdWrite_Errors(t *testing.T) {
|
||||
validFD := uint32(3) // arbitrary valid fd after 0, 1, and 2, that are stdin/out/err
|
||||
|
||||
tmpDir := t.TempDir() // open before loop to ensure no locking problems.
|
||||
@@ -1651,8 +1387,8 @@ func TestSnapshotPreview1_FdWrite_Errors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_PathCreateDirectory only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_PathCreateDirectory(t *testing.T) {
|
||||
// Test_PathCreateDirectory only tests it is stubbed for GrainLang per #271
|
||||
func Test_PathCreateDirectory(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionPathCreateDirectory, importPathCreateDirectory, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1669,8 +1405,8 @@ func TestSnapshotPreview1_PathCreateDirectory(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_PathFilestatGet only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_PathFilestatGet(t *testing.T) {
|
||||
// Test_PathFilestatGet only tests it is stubbed for GrainLang per #271
|
||||
func Test_PathFilestatGet(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionPathFilestatGet, importPathFilestatGet, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1687,8 +1423,8 @@ func TestSnapshotPreview1_PathFilestatGet(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_PathFilestatSetTimes only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_PathFilestatSetTimes(t *testing.T) {
|
||||
// Test_PathFilestatSetTimes only tests it is stubbed for GrainLang per #271
|
||||
func Test_PathFilestatSetTimes(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionPathFilestatSetTimes, importPathFilestatSetTimes, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1705,8 +1441,8 @@ func TestSnapshotPreview1_PathFilestatSetTimes(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_PathLink only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_PathLink(t *testing.T) {
|
||||
// Test_PathLink only tests it is stubbed for GrainLang per #271
|
||||
func Test_PathLink(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionPathLink, importPathLink, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1723,7 +1459,7 @@ func TestSnapshotPreview1_PathLink(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_PathOpen(t *testing.T) {
|
||||
func Test_PathOpen(t *testing.T) {
|
||||
type pathOpenArgs struct {
|
||||
fd uint32
|
||||
dirflags uint32
|
||||
@@ -1780,7 +1516,7 @@ func TestSnapshotPreview1_PathOpen(t *testing.T) {
|
||||
require.Equal(t, expectedMemory, actual)
|
||||
|
||||
// verify the file was actually opened
|
||||
_, fsc := sysFSCtx(ctx, mod)
|
||||
fsc := getSysCtx(mod).FS(ctx)
|
||||
f, ok := fsc.OpenedFile(expectedFD)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, pathName, f.Path)
|
||||
@@ -1832,7 +1568,7 @@ func TestSnapshotPreview1_PathOpen(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_PathOpen_Errors(t *testing.T) {
|
||||
func Test_PathOpen_Errors(t *testing.T) {
|
||||
validFD := uint32(3) // arbitrary valid fd after 0, 1, and 2, that are stdin/out/err
|
||||
pathName := "wazero"
|
||||
testFS := fstest.MapFS{pathName: &fstest.MapFile{Mode: os.ModeDir}}
|
||||
@@ -1899,8 +1635,8 @@ func TestSnapshotPreview1_PathOpen_Errors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_PathReadlink only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_PathReadlink(t *testing.T) {
|
||||
// Test_PathReadlink only tests it is stubbed for GrainLang per #271
|
||||
func Test_PathReadlink(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionPathReadlink, importPathReadlink, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1917,8 +1653,8 @@ func TestSnapshotPreview1_PathReadlink(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_PathRemoveDirectory only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_PathRemoveDirectory(t *testing.T) {
|
||||
// Test_PathRemoveDirectory only tests it is stubbed for GrainLang per #271
|
||||
func Test_PathRemoveDirectory(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionPathRemoveDirectory, importPathRemoveDirectory, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1935,8 +1671,8 @@ func TestSnapshotPreview1_PathRemoveDirectory(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_PathRename only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_PathRename(t *testing.T) {
|
||||
// Test_PathRename only tests it is stubbed for GrainLang per #271
|
||||
func Test_PathRename(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionPathRename, importPathRename, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1953,8 +1689,8 @@ func TestSnapshotPreview1_PathRename(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_PathSymlink only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_PathSymlink(t *testing.T) {
|
||||
// Test_PathSymlink only tests it is stubbed for GrainLang per #271
|
||||
func Test_PathSymlink(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionPathSymlink, importPathSymlink, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1971,8 +1707,8 @@ func TestSnapshotPreview1_PathSymlink(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_PathUnlinkFile only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_PathUnlinkFile(t *testing.T) {
|
||||
// Test_PathUnlinkFile only tests it is stubbed for GrainLang per #271
|
||||
func Test_PathUnlinkFile(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionPathUnlinkFile, importPathUnlinkFile, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -1989,25 +1725,7 @@ func TestSnapshotPreview1_PathUnlinkFile(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_PollOneoff only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_PollOneoff(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionPollOneoff, importPollOneoff, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
t.Run("wasi.PollOneoff", func(t *testing.T) {
|
||||
errno := a.PollOneoff(testCtx, mod, 0, 0, 0, 0)
|
||||
require.Equal(t, ErrnoNosys, errno, ErrnoName(errno))
|
||||
})
|
||||
|
||||
t.Run(functionPollOneoff, func(t *testing.T) {
|
||||
results, err := fn.Call(testCtx, 0, 0, 0, 0)
|
||||
require.NoError(t, err)
|
||||
errno := Errno(results[0]) // results[0] is the errno
|
||||
require.Equal(t, ErrnoNosys, errno, ErrnoName(errno))
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_ProcExit(t *testing.T) {
|
||||
func Test_ProcExit(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
exitCode uint32
|
||||
@@ -2038,8 +1756,8 @@ func TestSnapshotPreview1_ProcExit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_ProcRaise only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_ProcRaise(t *testing.T) {
|
||||
// Test_ProcRaise only tests it is stubbed for GrainLang per #271
|
||||
func Test_ProcRaise(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionProcRaise, importProcRaise, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -2056,8 +1774,8 @@ func TestSnapshotPreview1_ProcRaise(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_SchedYield only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_SchedYield(t *testing.T) {
|
||||
// Test_SchedYield only tests it is stubbed for GrainLang per #271
|
||||
func Test_SchedYield(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionSchedYield, importSchedYield, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -2074,7 +1792,7 @@ func TestSnapshotPreview1_SchedYield(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_RandomGet(t *testing.T) {
|
||||
func Test_RandomGet(t *testing.T) {
|
||||
expectedMemory := []byte{
|
||||
'?', // `offset` is after this
|
||||
0x53, 0x8c, 0x7f, 0x96, 0xb1, // random data from seed value of 42
|
||||
@@ -2116,7 +1834,7 @@ func TestSnapshotPreview1_RandomGet(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_RandomGet_Errors(t *testing.T) {
|
||||
func Test_RandomGet_Errors(t *testing.T) {
|
||||
validAddress := uint32(0) // arbitrary valid address
|
||||
|
||||
mod, _ := instantiateModule(testCtx, t, functionRandomGet, importRandomGet, nil)
|
||||
@@ -2152,7 +1870,7 @@ func TestSnapshotPreview1_RandomGet_Errors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSnapshotPreview1_RandomGet_SourceError(t *testing.T) {
|
||||
func Test_RandomGet_SourceError(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
randSource io.Reader
|
||||
@@ -2180,6 +1898,7 @@ func TestSnapshotPreview1_RandomGet_SourceError(t *testing.T) {
|
||||
tc.randSource,
|
||||
nil, 0,
|
||||
nil, 0,
|
||||
nil, // nanosleep
|
||||
nil,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@@ -2193,8 +1912,8 @@ func TestSnapshotPreview1_RandomGet_SourceError(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_SockRecv only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_SockRecv(t *testing.T) {
|
||||
// Test_SockRecv only tests it is stubbed for GrainLang per #271
|
||||
func Test_SockRecv(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionSockRecv, importSockRecv, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -2211,8 +1930,8 @@ func TestSnapshotPreview1_SockRecv(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_SockSend only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_SockSend(t *testing.T) {
|
||||
// Test_SockSend only tests it is stubbed for GrainLang per #271
|
||||
func Test_SockSend(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionSockSend, importSockSend, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -2229,8 +1948,8 @@ func TestSnapshotPreview1_SockSend(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSnapshotPreview1_SockShutdown only tests it is stubbed for GrainLang per #271
|
||||
func TestSnapshotPreview1_SockShutdown(t *testing.T) {
|
||||
// Test_SockShutdown only tests it is stubbed for GrainLang per #271
|
||||
func Test_SockShutdown(t *testing.T) {
|
||||
mod, fn := instantiateModule(testCtx, t, functionSockShutdown, importSockShutdown, nil)
|
||||
defer mod.Close(testCtx)
|
||||
|
||||
@@ -2300,6 +2019,7 @@ func newSysContext(args, environ []string, openedFiles map[uint32]*internalsys.F
|
||||
deterministicRandomSource(),
|
||||
nil, 0,
|
||||
nil, 0,
|
||||
nil, // nanosleep
|
||||
openedFiles,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user