Description
First mentioned in #657, I've come upon a problem with the standard library 'log' package and the error Uncaught Error: nosync: mutex is already locked
.
I've come up with a minimal reproduction case, available in its entirety here which raises more questions for me than it provides answers:
// +build js
package main
import (
"log"
"github.com/gopherjs/gopherjs/js"
"github.com/gopherjs/jquery"
)
func get() {
done := make(chan struct{})
xmlhttp := js.Global.Get("XMLHttpRequest").New()
xmlhttp.Set("onreadystatechange", func() {
if xmlhttp.Get("readyState") == js.Global.Get("XMLHttpRequest").Get("DONE") {
close(done)
}
})
xmlhttp.Call("open", "GET", "http://127.0.0.1/", true)
xmlhttp.Call("send")
<-done
}
func main() {
get()
initChan := make(chan struct{})
initDone := initChan
go func() {
log.Print("init terminating\n")
close(initChan)
}()
jquery.NewJQuery().Ready(func() {
get()
})
log.Print("Waiting for init\n")
<-initDone
log.Print("Done waiting for init\n")
}
When executed in the browser (tested in both Chromium 58 and Firefox 45.9.0), I get the following error on the console (from Chromium 58):
nosyncissue.js:1412 Uncaught Error: nosync: mutex is already locked
at $callDeferred (nosyncissue.js:1412)
at $panic (nosyncissue.js:1451)
at Object.$packages.github.com/gopherjs/gopherjs/nosync.Mutex.ptr.Lock (mutex.go:11)
at Object.$packages.log.Logger.ptr.Output (log.go:30)
at Object.Print (log.go:285)
at $b (main.go:31)
at $goroutine (nosyncissue.js:1471)
at $runScheduled (nosyncissue.js:1511)
at $schedule (nosyncissue.js:1527)
at queueEntry (nosyncissue.js:1593)
at $close (nosyncissue.js:1616)
at main.go:17
at XMLHttpRequest.v.$externalizeWrapper (nosyncissue.js:1867)
One thing I find quite interesting is the on ready call works at all:
jquery.NewJQuery().Ready(func() {
get()
})
Note that get()
is a blocking method, and in fact changing this to:
js.Global.Call("setTimeout", func() {
get()
}, 0)
then I get the expected Uncaught Error: runtime error: cannot block in JavaScript callback, fix by wrapping code in goroutine
error on the console.
Perhaps the underlying cause is improperly using a blocking method in a callback, and GopherJS just isn't detecting it for some reason? Perhaps that is consistent with what I observed in #657, that replacing nosync
with sync
in the log
package resulted in a deadlock that went undetected by the GopherJS runtime?
If I can be of further assistance in diagnosing the problem, please let me know.