1 -----------------------------------------------------------------------------
3 -- Module : Control.Concurrent.Chan
4 -- Copyright : (c) The University of Glasgow 2001
5 -- License : BSD-style (see the file libraries/base/LICENSE)
7 -- Maintainer : libraries@haskell.org
8 -- Stability : experimental
9 -- Portability : non-portable (concurrency)
11 -- Unbounded channels.
13 -----------------------------------------------------------------------------
15 module Control.Concurrent.Chan
21 newChan, -- :: IO (Chan a)
22 writeChan, -- :: Chan a -> a -> IO ()
23 readChan, -- :: Chan a -> IO a
24 dupChan, -- :: Chan a -> IO (Chan a)
25 unGetChan, -- :: Chan a -> a -> IO ()
26 isEmptyChan, -- :: Chan a -> IO Bool
29 getChanContents, -- :: Chan a -> IO [a]
30 writeList2Chan, -- :: Chan a -> [a] -> IO ()
35 import System.IO.Unsafe ( unsafeInterleaveIO )
36 import Control.Concurrent.MVar
41 -- A channel is represented by two @MVar@s keeping track of the two ends
42 -- of the channel contents,i.e., the read- and write ends. Empty @MVar@s
43 -- are used to handle consumers trying to read from an empty channel.
45 -- |'Chan' is an abstract type representing an unbounded FIFO channel.
47 = Chan (MVar (Stream a))
50 INSTANCE_TYPEABLE1(Chan,chanTc,"Chan")
52 type Stream a = MVar (ChItem a)
54 data ChItem a = ChItem a (Stream a)
56 -- See the Concurrent Haskell paper for a diagram explaining the
57 -- how the different channel operations proceed.
59 -- @newChan@ sets up the read and write end of a channel by initialising
60 -- these two @MVar@s with an empty @MVar@.
62 -- |Build and returns a new instance of 'Chan'.
63 newChan :: IO (Chan a)
68 return (Chan read write)
70 -- To put an element on a channel, a new hole at the write end is created.
71 -- What was previously the empty @MVar@ at the back of the channel is then
72 -- filled in with a new stream element holding the entered value and the
75 -- |Write a value to a 'Chan'.
76 writeChan :: Chan a -> a -> IO ()
77 writeChan (Chan _read write) val = do
78 new_hole <- newEmptyMVar
79 modifyMVar_ write $ \old_hole -> do
80 putMVar old_hole (ChItem val new_hole)
83 -- |Read the next value from the 'Chan'.
84 readChan :: Chan a -> IO a
85 readChan (Chan read _write) = do
86 modifyMVar read $ \read_end -> do
87 (ChItem val new_read_end) <- readMVar read_end
88 -- Use readMVar here, not takeMVar,
89 -- else dupChan doesn't work
90 return (new_read_end, val)
92 -- |Duplicate a 'Chan': the duplicate channel begins empty, but data written to
93 -- either channel from then on will be available from both. Hence this creates
94 -- a kind of broadcast channel, where data written by anyone is seen by
96 dupChan :: Chan a -> IO (Chan a)
97 dupChan (Chan _read write) = do
98 hole <- readMVar write
99 new_read <- newMVar hole
100 return (Chan new_read write)
102 -- |Put a data item back onto a channel, where it will be the next item read.
103 unGetChan :: Chan a -> a -> IO ()
104 unGetChan (Chan read _write) val = do
105 new_read_end <- newEmptyMVar
106 modifyMVar_ read $ \read_end -> do
107 putMVar new_read_end (ChItem val read_end)
110 -- |Returns 'True' if the supplied 'Chan' is empty.
111 isEmptyChan :: Chan a -> IO Bool
112 isEmptyChan (Chan read write) = do
113 withMVar read $ \r -> do
118 -- Operators for interfacing with functional streams.
120 -- |Return a lazy list representing the contents of the supplied
121 -- 'Chan', much like 'System.IO.hGetContents'.
122 getChanContents :: Chan a -> IO [a]
124 = unsafeInterleaveIO (do
126 xs <- getChanContents ch
130 -- |Write an entire list of items to a 'Chan'.
131 writeList2Chan :: Chan a -> [a] -> IO ()
132 writeList2Chan ch ls = sequence_ (map (writeChan ch) ls)