diff --git a/src/runtime/runtime_wasm_js.go b/src/runtime/runtime_wasm_js.go index f4335e121b..f6fae3d9e8 100644 --- a/src/runtime/runtime_wasm_js.go +++ b/src/runtime/runtime_wasm_js.go @@ -6,13 +6,20 @@ import "unsafe" type timeUnit float64 // time in milliseconds, just like Date.now() in JavaScript +// wasmRunning is used to track whether wasm is currently running to avoid nested scheduling. +var wasmRunning bool + //export _start func _start() { + wasmRunning = true + // These need to be initialized early so that the heap can be initialized. heapStart = uintptr(unsafe.Pointer(&heapStartSymbol)) heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize) run() + + wasmRunning = false } var handleEvent func() @@ -24,15 +31,27 @@ func setEventHandler(fn func()) { //export resume func resume() { + prevRunning := wasmRunning + wasmRunning = true go func() { handleEvent() }() - scheduler() + if !prevRunning { + // Nothing is currently running, so we can safely invoke the scheduler. + scheduler() + } + wasmRunning = prevRunning } //export go_scheduler func go_scheduler() { + if wasmRunning { + return + } + + wasmRunning = true scheduler() + wasmRunning = false } func ticksToNanoseconds(ticks timeUnit) int64 { diff --git a/src/runtime/scheduler.go b/src/runtime/scheduler.go index 44b07f75d9..46ea5c2d92 100644 --- a/src/runtime/scheduler.go +++ b/src/runtime/scheduler.go @@ -116,9 +116,18 @@ func addSleepTask(t *task.Task, duration timeUnit) { *q = t } +var schedulerRunning bool + // Run the scheduler until all tasks have finished. func scheduler() { // Main scheduler loop. + if schedulerDebug { + if schedulerRunning { + runtimePanic("nested scheduler") + } + + schedulerRunning = true + } var now timeUnit for !schedulerDone { scheduleLog("") @@ -143,7 +152,7 @@ func scheduler() { if sleepQueue == nil { if asyncScheduler { // JavaScript is treated specially, see below. - return + break } waitForEvents() continue @@ -170,6 +179,9 @@ func scheduler() { scheduleLogTask(" run:", t) t.Resume() } + if schedulerDebug { + schedulerRunning = false + } } func Gosched() {