Skip to content

Commit

Permalink
wasm: support //go:wasmexport functions after a call to time.Sleep
Browse files Browse the repository at this point in the history
This fixes a bug where `//go:wasmexport` functions would not be allowed
anymore after a call to `time.Sleep` (when using `-buildmode=default`).
  • Loading branch information
aykevl committed Oct 30, 2024
1 parent 0edeaf6 commit 88a6f4e
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 26 deletions.
34 changes: 11 additions & 23 deletions src/runtime/runtime_wasmentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,22 @@ import (
// This is the _start entry point, when using -buildmode=default.
func wasmEntryCommand() {
// These need to be initialized early so that the heap can be initialized.
initializeCalled = true
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
wasmExportState = wasmExportStateInMain
run()
wasmExportState = wasmExportStateExited
beforeExit()
if mainExited {
beforeExit()
}
}

// This is the _initialize entry point, when using -buildmode=c-shared.
func wasmEntryReactor() {
// This function is called before any //go:wasmexport functions are called
// to initialize everything. It must not block.

initializeCalled = true

// Initialize the heap.
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
Expand All @@ -38,38 +41,23 @@ func wasmEntryReactor() {
// goroutine.
go func() {
initAll()
wasmExportState = wasmExportStateReactor
}()
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 {
// There are no goroutines (except for the main one, if you can call it
// that), so we can just run all the package initializers.
initAll()
wasmExportState = wasmExportStateReactor
}
}

// Track which state we're in: before (or during) init, running inside
// main.main, after main.main returned, or reactor mode (after init).
var wasmExportState uint8

const (
wasmExportStateInit = iota
wasmExportStateInMain
wasmExportStateExited
wasmExportStateReactor
)
// Whether the runtime was initialized by a call to _initialize or _start.
var initializeCalled bool

func wasmExportCheckRun() {
switch wasmExportState {
case wasmExportStateInit:
switch {
case !initializeCalled:
runtimePanic("//go:wasmexport function called before runtime initialization")
case wasmExportStateExited:
case mainExited:
runtimePanic("//go:wasmexport function called after main.main returned")
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const schedulerDebug = false
// queue a new scheduler invocation using setTimeout.
const asyncScheduler = GOOS == "js"

var schedulerDone bool
var mainExited bool

// Queues used by the scheduler.
var (
Expand Down Expand Up @@ -166,7 +166,7 @@ func removeTimer(tim *timer) bool {
func scheduler(returnAtDeadlock bool) {
// Main scheduler loop.
var now timeUnit
for !schedulerDone {
for !mainExited {
scheduleLog("")
scheduleLog(" schedule")
if sleepQueue != nil || timerQueue != nil {
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/scheduler_any.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func run() {
go func() {
initAll()
callMain()
schedulerDone = true
mainExited = true
}()
scheduler(false)
}
Expand Down
3 changes: 3 additions & 0 deletions testdata/wasmexport-noscheduler.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package main

import "time"

func init() {
println("called init")
}
Expand All @@ -9,6 +11,7 @@ func callTestMain()

func main() {
// main.main is not used when using -buildmode=c-shared.
time.Sleep(time.Millisecond)
callTestMain()
}

Expand Down

0 comments on commit 88a6f4e

Please sign in to comment.