Skip to content

Commit fe042c6

Browse files
committed
Good enough for now
1 parent 07df105 commit fe042c6

File tree

4 files changed

+92
-0
lines changed

4 files changed

+92
-0
lines changed

Control/Concurrent/STM/TQueue.hs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ module Control.Concurrent.STM.TQueue (
3838
newTQueue,
3939
newTQueueIO,
4040
readTQueue,
41+
readTQueueN,
4142
tryReadTQueue,
4243
flushTQueue,
4344
peekTQueue,
@@ -103,6 +104,64 @@ readTQueue (TQueue read write) = do
103104
writeTVar read zs
104105
return z
105106

107+
108+
-- +-----------+--------------- +-----------------+
109+
-- | write = 0 | write < N-read | write >= N-read |
110+
-- +--------------+-----------+--------------- +-----------------+
111+
-- | read == 0 | retry | case 2 | case 3 |
112+
-- | 0 < read < N | retry | retry | case 4 |
113+
-- +--------------+-----------+--------------- +-----------------+
114+
-- | read >= N | . . . . . . . case 1 . . . . . . . . . |
115+
-- +----=--------------------------------------------------------+
116+
117+
-- case 1a: More than N: splitAt N read -> put suffix in read and return prefix
118+
-- case 1b: Exactly N: Reverse write into read, and return all of the old read
119+
-- case 2: Move reverse write to read, retry
120+
-- case 3: Reverse write -> splitAt N, put suffix in read and return prefix
121+
-- case 4: Like case 3 but prepend read onto return value
122+
123+
-- |Reads N values, blocking until enough are available
124+
readTQueueN :: Int -> TQueue a -> STM [a]
125+
readTQueueN n (TQueue read write) = do
126+
xs <- readTVar read
127+
let xl = length xs
128+
if xl > n then do -- case 1a
129+
let (as,bs) = splitAt n xs
130+
writeTVar read bs
131+
pure as
132+
else if xl == n then do -- case 1b
133+
ys <- readTVar write
134+
case ys of
135+
[] -> do
136+
writeTVar read []
137+
retry
138+
_ -> do
139+
let zs = reverse ys
140+
writeTVar write []
141+
writeTVar read zs
142+
pure xs
143+
else do
144+
ys <- readTVar write
145+
let yl = length ys
146+
if yl == 0 then
147+
retry
148+
else if yl < n - xl then
149+
if xl == 0 then do -- case 2
150+
let zs = reverse ys
151+
writeTVar write []
152+
writeTVar read zs
153+
retry
154+
else
155+
retry
156+
else do -- cases 3 and 4
157+
let (as,bs) = splitAt (n-xl) (reverse ys)
158+
writeTVar read bs
159+
pure $ xs <> as
160+
161+
162+
163+
164+
106165
-- | A version of 'readTQueue' which does not retry. Instead it
107166
-- returns @Nothing@ if no value is available.
108167
tryReadTQueue :: TQueue a -> STM (Maybe a)

testsuite/src/Main.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import qualified Issue17
1010
import qualified Stm052
1111
import qualified Stm064
1212
import qualified Stm065
13+
import qualified Stm066
1314

1415
main :: IO ()
1516
main = do
@@ -23,6 +24,7 @@ main = do
2324
, testCase "stm052" Stm052.main
2425
, testCase "stm064" Stm064.main
2526
, testCase "stm065" Stm065.main
27+
, testCase "stm066" Stm066.main
2628
]
2729
]
2830

testsuite/src/Stm066.hs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{-# LANGUAGE CPP #-}
2+
3+
{- NB: This one fails for GHC < 7.6 which had a bug exposed via
4+
nested uses of `orElse` in `stmCommitNestedTransaction`
5+
6+
This was fixed in GHC via
7+
f184d9caffa09750ef6a374a7987b9213d6db28e
8+
-}
9+
10+
module Stm066 (main) where
11+
12+
import Control.Concurrent
13+
import Control.Concurrent.STM
14+
import Control.Concurrent.STM.TQueue
15+
import Control.Monad (unless)
16+
17+
main :: IO ()
18+
main = do
19+
q <- atomically $ newTQueue
20+
_ <- forkIO $ atomically $ do
21+
writeTQueue q (1::Int)
22+
writeTQueue q 2
23+
writeTQueue q 3
24+
writeTQueue q 4
25+
l <- atomically $ do
26+
_ <- readTQueueN 1 q
27+
readTQueueN 3 q
28+
29+
unless (l == [2,3,4]) $
30+
fail (show l)

testsuite/testsuite.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ test-suite stm
3737
Stm052
3838
Stm064
3939
Stm065
40+
Stm066
4041

4142
type: exitcode-stdio-1.0
4243

0 commit comments

Comments
 (0)