module Dingo.Internal.Queue
       ( readChanTimeout
       ) where

import Control.Concurrent (forkIO, threadDelay, killThread, myThreadId)
import Control.Concurrent.Chan.Strict (Chan, readChan)
import Control.Concurrent.MVar.Strict (newEmptyMVar, putMVar, takeMVar)
import Control.DeepSeq (NFData)

-- Read a Chan with timeout.
readChanTimeout :: NFData a => Chan a -> Int -> IO (Maybe a)
readChanTimeout ch timeout = do
  result <- newEmptyMVar
  _ <- forkIO $ do
    wid <- myThreadId
    readerThreadId <- forkIO $ do
      x <- readChan ch
      killThread wid
      putMVar result (Just x)
    threadDelay timeout
    killThread readerThreadId
    putMVar result Nothing
  -- Block waiting for either timeout or the read.
  takeMVar result