Skip to content

Commit 612a38e

Browse files
aykevldeadprogram
authored andcommitted
wasm: don't block //go:wasmexport because of running goroutines
This fixes bug #4874.
1 parent 0c2ab89 commit 612a38e

8 files changed

+46
-1
lines changed

main_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,10 @@ func TestWasmExport(t *testing.T) {
687687
// again.
688688
checkResult("reentrantCall(2, 3)", mustCall(mod.ExportedFunction("reentrantCall").Call(ctx, 2, 3)), []uint64{5})
689689
checkResult("reentrantCall(1, 8)", mustCall(mod.ExportedFunction("reentrantCall").Call(ctx, 1, 8)), []uint64{9})
690+
691+
// Check that goroutines started inside //go:wasmexport don't
692+
// block the called function from returning.
693+
checkResult("goroutineExit()", mustCall(mod.ExportedFunction("goroutineExit").Call(ctx)), nil)
690694
}
691695

692696
// Add wasip1 module.

src/runtime/runtime_wasmentry.go

+4
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ func wasmExportRun(done *bool) {
9292
//
9393
// This function is not called when the scheduler is disabled.
9494
func wasmExportExit() {
95+
// Signal to the scheduler that it should return, since this call to a
96+
// //go:wasmexport function has exited.
97+
schedulerExit = true
98+
9599
task.Pause()
96100

97101
// TODO: we could cache the allocated stack so we don't have to keep

src/runtime/scheduler_cooperative.go

+11
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ const hasParallelism = false
3030
// Set to true after main.main returns.
3131
var mainExited bool
3232

33+
// Set to true when the scheduler should exit after the next switch to the
34+
// scheduler. This is a special case for //go:wasmexport.
35+
var schedulerExit bool
36+
3337
// Queues used by the scheduler.
3438
var (
3539
runqueue task.Queue
@@ -214,6 +218,13 @@ func scheduler(returnAtDeadlock bool) {
214218
// Run the given task.
215219
scheduleLogTask(" run:", t)
216220
t.Resume()
221+
222+
// The last call to Resume() was a signal to stop the scheduler since a
223+
// //go:wasmexport function returned.
224+
if GOARCH == "wasm" && schedulerExit {
225+
schedulerExit = false // reset the signal
226+
return
227+
}
217228
}
218229
}
219230

src/runtime/scheduler_none.go

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ const hasParallelism = false
1212
// Set to true after main.main returns.
1313
var mainExited bool
1414

15+
// dummy flag, not used without scheduler
16+
var schedulerExit bool
17+
1518
// run is called by the program entry point to execute the go program.
1619
// With the "none" scheduler, init and the main function are invoked directly.
1720
func run() {

testdata/wasmexport-noscheduler.go

+6
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,9 @@ func reentrantCall(a, b int32) int32 {
3939
println("reentrantCall result:", result)
4040
return result
4141
}
42+
43+
//go:wasmexport goroutineExit
44+
func goroutineExit() {
45+
// Dummy, not a real test (since we have no scheduler).
46+
println("goroutineExit: exit")
47+
}

testdata/wasmexport.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package main
22

3-
import "time"
3+
import (
4+
"runtime"
5+
"time"
6+
)
47

58
func init() {
69
println("called init")
@@ -50,3 +53,15 @@ func reentrantCall(a, b int32) int32 {
5053
println("reentrantCall result:", result)
5154
return result
5255
}
56+
57+
// Test for bug: https://github.com/tinygo-org/tinygo/issues/4874
58+
//
59+
//go:wasmexport goroutineExit
60+
func goroutineExit() {
61+
go func() {
62+
time.Sleep(time.Second * 10)
63+
println("goroutineExit: exiting goroutine")
64+
}()
65+
runtime.Gosched()
66+
println("goroutineExit: exit")
67+
}

testdata/wasmexport.js

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ function runTests() {
1515
testCall('add', [6, 1], 7);
1616
testCall('reentrantCall', [2, 3], 5);
1717
testCall('reentrantCall', [1, 8], 9);
18+
testCall('goroutineExit', [], undefined);
1819
}
1920

2021
let go = new Go();

testdata/wasmexport.txt

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ reentrantCall result: 5
99
reentrantCall: 1 8
1010
called add: 1 8
1111
reentrantCall result: 9
12+
goroutineExit: exit

0 commit comments

Comments
 (0)