git.iko.soy/distributed-process
on master help sign in
Cleaned up examples and benchmarks. Found strange bug. Tweaked Process.hs for strict bytestrings.

The bug is that DemoTransport.hs will hang when trying to "killThread" (Pipes backend, demo3 and demo4), but ONLY under GHC 7.0.4 and 7.2.1. Under GHC 6.12.3 and GHC 7.4.1 it works fine! At first I thought this may be an issue with non-allocating threads not being preempted by the runtime system (and therefore not servicing the ThreadKilled asynchronous exception). But it's hard to explain that pattern of outcomes on different GHC versions.

commit48e257ad2456c1c4c953281b21c7aa80a9fa3e75 authorRyan Newton <rrnewton@gmail.com> dateSat 25 Feb 2012, 04:50 (15 years ago) parentff8d9c6
7 files changed+57−24
distributed-process/src/Control/Distributed/Process.hs+4−2 examples/DemoProcess.hs+3−1 examples/DemoTransport.hs+15−2 examples/Makefile+11−4 network-transport-pipes/network-transport-pipes.cabal+4−3 network-transport-pipes/src/Network/Transport/Pipes.hs+18−10 network-transport/network-transport.cabal+2−2
distributed-process/src/Control/Distributed/Process.hs+4−2
@@ -27,8 +27,10 @@ module Control.Distributed.Process (
2727import qualified Network.Transport as Trans
2828import Network.Transport (Transport)
2929
30−import qualified Data.ByteString.Lazy.Char8 as BS
31−import Data.ByteString.Lazy.Char8 (ByteString)
30+-- import qualified Data.ByteString.Lazy.Char8 as BS
31+-- import Data.ByteString.Lazy.Char8 (ByteString)
32+import qualified Data.ByteString.Char8 as BS
33+import Data.ByteString.Char8 (ByteString)
3234import qualified Data.IntMap as IntMap
3335import Data.IntMap (IntMap)
3436import Control.Applicative
examples/DemoProcess.hs+3−1
@@ -1,4 +1,4 @@
1−module DemoProcess where
1+module Main where
22
33import Control.Distributed.Process
44import Control.Concurrent (threadDelay)
@@ -32,3 +32,5 @@ logger n = do
3232 str <- expect
3333 liftIO . putStrLn $ show n ++ ": " ++ str
3434 logger (n+1)
35+
36+main = demo1
examples/DemoTransport.hs+15−2
@@ -9,7 +9,8 @@ import Network.Transport.TCP (mkTransport, TCPConfig (..))
99import Control.Concurrent
1010import Control.Monad
1111
12−import qualified Data.ByteString.Lazy.Char8 as BS
12+-- import qualified Data.ByteString.Lazy.Char8 as BS
13+import qualified Data.ByteString.Char8 as BS
1314
1415import Data.IORef
1516import Debug.Trace
@@ -23,6 +24,9 @@ tcp = mkTCPOff 8080
2324mvar = return Network.Transport.MVar.mkTransport
2425pipes = return Network.Transport.Pipes.mkTransport
2526
27+tcp :: IO (IO Transport)
28+mvar :: IO (IO Transport)
29+pipes :: IO (IO Transport)
2630
2731-------------------------------------------
2832-- Example programs using backend directly
@@ -103,11 +107,13 @@ demo3 mktrans = do
103107 send sourceEnd2 [BS.pack "hello2"]
104108
105109 threadDelay 100000
106−
110+ putStrLn "demo3: Time, up, killing threads & closing transports.."
107111 killThread threadId1
108112 killThread threadId2
113+ putStrLn "demo3: Threads killed."
109114 closeTransport trans1
110115 closeTransport trans2
116+ putStrLn "demo3: Done."
111117
112118
113119-- | Check that two different connections on the same transport can be created.
@@ -129,9 +135,14 @@ demo4 mktrans = do
129135
130136 threadDelay 100000
131137
138+ putStrLn "demo4: Time, up, killing threads & closing transports.."
132139 killThread threadId1
133140 killThread threadId2
141+ putStrLn "demo4: Threads killed."
134142 closeTransport trans
143+ putStrLn "demo4: Done."
144+
145+
135146
136147--------------------------------------------------------------------------------
137148
@@ -151,10 +162,12 @@ mkTCPOff off = do
151162runWAllTranports :: (IO Transport -> IO ()) -> Int -> IO ()
152163runWAllTranports demo offset = do
153164 putStrLn "------------------------------------------------------------"
165+{-
154166 putStrLn " MVAR transport:"
155167 mvar >>= demo
156168 putStrLn "\n TCP transport:"
157169 tcp >>= demo
170+-}
158171 putStrLn "\n PIPES transport:"
159172 pipes >>= demo
160173 putStrLn "\n"
examples/Makefile+11−4
@@ -4,10 +4,17 @@ ifeq ($(GHC),)
44 GHC=ghc
55endif
66
7−all:
8− $(GHC) -threaded --make -i../network-transport/src DemoTransport.hs -o DemoTransport.exe -fforce-recomp
7+INCLUDES= -i../network-transport/src -i../network-transport-pipes/src -i../distributed-process/src
98
9+EXMPLS= DemoTransport.exe DemoProcess.exe
1010
11−clean:
12− rm -f *.hi *.o DemoTransport.exe
11+all: $(EXMPLS)
12+
13+$(EXMPLS): %.exe: %.hs
14+ $(GHC) -O2 -rtsopts -threaded --make $(INCLUDES) $< -o $@
1315
16+# transport:
17+# $(GHC) -threaded --make -i../network-transport/src DemoTransport.hs -o DemoTransport.exe -fforce-recomp
18+
19+clean:
20+ rm -f *.hi *.o $(EXMPLS)
network-transport-pipes/network-transport-pipes.cabal+4−3
@@ -14,14 +14,15 @@ Cabal-Version: >=1.2
1414
1515Library
1616 Build-Depends: base >= 3 && < 5,
17− binary >= 0.5,
17+-- binary >= 0.5,
1818 cereal,
1919 bytestring >= 0.9,
2020 network-transport >= 0.0.1.1,
21− containers >= 0.4,
21+-- containers >= 0.4,
22+ containers >= 0.3,
2223-- network >= 2.3,
2324-- safe >= 0.3,
24− unix >= 2.5.0.0,
25+ unix >= 2.4,
2526 random,
2627 directory,
2728 unix-bytestring >= 0.3.5.3
network-transport-pipes/src/Network/Transport/Pipes.hs+18−10
@@ -6,7 +6,6 @@
66
77-- * Add support for messages greater than 4096 bytes.
88-- * debug ODD problem with CEREAL below
9−-- * switch to unix-bytestring after that package is updated for 7.4.1
109
1110----------------------------------------------------------------------------------------------------
1211
@@ -88,9 +87,12 @@ fileFlags =
8887
8988mkTransport :: IO Transport
9089mkTransport = do
91− uid <- randomIO :: IO Word64
90+-- uid <- randomIO :: IO Word64
91+ -- For backwards compatibility we shouldn't assume a Random instance for Word64:
92+ uid <- randomIO :: IO Int
93+
9294 lock <- newMVar ()
93− let filename = "/tmp/pipe_"++show uid
95+ let filename = "/tmp/pipe_"++show (abs uid)
9496 createNamedPipe filename $ unionFileModes ownerReadMode ownerWriteMode
9597
9698 return Transport
@@ -128,6 +130,7 @@ mkTransport = do
128130 SourceEnd
129131 { send = \bsls -> do
130132 -- ThreadSafe: This may happen on multiple processes/threads:
133+ -- We don't need to lock because the write is atomic (for <4096):
131134 let msgsize :: Word32 = fromIntegral$ foldl' (\n s -> n + BS.length s) 0 bsls
132135 when (msgsize > 4096)$ -- TODO, look up PIPE_BUF in foreign code
133136 error "Message larger than blocksize written atomically to a named pipe. Unimplemented."
@@ -162,10 +165,14 @@ mkTransport = do
162165 { receive = do
163166 fd <- readMVar mv -- Make sure Fd is there before
164167
165− -- This should only happen on a single process. But it may
168+ -- This should only happen on a *single* process. But it may
166169 -- happen on multiple threads so we grab a lock.
170+
171+ -- If we don't lock, we cannot atomically read the length
172+ -- and THEN read the payload. (A single read could be
173+ -- atomic, but not two reads.)
167174 takeMVar lock
168−
175+
169176 let spinread :: Int -> IO BS.ByteString
170177 spinread desired = do
171178
@@ -174,23 +181,24 @@ mkTransport = do
174181
175182 case BS.length bs of
176183 n | n == desired -> return bs
177− 0 -> do threadDelay (10*1000)
178− spinread desired
184+ -- Because we're in non-blocking mode we deal with failed reads thusly:
185+-- 0 -> do threadDelay (10*1000)
186+-- spinread desired
187+ 0 -> error$ "receive: read zero bytes from pipe. Even in non-blocking mode should have had an EAGAIN error instead."
179188 l -> error$ "Inclomplete read expected either 0 bytes or complete msg ("++
180189 show desired ++" bytes) got "++ show l ++ " bytes"
181190
182191 hdr <- spinread sizeof_header
183− let -- decoded :: BSS.ByteString
192+ let
184193#ifdef CEREAL
185−-- decoded = decode (BSS.concat$ BS.toChunks hdr)
186194 decoded = decode hdr
187195#else
188−-- decoded = decode hdr
189196 decoded = decode (BS.fromChunks [hdr])
190197#endif
191198 payload <- case decoded of
192199 Left err -> error$ "ERROR: "++ err
193200 Right size -> spinread (fromIntegral (size::Word32))
201+
194202 putMVar lock ()
195203 return [payload] -- How terribly listy.
196204 , closeTargetEnd = do
network-transport/network-transport.cabal+2−2
@@ -16,13 +16,13 @@ Cabal-Version: >=1.2
1616
1717Library
1818 Build-Depends: base >= 3 && < 5,
19− binary >= 0.5,
19+-- binary >= 0.5,
2020 bytestring >= 0.9,
2121 cereal >= 0.3,
2222 containers >= 0.4,
2323 network >= 2.3,
2424 safe >= 0.3,
25− unix >= 2.5.0.0
25+ unix >= 2.4
2626 Exposed-modules: Network.Transport,
2727 Network.Transport.MVar,
2828 Network.Transport.TCP