Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
GHC
GHC
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,389
    • Issues 4,389
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
    • Iterations
  • Merge Requests 373
    • Merge Requests 373
  • Requirements
    • Requirements
    • List
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Operations
    • Operations
    • Incidents
    • Environments
  • Analytics
    • Analytics
    • CI / CD
    • Code Review
    • Insights
    • Issue
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #18580

Closed
Open
Opened Aug 15, 2020 by Facundo Domínguez@facundominguezReporter

Have System.Timeout.timeout fail if exceptions are uninterruptibly masked

Motivation

The following contrieved program blocks indefinitely because UnliftIO.finally masks exceptions uninterruptibly.

return () `UnliftIO.finally` timeout 100 (forever $ threadDelay maxBound)

Proposal

There is no way that timeout can deliver its asynchronous exception if the exceptions are masked uninterruptibly. It is easier to discover the mistake of calling timeout if it throws an error, rather than letting it block. Therefore, we should modify timeout as follows and document the new precondition.

 timeout :: Int -> IO a -> IO (Maybe a)
 timeout n f
     | n <  0    = fmap Just f
     | n == 0    = return Nothing
 #if !defined(mingw32_HOST_OS)
     | rtsSupportsBoundThreads = do
+        checkNonUninterruptibleMask       
         pid <- myThreadId
         ex  <- fmap Timeout newUnique

 ...

 #endif
     | otherwise = do
+        checkNonUninterruptibleMask
         pid <- myThreadId
         ex  <- fmap Timeout newUnique

 ...

+  where
+    checkNonUninterruptibleMask = do
+      maskingState <- getMaskingState
+      when (maskingState == Unmasked) $
+        error "System.Timeout.timeout called with exceptions uninterruptibly masked"

Additionally, maybe we should add a HasCallStack constraint so the offending timeout call is easier to spot.

Edited Aug 17, 2020 by Facundo Domínguez
Assignee
Assign to
None
Milestone
None
Assign milestone
Time tracking
None
Due date
None
Reference: ghc/ghc#18580