wasm: support //go:wasmexport functions after a call to time.Sleep

This fixes a bug where `//go:wasmexport` functions would not be allowed
anymore after a call to `time.Sleep` (when using `-buildmode=default`).
This commit is contained in:
Ayke van Laethem
2024-10-30 12:12:10 +01:00
committed by Ayke
parent 8ff97bdedd
commit 04a7baec3e
4 changed files with 20 additions and 26 deletions
+11 -23
View File
@@ -14,12 +14,13 @@ import (
// This is the _start entry point, when using -buildmode=default. // This is the _start entry point, when using -buildmode=default.
func wasmEntryCommand() { func wasmEntryCommand() {
// These need to be initialized early so that the heap can be initialized. // These need to be initialized early so that the heap can be initialized.
initializeCalled = true
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol)) heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize) heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
wasmExportState = wasmExportStateInMain
run() run()
wasmExportState = wasmExportStateExited if mainExited {
beforeExit() beforeExit()
}
} }
// This is the _initialize entry point, when using -buildmode=c-shared. // This is the _initialize entry point, when using -buildmode=c-shared.
@@ -27,6 +28,8 @@ func wasmEntryReactor() {
// This function is called before any //go:wasmexport functions are called // This function is called before any //go:wasmexport functions are called
// to initialize everything. It must not block. // to initialize everything. It must not block.
initializeCalled = true
// Initialize the heap. // Initialize the heap.
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol)) heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize) heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
@@ -38,38 +41,23 @@ func wasmEntryReactor() {
// goroutine. // goroutine.
go func() { go func() {
initAll() initAll()
wasmExportState = wasmExportStateReactor
}() }()
scheduler(true) scheduler(true)
if wasmExportState != wasmExportStateReactor {
// Unlikely, but if package initializers do something blocking (like
// time.Sleep()), that's a bug.
runtimePanic("package initializer blocks")
}
} else { } else {
// There are no goroutines (except for the main one, if you can call it // There are no goroutines (except for the main one, if you can call it
// that), so we can just run all the package initializers. // that), so we can just run all the package initializers.
initAll() initAll()
wasmExportState = wasmExportStateReactor
} }
} }
// Track which state we're in: before (or during) init, running inside // Whether the runtime was initialized by a call to _initialize or _start.
// main.main, after main.main returned, or reactor mode (after init). var initializeCalled bool
var wasmExportState uint8
const (
wasmExportStateInit = iota
wasmExportStateInMain
wasmExportStateExited
wasmExportStateReactor
)
func wasmExportCheckRun() { func wasmExportCheckRun() {
switch wasmExportState { switch {
case wasmExportStateInit: case !initializeCalled:
runtimePanic("//go:wasmexport function called before runtime initialization") runtimePanic("//go:wasmexport function called before runtime initialization")
case wasmExportStateExited: case mainExited:
runtimePanic("//go:wasmexport function called after main.main returned") runtimePanic("//go:wasmexport function called after main.main returned")
} }
} }
+2 -2
View File
@@ -21,7 +21,7 @@ const schedulerDebug = false
// queue a new scheduler invocation using setTimeout. // queue a new scheduler invocation using setTimeout.
const asyncScheduler = GOOS == "js" const asyncScheduler = GOOS == "js"
var schedulerDone bool var mainExited bool
// Queues used by the scheduler. // Queues used by the scheduler.
var ( var (
@@ -166,7 +166,7 @@ func removeTimer(tim *timer) bool {
func scheduler(returnAtDeadlock bool) { func scheduler(returnAtDeadlock bool) {
// Main scheduler loop. // Main scheduler loop.
var now timeUnit var now timeUnit
for !schedulerDone { for !mainExited {
scheduleLog("") scheduleLog("")
scheduleLog(" schedule") scheduleLog(" schedule")
if sleepQueue != nil || timerQueue != nil { if sleepQueue != nil || timerQueue != nil {
+1 -1
View File
@@ -23,7 +23,7 @@ func run() {
go func() { go func() {
initAll() initAll()
callMain() callMain()
schedulerDone = true mainExited = true
}() }()
scheduler(false) scheduler(false)
} }
+6
View File
@@ -1,5 +1,7 @@
package main package main
import "time"
func init() { func init() {
println("called init") println("called init")
} }
@@ -8,6 +10,10 @@ func init() {
func callTestMain() func callTestMain()
func main() { func main() {
// Check that exported functions can still be called after calling
// time.Sleep.
time.Sleep(time.Millisecond)
// main.main is not used when using -buildmode=c-shared. // main.main is not used when using -buildmode=c-shared.
callTestMain() callTestMain()
} }