Ticket #2651 (closed bug: wontfix)

Opened 5 years ago

Last modified 5 years ago

BlockedIndefinitely not thrown when it should be

Reported by: govereau Owned by:
Priority: normal Milestone: 6.10 branch
Component: Runtime System Version: 6.8.3
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Difficulty: Unknown
Test Case: Blocked By:
Blocking: Related Tickets:

Description

The following program demonstrates the bug. When run with no arguments, the "die" thread gets a BlockedIndefinitely? exception, when run with command line arguments it does not.

module Main where
import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import System.Environment

main :: IO ()
main = do { flags <- getArgs
           ; if (length flags > 0)
            then forkIO die >>         -- die does not die
                 threadDelay 10000000
            else die                   -- die dies         
          }

-- expect BlockedIndefinitely exception to be thrown
die :: IO ()
die = newTVarIO "die" >>= f >>= print
 where f tv = atomically $ do { x <- readTVar tv
                              ; if x == "die" then retry else return x
                              }

Change History

  Changed 5 years ago by igloo

  • difficulty set to Unknown
  • os changed from MacOS X to Unknown/Multiple
  • architecture changed from x86 to Unknown/Multiple
  • milestone set to 6.10 branch

Here's an example that doesn't need stm:

module Main where
import Control.Concurrent
import Control.Concurrent.MVar
import Control.Exception as E
import System.Environment

main :: IO ()
main = do flags <- getArgs
          if (length flags > 0)
              then do forkIO die
                      threadDelay 10000000
              else die

-- expect BlockedIndefinitely exception to be thrown
die :: IO ()
die = newEmptyMVar >>= g
 where g v = f v `E.catch` \e -> do print ('a', e :: E.SomeException)
                                    E.throw e
       f v = readMVar v
$ ghc n.hs -o n -fforce-recomp        
$ ./n
('a',thread blocked indefinitely)
n: thread blocked indefinitely
$ ./n q
$

The thread does get an exception with the threaded RTS, however:

$ ghc n.hs -o n -fforce-recomp -threaded
$ ./n  
('a',thread blocked indefinitely)
n: thread blocked indefinitely
$ ./n q
('a',thread blocked indefinitely)
$

(the above is with the 6.10 branch)

  Changed 5 years ago by simonmar

  • status changed from new to closed
  • resolution set to wontfix

As Ian says, it works with the threaded RTS. This is because detecting deadlocked threads requires the GC to run, and only the threaded RTS runs the GC during idle time (i.e. when the main thread is in threadDelay in this example).

The non-threaded RTS just sits in select() waiting for the time to expire. I suppose it could notice that it had a long time to wait and do a GC, but I don't feel terribly inclined to fix this since there's an easy workaround. We don't guarantee anything about deadlock detection anyway, because GC can always be delayed for an arbitrary amount of time, so it's really just a debugging feature.

follow-up: ↓ 4   Changed 5 years ago by govereau

Just to be clear. I observed this problem with the threaded RTS on OSX and only with the STM-like example, not MVars. I am happy to hear that it is fixed in 6.10! Thanks!

in reply to: ↑ 3   Changed 5 years ago by simonmar

Replying to govereau:

Just to be clear. I observed this problem with the threaded RTS on OSX and only with the STM-like example, not MVars. I am happy to hear that it is fixed in 6.10! Thanks!

A thread created by 'forkIO' has an exception handler that ignores 'BlockedIndefintely?', so that is why it isn't printed. It is still being raised, however. I've just added a note about this to the documentation for 'forkIO'. Just to be clear, nothing has changed in 6.10.1 here.

Note: See TracTickets for help on using tickets.