-
Notifications
You must be signed in to change notification settings - Fork 851
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
builder, src/runtime, targets, tests/wasm: prototype WebAssembly reac…
…tor mode The entrypoint for a WebAssembly reactor module is _initialize instead of _start. Assuming that the WebAssembly runtime is not reentrant (e.g. not threaded), then this works if the //go:wasmexport calls are detected and wrapped in a function that starts the Go scheduler. When the exported function ends, all other goroutines are paused. Goroutines started in a global init() function will run while the host has called into the guest. They are paused when the guest call returns and restarted on the next call. TODO: figure out how to enable reactor mode: 1. Should it be a flag to tinygo build? 2. Should it be a build tag (e.g. -tags reactor)? 3. Should the compiler detect the omission of main.main and automatically enable reactor mode? TODO: figure out where best to wrap //go:wasmexport calls. WIP
- Loading branch information
Showing
10 changed files
with
157 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
//go:build !scheduler.none | ||
|
||
package runtime | ||
|
||
// runReactor is the program entry point for a WebAssembly reactor program, instead of run(). | ||
// With a scheduler, init (but not main) functions are invoked in a goroutine before starting the scheduler. | ||
func runReactor() { | ||
initHeap() | ||
go func() { | ||
initAll() | ||
// main is NOT called | ||
schedulerDone = true | ||
}() | ||
scheduler() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
//go:build scheduler.none | ||
|
||
package runtime | ||
|
||
// runReactor is the program entry point for a WebAssembly reactor program, instead of run(). | ||
// With the "none" scheduler, init (but not main) functions are invoked directly. | ||
func runReactor() { | ||
initHeap() | ||
initAll() | ||
// main is NOT called | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package wasm | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func TestReactor(t *testing.T) { | ||
tmpDir := t.TempDir() | ||
|
||
err := run(t, "tinygo build -x -o "+tmpDir+"/reactor.wasm -target wasi testdata/reactor.go") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
out, err := runout(t, "wasmtime run --invoke tinygo_test "+tmpDir+"/reactor.wasm") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
got := string(out) | ||
want := "1337\n" | ||
if !strings.Contains(got, want) { | ||
t.Errorf("reactor: expected %s, got %s", want, got) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package main | ||
|
||
import ( | ||
"time" | ||
_ "unsafe" | ||
) | ||
|
||
//go:linkname scheduler runtime.scheduler | ||
func scheduler() | ||
|
||
//go:linkname setSchedulerDone runtime.setSchedulerDone | ||
func setSchedulerDone(bool) | ||
|
||
// __go_wasm_export_tinygo_test is a wrapper function around tinygo_test | ||
// that runs the exported function in a goroutine and starts the scheduler. | ||
// Goroutines started by this or other functions will persist, are paused | ||
// when this function returns, and restarted when the host calls back into | ||
// another exported function. | ||
// | ||
//export tinygo_test | ||
func __go_wasm_export_tinygo_test() int32 { | ||
setSchedulerDone(false) | ||
var ret int32 | ||
go func() { | ||
ret = tinygo_test() | ||
setSchedulerDone(true) | ||
}() | ||
scheduler() | ||
return ret | ||
} | ||
|
||
func tinygo_test() int32 { | ||
for ticks != 1337 { | ||
time.Sleep(time.Nanosecond) | ||
} | ||
return ticks | ||
} | ||
|
||
var ticks int32 | ||
|
||
func init() { | ||
// Start infinite ticker | ||
go func() { | ||
for { | ||
ticks++ | ||
time.Sleep(time.Nanosecond) | ||
} | ||
}() | ||
} |