Skip to content
GitLab
Projects Groups Topics Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Register
  • Sign in
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
    • Locked files
  • Issues 5.6k
    • Issues 5.6k
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 663
    • Merge requests 663
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Artifacts
    • Schedules
    • Test cases
  • Deployments
    • Deployments
    • Releases
  • Packages and registries
    • Packages and registries
    • Model experiments
  • Analytics
    • Analytics
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell CompilerGlasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #16707

Hanging STM transaction with orElse on writeTVar

In the following program the main thread's atomically hangs in the second iteration, although no other threads are running (and the transaction would have no reason to retry).

import Control.Concurrent
import Control.Concurrent.STM
import Debug.Trace

main :: IO ()
main = (`mapM_` [1..1000]) $ \_ -> do
  traceEventIO "(((("

  x <- newTVarIO False

  forkIO $ atomically $ writeTVar x True

  traceEventIO "----"

  atomically $ do  -- hangs in the second iteration
    _ <- readTVar x
    writeTVar x True `orElse` return ()

  threadDelay 100000
  traceEventIO "))))"

Obviously, using orElse on writeTVar makes no sense, the code here is the result of boiling down a much bigger program.

$ ghc -debug Bug.hs
[1 of 1] Compiling Main             ( Bug.hs, Bug.o )
Linking Bug ...
$ ./Bug +RTS -v
created capset 0 of type 2
created capset 1 of type 3
cap 0: initialised
assigned cap 0 to capset 0
assigned cap 0 to capset 1
cap 0: created thread 1
cap 0: running thread 1 (ThreadRunGHC)
cap 0: ((((
cap 0: created thread 2
cap 0: ----
cap 0: thread 1 stopped (blocked on a delay operation)
cap 0: running thread 2 (ThreadRunGHC)
cap 0: thread 2 stopped (finished)
cap 0: running thread 1 (ThreadRunGHC)
cap 0: thread 1 stopped (yielding)
cap 0: running thread 1 (ThreadRunGHC)
cap 0: ))))
cap 0: ((((
cap 0: created thread 3
cap 0: ----
cap 0: thread 1 stopped (yielding)
cap 0: running thread 3 (ThreadRunGHC)
cap 0: thread 3 stopped (finished)
cap 0: running thread 1 (ThreadRunGHC)

At this point the program hangs and uses 100% CPU. Only the main thread (1) is running (2 and 3 finished). It is past the ----, but hasn't reached threadDelay yet (no blocked on a delay operation in the second iteration). So it must be working on the atomically block in between.

This is perfectly reproducible (exact same result on two different machines, tested several times).

Compiling with -fno-omit-yields (as suggested in https://downloads.haskell.org/~ghc/8.6.5/docs/html/users_guide/bugs.html#bugs-in-ghc, which refers to #367) makes no difference. This also seems different to #15975, where the problem appears to be a failure to yield in between transactions. Removing either the readTVar x or the `orElse` return () bit makes all 1000 iterations go through without hanging.

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.6.5
Edited May 29, 2019 by roland
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking