Go: wasm: fatal error: all goroutines are asleep - deadlock!

Created on 23 Sep 2019  ·  7Comments  ·  Source: golang/go

Version: go1.13 windows/amd64
Does this issue reproduce with the latest release? Yes

go env Output

set GO111MODULE=
set GOARCH=wasm
set GOBIN=
set GOCACHE=C:\Users\danau\AppData\Local\go-build
set GOENV=C:\Users\danau\AppData\Roaming\go\env
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GONOPROXY=
set GONOSUMDB=
set GOOS=js
set GOPATH=C:\projects\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=c:\go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=c:\go\pkg\tool\windows_amd64
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\danau\AppData\Local\Temp\go-build158127038=/tmp/go-build -gno-record-gcc-switches

Minimal Reproducible Example

package main

import (
    "fmt"
    "syscall/js"
)

func doStuffSynchronously() {
    done := make(chan bool)
    f := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
        fmt.Println("DOING STUFF")
        done <- true
        return nil
    })
    defer f.Release()
    js.Global().Call("setTimeout", f, 1000)
    <-done
    fmt.Println("DONE DOING STUFF")
}

func main() {

    doStuffSynchronously() // <- WORKS HERE

    cb := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
        fmt.Println("CB CALLED")
        doStuffSynchronously() // <- CRASHES WITH "fatal error: all goroutines are asleep - deadlock!"
        return nil
    })
    defer cb.Release()
    js.Global().Call("setTimeout", cb, 1000)

    // Prevent app from finishing while we wait for callback to execute
    neverDone := make(chan bool)
    <-neverDone
}

What did you expect to see?

I expected doStuffSynchronously() to work inside a callback just like it works outside one.

What did you see instead?

fatal error: all goroutines are asleep - deadlock!

Arch-Wasm FrozenDueToAge NeedsInvestigation

Most helpful comment

@bcmills I don't see any way to relax this restriction. setTimeout can only fire its callback if the event loop continues to run. The documentation may get improved by https://github.com/golang/go/issues/34324#issuecomment-534272747. Closing this issue.

@danaugrs Btw: You can use select {} instead of neverDone.

All 7 comments

As https://golang.org/pkg/syscall/js/#FuncOf says:

Blocking operations in the wrapped function will block the event loop. As a consequence, if one wrapped function blocks, other wrapped funcs will not be processed. A blocking function should therefore explicitly start a new goroutine.

currently, blocking operation, such as channel send, doesn't work in callbacks.

@cherrymui Thanks for the fast reply! If I start a new goroutine go doStuffSynchronously() is it guaranteed that it will be executed sequentially (i.e. the go syntax is only necessary due to limitations in the WASM implementation)?

I think it is not guaranteed to be executed sequentially, just like the go statement in general.

@cherrymui Yeah, just tried it and it's async - is there any workaround?

There is none at the moment. If you are making any call to JS land from inside a wrapped function, it's a deadlock. You have to change your programming model accordingly.

@cherrymui, @neelance: should we keep this issue open to track a future improvement to relax this restriction, or is it going to remain this way for the foreseeable future?

@bcmills I don't see any way to relax this restriction. setTimeout can only fire its callback if the event loop continues to run. The documentation may get improved by https://github.com/golang/go/issues/34324#issuecomment-534272747. Closing this issue.

@danaugrs Btw: You can use select {} instead of neverDone.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ashb picture ashb  ·  3Comments

bradfitz picture bradfitz  ·  3Comments

longzhizhi picture longzhizhi  ·  3Comments

myitcv picture myitcv  ·  3Comments

natefinch picture natefinch  ·  3Comments