Skip to content

Uncaught Error: nosync: mutex is already locked #659

Open
@flimzy

Description

@flimzy

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions