summaryrefslogtreecommitdiff
path: root/src/Data/PacketQueue.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Data/PacketQueue.hs')
-rw-r--r--src/Data/PacketQueue.hs65
1 files changed, 65 insertions, 0 deletions
diff --git a/src/Data/PacketQueue.hs b/src/Data/PacketQueue.hs
new file mode 100644
index 00000000..a617d502
--- /dev/null
+++ b/src/Data/PacketQueue.hs
@@ -0,0 +1,65 @@
1-- | This module is useful for implementing a lossess protocol on top of a
2-- lossy datagram style protocol. It implements a buffer in which packets may
3-- be stored out of order, but from which they are extracted in the proper
4-- sequence.
5{-# LANGUAGE NamedFieldPuns #-}
6module Data.PacketQueue
7 ( PacketQueue
8 , new
9 , dequeue
10 , enqueue
11 ) where
12
13import Control.Concurrent.STM
14import Control.Concurrent.STM.TArray
15import Control.Monad
16import Data.Word
17import Data.Array.MArray
18
19data PacketQueue a = PacketQueue
20 { pktq :: TArray Word32 (Maybe a)
21 , seqno :: TVar Word32
22 , qsize :: Word32
23 }
24
25-- | Create a new PacketQueue.
26new :: Word32 -- ^ Capacity of queue.
27 -> Word32 -- ^ Initial sequence number.
28 -> STM (PacketQueue a)
29new capacity seqstart = do
30 let cap = if capacity `mod` 2 == 0 then capacity else capacity + 1
31 q <- newArray (0,cap - 1) Nothing
32 seqv <- newTVar seqstart
33 return PacketQueue
34 { pktq = q
35 , seqno = seqv
36 , qsize = cap
37 }
38
39-- | Retry until the next expected packet is enqueued. Then return it.
40dequeue :: PacketQueue a -> STM a
41dequeue PacketQueue { pktq, seqno, qsize } = do
42 i0 <- readTVar seqno
43 let i = i0 `mod` qsize
44 x <- maybe retry return =<< readArray pktq i
45 writeArray pktq i Nothing
46 modifyTVar' seqno succ
47 return x
48
49-- | Enqueue a packet. Packets need not be enqueued in order as long as there
50-- is spare capacity in the queue. If there is not, the packet will be
51-- silently discarded without blocking.
52enqueue :: PacketQueue a -- ^ The packet queue.
53 -> Word32 -- ^ Sequence number of the packet.
54 -> a -- ^ The packet.
55 -> STM ()
56enqueue PacketQueue{ pktq, seqno, qsize } no x = do
57 low <- readTVar seqno
58 let proj = no - low
59 -- Ignore packet if out of range.
60 when ( proj < qsize) $ do
61 let i = no `mod` qsize
62 writeArray pktq i (Just x)
63
64-- lookup :: PacketQueue a -> Word32 -> STM (Maybe a)
65-- lookup PacketQueue{ pktq, seqno, qsize } no = _todo