Skip to content

Missing deadlock detection #148

Description

@grantnelson-wf

goscript doesn't detect deadlocking (at least in the playground, node.js may detect it).

goscript will start these applications and never end since the routines are stuck on awaits. Obviously all deadlocking and contentions can not be resolved when the resource comes from an external source or there are hardware interrupts (alive locks fall under the halting problem). For transpiled code there is a similar issue when, in these cases, unexported channels are being awaited. It may not be able to determine if there is a deadlock with exported channels since something outside of the goscript events could change the state of the channel and break contention thus resolving the await such that the event for the routines are suddenly alive again.

GopherJS runs as if it is self-contained like Go's executable (GopherJS runs in an IIFE) and GopherJS does not halt other routines when the main routine exists, this means the GopherJS scheduler stays alive or dormant (since it was originally written before JS got async/await) and can detect when there are routines awaiting to be run but are suspended on a resource (e.g. on a channel send or receive, or a mutex lock). Go does a similar thing with its routines even when the routines are distributed across multiple OS threads.

I tried two types of deadlocking:

  • Main deadlocking shows a routine deadlocking itself, in this case the main routine
  • Routine deadlocking shows two routines in contention, this is similar to resource contention deadlocking

Main deadlocking

playground:

package main

func main() {
	c := make(chan int)
	<- c
}

Go output:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
	/tmp/sandbox4065277556/prog.go:5 +0x25

Routine deadlocking

playgrounds:

package main

func ping(in, out, done chan int) {
	x := <-in
	out <- x
	done <- 1
}

func main() {
	a := make(chan int)
	b := make(chan int)
	done := make(chan int)

	go ping(a, b, done)
	go ping(b, a, done)

	<-done
	<-done
}

Go output:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
	/tmp/sandbox1809719584/prog.go:17 +0x11e

goroutine 6 [chan receive]:
main.ping(...)
	/tmp/sandbox1809719584/prog.go:4
created by main.main in goroutine 1
	/tmp/sandbox1809719584/prog.go:14 +0xb2

goroutine 7 [chan receive]:
main.ping(...)
	/tmp/sandbox1809719584/prog.go:4
created by main.main in goroutine 1
	/tmp/sandbox1809719584/prog.go:15 +0x112

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions