1 -----------------------------------------------------------------------------
3 -- Module : Control.Concurrent.Chan
4 -- Copyright : (c) The University of Glasgow 2001
5 -- License : BSD-style (see the file libraries/core/LICENSE)
7 -- Maintainer : libraries@haskell.org
8 -- Stability : experimental
9 -- Portability : non-portable
11 -- $Id: Chan.hs,v 1.1 2001/06/28 14:15:02 simonmar Exp $
13 -- Standard, unbounded channel abstraction.
15 -----------------------------------------------------------------------------
17 module Control.Concurrent.Chan
21 , newChan -- :: IO (Chan a)
24 , writeChan -- :: Chan a -> a -> IO ()
25 , readChan -- :: Chan a -> IO a
26 , dupChan -- :: Chan a -> IO (Chan a)
27 , unGetChan -- :: Chan a -> a -> IO ()
29 , isEmptyChan -- :: Chan a -> IO Bool
32 , getChanContents -- :: Chan a -> IO [a]
33 , writeList2Chan -- :: Chan a -> [a] -> IO ()
39 import System.IO.Unsafe ( unsafeInterleaveIO )
40 import Control.Concurrent.MVar
42 -- A channel is represented by two @MVar@s keeping track of the two ends
43 -- of the channel contents,i.e., the read- and write ends. Empty @MVar@s
44 -- are used to handle consumers trying to read from an empty channel.
47 = Chan (MVar (Stream a))
50 type Stream a = MVar (ChItem a)
52 data ChItem a = ChItem a (Stream a)
54 -- See the Concurrent Haskell paper for a diagram explaining the
55 -- how the different channel operations proceed.
57 -- @newChan@ sets up the read and write end of a channel by initialising
58 -- these two @MVar@s with an empty @MVar@.
60 newChan :: IO (Chan a)
65 return (Chan read write)
67 -- To put an element on a channel, a new hole at the write end is created.
68 -- What was previously the empty @MVar@ at the back of the channel is then
69 -- filled in with a new stream element holding the entered value and the
72 writeChan :: Chan a -> a -> IO ()
73 writeChan (Chan _read write) val = do
74 new_hole <- newEmptyMVar
75 modifyMVar_ write $ \old_hole -> do
76 putMVar old_hole (ChItem val new_hole)
79 readChan :: Chan a -> IO a
80 readChan (Chan read _write) = do
81 modifyMVar read $ \read_end -> do
82 (ChItem val new_read_end) <- readMVar read_end
83 -- Use readMVar here, not takeMVar,
84 -- else dupChan doesn't work
85 return (new_read_end, val)
87 dupChan :: Chan a -> IO (Chan a)
88 dupChan (Chan _read write) = do
89 hole <- readMVar write
90 new_read <- newMVar hole
91 return (Chan new_read write)
93 unGetChan :: Chan a -> a -> IO ()
94 unGetChan (Chan read _write) val = do
95 new_read_end <- newEmptyMVar
96 modifyMVar_ read $ \read_end -> do
97 putMVar new_read_end (ChItem val read_end)
100 isEmptyChan :: Chan a -> IO Bool
101 isEmptyChan (Chan read write) = do
102 withMVar read $ \r -> do
107 -- Operators for interfacing with functional streams.
109 getChanContents :: Chan a -> IO [a]
111 = unsafeInterleaveIO (do
113 xs <- getChanContents ch
118 writeList2Chan :: Chan a -> [a] -> IO ()
119 writeList2Chan ch ls = sequence_ (map (writeChan ch) ls)