return ok
}
-func beforeIdle(int64) bool {
- return false
+func beforeIdle(int64) (*g, bool) {
+ return nil, false
}
func checkTimeouts() {}
// beforeIdle gets called by the scheduler if no goroutine is awake.
// If we are not already handling an event, then we pause for an async event.
// If an event handler returned, we resume it and it will pause the execution.
-func beforeIdle(delay int64) bool {
+// beforeIdle either returns the specific goroutine to schedule next or
+// indicates with otherReady that some goroutine became ready.
+func beforeIdle(delay int64) (gp *g, otherReady bool) {
if delay > 0 {
clearIdleID()
if delay < 1e6 {
if len(events) == 0 {
go handleAsyncEvent()
- return true
+ return nil, true
}
e := events[len(events)-1]
if e.returned {
- goready(e.gp, 1)
- return true
+ return e.gp, false
}
- return false
+ return nil, false
}
func handleAsyncEvent() {
return ok
}
-func beforeIdle(int64) bool {
- return false
+func beforeIdle(int64) (*g, bool) {
+ return nil, false
}
func checkTimeouts() {}
// wasm only:
// If a callback returned and no other goroutine is awake,
- // then pause execution until a callback was triggered.
- if beforeIdle(delta) {
- // At least one goroutine got woken.
+ // then wake event handler goroutine which pauses execution
+ // until a callback was triggered.
+ gp, otherReady := beforeIdle(delta)
+ if gp != nil {
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ if trace.enabled {
+ traceGoUnpark(gp, 0)
+ }
+ return gp, false
+ }
+ if otherReady {
goto top
}
--- /dev/null
+// +build js
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test race condition between timers and wasm calls that led to memory corruption.
+
+package main
+
+import (
+ "os"
+ "syscall/js"
+ "time"
+)
+
+func main() {
+ ch1 := make(chan struct{})
+
+ go func() {
+ for {
+ time.Sleep(5 * time.Millisecond)
+ ch1 <- struct{}{}
+ }
+ }()
+ go func() {
+ for {
+ time.Sleep(8 * time.Millisecond)
+ ch1 <- struct{}{}
+ }
+ }()
+ go func() {
+ time.Sleep(2 * time.Second)
+ os.Exit(0)
+ }()
+
+ for range ch1 {
+ ch2 := make(chan struct{}, 1)
+ f := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ ch2 <- struct{}{}
+ return nil
+ })
+ defer f.Release()
+ fn := js.Global().Get("Function").New("cb", "cb();")
+ fn.Invoke(f)
+ <-ch2
+ }
+}