Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions Control/Concurrent/STM/TQueue.hs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ module Control.Concurrent.STM.TQueue (
newTQueue,
newTQueueIO,
readTQueue,
readTQueueN,
tryReadTQueue,
flushTQueue,
peekTQueue,
Expand Down Expand Up @@ -103,6 +104,60 @@ readTQueue (TQueue read write) = do
writeTVar read zs
return z


-- Logic of readTQueueN:
-- +-----------+--------------- +-----------------+
-- | write = 0 | write < N-read | write >= N-read |
-- +--------------+-----------+--------------- +-----------------+
-- | read == 0 | retry | retry | case 3 |
-- | 0 < read < N | retry | retry | case 4 |
-- +--------------+-----------+--------------- +-----------------+
-- | read >= N | . . . . . . . case 1 . . . . . . . . . |
-- +----=--------------------------------------------------------+

-- case 1a: More than N: splitAt N read -> put suffix in read and return prefix
-- case 1b: Exactly N: Reverse write into read, and return all of the old read
-- case 2: No longer exists
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renumber the cases please

-- case 3: Reverse write -> splitAt N, put suffix in read and return prefix
-- case 4: Like case 3 but prepend read onto return value

-- |Reads N values, blocking until enough are available.
-- This is likely never to return if another thread is
-- blocking on readTQueue. It has quadratic complexity
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: markup identifiers e.g. 'readTQueue'

-- in n due to each write triggering readTQueueN to calculate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: N not n

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a test in Stm066.hs. I made the other changes.

-- the length of the write side as <n items pile up there.
--
-- @since 2.5.4
readTQueueN :: TQueue a -> Int -> STM [a]
readTQueueN (TQueue read write) n = do
xs <- readTVar read
let xl = length xs
if xl > n then do -- case 1a
let (as,bs) = splitAt n xs
writeTVar read bs
pure as
else if xl == n then do -- case 1b
ys <- readTVar write
case ys of
[] -> do
writeTVar read []
retry
_ -> do
let zs = reverse ys
writeTVar write []
writeTVar read zs
pure xs
else do
ys <- readTVar write
let yl = length ys
if yl == 0 then
retry
else if yl < n - xl then retry
else do -- cases 3 and 4
let (as,bs) = splitAt (n-xl) (reverse ys)
writeTVar read bs
pure $ xs <> as

-- | A version of 'readTQueue' which does not retry. Instead it
-- returns @Nothing@ if no value is available.
tryReadTQueue :: TQueue a -> STM (Maybe a)
Expand Down
2 changes: 1 addition & 1 deletion stm.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: >=1.10
name: stm
version: 2.5.3.1
version: 2.5.4
-- don't forget to update changelog.md file!

license: BSD3
Expand Down
2 changes: 2 additions & 0 deletions testsuite/src/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import qualified Issue17
import qualified Stm052
import qualified Stm064
import qualified Stm065
import qualified Stm066

main :: IO ()
main = do
Expand All @@ -23,6 +24,7 @@ main = do
, testCase "stm052" Stm052.main
, testCase "stm064" Stm064.main
, testCase "stm065" Stm065.main
, testCase "stm066" Stm066.main
]
]

30 changes: 30 additions & 0 deletions testsuite/src/Stm066.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{-# LANGUAGE CPP #-}

{- NB: This one fails for GHC < 7.6 which had a bug exposed via
nested uses of `orElse` in `stmCommitNestedTransaction`

This was fixed in GHC via
f184d9caffa09750ef6a374a7987b9213d6db28e
-}

module Stm066 (main) where

import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TQueue
import Control.Monad (unless)

main :: IO ()
main = do
q <- atomically $ newTQueue
_ <- forkIO $ atomically $ do
writeTQueue q (1::Int)
writeTQueue q 2
writeTQueue q 3
writeTQueue q 4
l <- atomically $ do
_ <- readTQueueN q 1
readTQueueN q 3

unless (l == [2,3,4]) $
fail (show l)
1 change: 1 addition & 0 deletions testsuite/testsuite.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ test-suite stm
Stm052
Stm064
Stm065
Stm066

type: exitcode-stdio-1.0

Expand Down