[project @ 1999-01-14 18:21:49 by sof]
[ghc-hetmet.git] / ghc / lib / concurrent / Channel.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1995-97
3 %
4 \section[Channel]{Unbounded Channels}
5
6 Standard, unbounded channel abstraction.
7
8 \begin{code}
9 module Channel
10        (
11          {- abstract type defined -}
12         Chan,
13
14          {- creator -}
15         newChan,         -- :: IO (Chan a)
16
17          {- operators -}
18         writeChan,       -- :: Chan a -> a -> IO ()
19         readChan,        -- :: Chan a -> IO a
20         dupChan,         -- :: Chan a -> IO (Chan a)
21         unGetChan,       -- :: Chan a -> a -> IO ()
22
23          {- stream interface -}
24         getChanContents, -- :: Chan a -> IO [a]
25         writeList2Chan   -- :: Chan a -> [a] -> IO ()
26
27        ) where
28
29 import Prelude
30 import PrelConc
31 import PrelST
32 import PrelIOBase ( unsafeInterleaveIO )
33 \end{code}
34
35 A channel is represented by two @MVar@s keeping track of the two ends
36 of the channel contents,i.e.,  the read- and write ends. Empty @MVar@s
37 are used to handle consumers trying to read from an empty channel.
38
39 \begin{code}
40 data Chan a
41  = Chan (MVar (Stream a))
42         (MVar (Stream a))
43
44 type Stream a = MVar (ChItem a)
45
46 data ChItem a = ChItem a (Stream a)
47 \end{code}
48
49 See the Concurrent Haskell paper for a diagram explaining the
50 how the different channel operations proceed.
51
52 @newChan@ sets up the read and write end of a channel by initialising
53 these two @MVar@s with an empty @MVar@.
54
55 \begin{code}
56 newChan :: IO (Chan a)
57 newChan = do
58    hole  <- newEmptyMVar
59    read  <- newMVar hole
60    write <- newMVar hole
61    return (Chan read write)
62 \end{code}
63
64 To put an element on a channel, a new hole at the write end is created.
65 What was previously the empty @MVar@ at the back of the channel is then
66 filled in with a new stream element holding the entered value and the
67 new hole.
68
69 \begin{code}
70 writeChan :: Chan a -> a -> IO ()
71 writeChan (Chan read write) val = do
72    new_hole <- newEmptyMVar
73    old_hole <- takeMVar write
74    putMVar write new_hole
75    putMVar old_hole (ChItem val new_hole)
76
77 readChan :: Chan a -> IO a
78 readChan (Chan read write) = do
79   read_end                  <- takeMVar read
80   (ChItem val new_read_end) <- takeMVar read_end
81   putMVar read new_read_end
82   return val
83
84
85 dupChan :: Chan a -> IO (Chan a)
86 dupChan (Chan read write) = do
87    new_read <- newEmptyMVar
88    hole     <- readMVar write
89    putMVar new_read hole
90    return (Chan new_read write)
91
92 unGetChan :: Chan a -> a -> IO ()
93 unGetChan (Chan read write) val = do
94    new_read_end <- newEmptyMVar
95    read_end     <- takeMVar read
96    putMVar new_read_end (ChItem val read_end)
97    putMVar read new_read_end
98
99 \end{code}
100
101 Operators for interfacing with functional streams.
102
103 \begin{code}
104 getChanContents :: Chan a -> IO [a]
105 getChanContents ch
106   = unsafeInterleaveIO (do
107         x  <- readChan ch
108         xs <- getChanContents ch
109         return (x:xs)
110     )
111
112 -------------
113 writeList2Chan :: Chan a -> [a] -> IO ()
114 writeList2Chan ch ls = sequence_ (map (writeChan ch) ls)
115
116 \end{code}