Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,10 @@ func TestWasmExport(t *testing.T) {
// again.
checkResult("reentrantCall(2, 3)", mustCall(mod.ExportedFunction("reentrantCall").Call(ctx, 2, 3)), []uint64{5})
checkResult("reentrantCall(1, 8)", mustCall(mod.ExportedFunction("reentrantCall").Call(ctx, 1, 8)), []uint64{9})

// Check that goroutines started inside //go:wasmexport don't
// block the called function from returning.
checkResult("goroutineExit()", mustCall(mod.ExportedFunction("goroutineExit").Call(ctx)), nil)
}

// Add wasip1 module.
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/runtime_wasmentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ func wasmExportRun(done *bool) {
//
// This function is not called when the scheduler is disabled.
func wasmExportExit() {
// Signal to the scheduler that it should return, since this call to a
// //go:wasmexport function has exited.
schedulerExit = true

task.Pause()

// TODO: we could cache the allocated stack so we don't have to keep
Expand Down
11 changes: 11 additions & 0 deletions src/runtime/scheduler_cooperative.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ const hasParallelism = false
// Set to true after main.main returns.
var mainExited bool

// Set to true when the scheduler should exit after the next switch to the
// scheduler. This is a special case for //go:wasmexport.
var schedulerExit bool

// Queues used by the scheduler.
var (
runqueue task.Queue
Expand Down Expand Up @@ -214,6 +218,13 @@ func scheduler(returnAtDeadlock bool) {
// Run the given task.
scheduleLogTask(" run:", t)
t.Resume()

// The last call to Resume() was a signal to stop the scheduler since a
// //go:wasmexport function returned.
if GOARCH == "wasm" && schedulerExit {
schedulerExit = false // reset the signal
return
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/runtime/scheduler_none.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const hasParallelism = false
// Set to true after main.main returns.
var mainExited bool

// dummy flag, not used without scheduler
var schedulerExit bool

// run is called by the program entry point to execute the go program.
// With the "none" scheduler, init and the main function are invoked directly.
func run() {
Expand Down
6 changes: 6 additions & 0 deletions testdata/wasmexport-noscheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,9 @@ func reentrantCall(a, b int32) int32 {
println("reentrantCall result:", result)
return result
}

//go:wasmexport goroutineExit
func goroutineExit() {
// Dummy, not a real test (since we have no scheduler).
println("goroutineExit: exit")
}
17 changes: 16 additions & 1 deletion testdata/wasmexport.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package main

import "time"
import (
"runtime"
"time"
)

func init() {
println("called init")
Expand Down Expand Up @@ -50,3 +53,15 @@ func reentrantCall(a, b int32) int32 {
println("reentrantCall result:", result)
return result
}

// Test for bug: https://github.com/tinygo-org/tinygo/issues/4874
//
//go:wasmexport goroutineExit
func goroutineExit() {
go func() {
time.Sleep(time.Second * 10)
println("goroutineExit: exiting goroutine")
}()
runtime.Gosched()
println("goroutineExit: exit")
}
1 change: 1 addition & 0 deletions testdata/wasmexport.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function runTests() {
testCall('add', [6, 1], 7);
testCall('reentrantCall', [2, 3], 5);
testCall('reentrantCall', [1, 8], 9);
testCall('goroutineExit', [], undefined);
}

let go = new Go();
Expand Down
1 change: 1 addition & 0 deletions testdata/wasmexport.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ reentrantCall result: 5
reentrantCall: 1 8
called add: 1 8
reentrantCall result: 9
goroutineExit: exit