Deadlock detection different in ghc-5.04?

Simon Marlow simonmar@microsoft.com
Mon, 22 Jul 2002 18:12:53 +0100


> Hi, for some concurrency abstractions I decided to use deadlock
> detection by means of exceptions which didn't work out as expected.
> Below is some simplifed source code showing the problem: My assumption
> was since GHC should be able to detect that the child still has a
> reference to mv_should_work -- although in an exception handler -- the
> RTS would never decide to kill the other thread.
>=20
> Unluckily, this assumption turned out to be false. Did I overestimate
> GHC's capabilities or is this a bug?

It's not a bug, but it's quite tricky to explain.

The effect you're seeing is this: GHC 5.04 is a bit more general in
dealing with deadlocks, in that it doesn't automatically assume that the
main thread is alive (GHC 5.02 did make that assumption).  In your
example, at the point of the deadlock *both* threads are blocked on
unreachable MVars, so both threads get an exception.  The RTS has no way
to know that if it woke up the child thread first, then this would also
unblock the main thread.

I've cut-n-pasted the trace below (you can get this by compiling the RTS
with -DDEBUG and running the program with +RTS -D1; arguably this is so
useful that we ought to take it out from under -DDEBUG).

Cheers,
	Simon

DEBUG (-D1): scheduler
scheduler: created thread 1, stack size =3D f4 words
scheduler: =3D=3D scheduler: waiting for thread (1)

scheduler: =3D=3D scheduler: waiting for thread (1)

scheduler: =3D=3D scheduler: new main thread (1)

scheduler: all threads:
        thread 1 @ 0x500c0000 is not blocked
scheduler: -->> Running TSO 1 (0x500c0000) ThreadEnterGHC ...
scheduler: created thread 2, stack size =3D f4 words
scheduler: --<< thread 1 (0x500c0000; ThreadRunGHC) stopped, yielding
scheduler: all threads:
        thread 2 @ 0x500c0400 is not blocked
        thread 1 @ 0x500c0000 is not blocked
scheduler: -->> Running TSO 2 (0x500c0400) ThreadEnterGHC ...
scheduler: --<< thread 2 (0x500c0400) stopped: is blocked on an MVar
scheduler: all threads:
        thread 2 @ 0x500c0400 is blocked on an MVar
        thread 1 @ 0x500c0000 is not blocked
scheduler: -->> Running TSO 1 (0x500c0000) ThreadRunGHC ...
scheduler: --<< thread 1 (0x500c0000; ThreadRunGHC) stopped, yielding
scheduler: all threads:
        thread 2 @ 0x500c0400 is blocked on an MVar
        thread 1 @ 0x500c0000 is not blocked
scheduler: -->> Running TSO 1 (0x500c0000) ThreadRunGHC ...
scheduler: --<< thread 1 (0x500c0000; ThreadRunGHC) stopped, yielding
scheduler: all threads:
        thread 2 @ 0x500c0400 is blocked on an MVar
        thread 1 @ 0x500c0000 is not blocked
scheduler: -->> Running TSO 1 (0x500c0000) ThreadRunGHC ...
scheduler: --<< thread 1 (0x500c0000) stopped: is blocked on an MVar
scheduler: all threads:
        thread 2 @ 0x500c0400 is blocked on an MVar
        thread 1 @ 0x500c0000 is blocked on an MVar
scheduler: deadlocked, forcing major GC...
scheduler: resurrecting thread 1
scheduler: raising exception in thread 1.
scheduler: raising exception in thread 1.
scheduler: resurrecting thread 2
scheduler: raising exception in thread 2.
scheduler: raising exception in thread 2.
scheduler: -->> Running TSO 2 (0x500bf000) ThreadEnterGHC ...
scheduler: --++ thread 2 (0x500bf000) finished
scheduler: all threads:
        thread 2 @ 0x500bf000 has completed
        thread 1 @ 0x500bf400 is not blocked
scheduler: -->> Running TSO 1 (0x500bf400) ThreadEnterGHC ...
main caught: thread blocked indefinitely
scheduler: --++ thread 1 (0x500bf400) finished
scheduler: all threads:
        thread 2 @ 0x500bf000 has completed
        thread 1 @ 0x500bf400 has completed
=3D=3D scheduler: main thread (1) finished
scheduler: created thread 3, stack size =3D f4 words
scheduler: =3D=3D scheduler: waiting for thread (3)

scheduler: =3D=3D scheduler: waiting for thread (3)

scheduler: =3D=3D scheduler: new main thread (3)

scheduler: all threads:
        thread 3 @ 0x500bd028 is not blocked
        thread 2 @ 0x500bf000 has completed
        thread 1 @ 0x500bf400 has completed
scheduler: -->> Running TSO 3 (0x500bd028) ThreadEnterGHC ...
scheduler: --++ thread 3 (0x500bd028) finished
scheduler: all threads:
        thread 3 @ 0x500bd028 has completed
        thread 2 @ 0x500bf000 has completed
        thread 1 @ 0x500bf400 has completed
=3D=3D scheduler: main thread (3) finished