diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,9 +1,9 @@
 import Distribution.Simple
 import Distribution.Simple.LocalBuildInfo (LocalBuildInfo(buildDir))
 import Distribution.Simple.Program
-import System.Cmd
 import System.Directory
 import System.Exit
+import System.Process
 
 main = copyFile "debian/changelog" "changelog" >>
        defaultMainWithHooks simpleUserHooks {
diff --git a/System/Process/Read.hs b/System/Process/Read.hs
--- a/System/Process/Read.hs
+++ b/System/Process/Read.hs
@@ -4,7 +4,13 @@
     , readCreateProcess
     , readProcessWithExitCode
     , readProcess
+    , Chunked(..)
+    , readProcessInterleaved
+    , readInterleaved
+    , Output(..)
+    , readProcessChunks
     ) where
 
-import System.Process.Read.Chars
-import System.Process.Read.Instances ()
+import System.Process.Read.Chunks
+import System.Process.Read.ListLike
+import System.Process.Read.Interleaved
diff --git a/System/Process/Read/Chars.hs b/System/Process/Read/Chars.hs
deleted file mode 100644
--- a/System/Process/Read/Chars.hs
+++ /dev/null
@@ -1,190 +0,0 @@
--- | Versions of the functions in module 'System.Process.Read' specialized for type ByteString.
-{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies #-}
-module System.Process.Read.Chars (
-  ListLikePlus(..),
-  readCreateProcessWithExitCode,
-  readCreateProcess,
-  readProcessWithExitCode,
-  readProcess,
-  ) where
-
-import Control.Concurrent
-import Control.Exception as E (SomeException, onException, evaluate, catch, try, throwIO, mask)
-import Control.Monad
-import Data.ListLike (ListLike(..), ListLikeIO(..))
-import Data.ListLike.Text.Text ()
-import Data.ListLike.Text.TextLazy ()
-import GHC.IO.Exception (IOErrorType(OtherError, ResourceVanished), IOException(ioe_type))
-import Prelude hiding (null, length)
-import System.Exit (ExitCode(ExitSuccess, ExitFailure))
-import System.IO hiding (hPutStr, hGetContents)
-import qualified System.IO.Error as IO
-import System.Process (CreateProcess(..), StdStream(CreatePipe, Inherit), proc,
-                       CmdSpec(RawCommand, ShellCommand), showCommandForUser,
-                       createProcess, waitForProcess, terminateProcess)
-
--- | Class of types which can be used as the input and outputs of the process functions.
-class (Integral (LengthType a), ListLikeIO a c) => ListLikePlus a c where
-  type LengthType a
-  binary :: a -> [Handle] -> IO ()
-  -- ^ This should call 'hSetBinaryMode' on each handle if a is a
-  -- ByteString type, so that it doesn't attempt to decode the text
-  -- using the current locale.
-  lazy :: a -> Bool
-  length' :: a -> LengthType a
-
--- | A polymorphic implementation of
--- 'System.Process.readProcessWithExitCode' with a few
--- generalizations:
---
---    1. The input and outputs can be any instance of 'ListLikePlus'.
---
---    2. Allows you to modify the 'CreateProcess' record before the process starts
---
---    3. Takes a 'CmdSpec', so you can launch either a 'RawCommand' or a 'ShellCommand'.
-readCreateProcessWithExitCode
-    :: forall a c.
-       ListLikePlus a c =>
-       CreateProcess   -- ^ process to run
-    -> a               -- ^ standard input
-    -> IO (ExitCode, a, a) -- ^ exitcode, stdout, stderr, exception
-readCreateProcessWithExitCode p input = mask $ \restore -> do
-    (Just inh, Just outh, Just errh, pid) <-
-        createProcess (p {std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe })
-
-    flip onException
-      (do hClose inh; hClose outh; hClose errh;
-          terminateProcess pid; waitForProcess pid) $ restore $ do
-      (out, err) <- (if lazy input then readLazy else readStrict) inh outh errh
-
-      hClose outh
-      hClose errh
-
-      -- wait on the process
-      ex <- waitForProcess pid
-
-      return (ex, out, err)
-    where
-      readLazy :: Handle -> Handle -> Handle -> IO (a, a)
-      readLazy inh outh errh =
-           do out <- hGetContents outh
-              waitOut <- forkWait $ void $ force $ out
-              err <- hGetContents errh
-              waitErr <- forkWait $ void $ force $ err
-              -- now write and flush any input
-              writeInput inh
-              -- wait on the output
-              waitOut
-              waitErr
-              return (out, err)
-
-      readStrict :: Handle -> Handle -> Handle -> IO (a, a)
-      readStrict inh outh errh =
-           do -- fork off a thread to start consuming stdout
-              waitOut <- forkWait $ hGetContents outh
-              -- fork off a thread to start consuming stderr
-              waitErr <- forkWait $ hGetContents errh
-              -- now write and flush any input
-              writeInput inh
-              -- wait on the output
-              out <- waitOut
-              err <- waitErr
-              return (out, err)
-
-      writeInput :: Handle -> IO ()
-      writeInput inh = do
-        (do unless (null input) (hPutStr inh input >> hFlush inh)
-            hClose inh) `E.catch` resourceVanished (\ _ -> return ())
-
--- | A polymorphic implementation of
--- 'System.Process.readProcessWithExitCode' in terms of
--- 'readCreateProcessWithExitCode'.
-readProcessWithExitCode
-    :: ListLikePlus a c =>
-       FilePath                 -- ^ command to run
-    -> [String]                 -- ^ any arguments
-    -> a               -- ^ standard input
-    -> IO (ExitCode, a, a) -- ^ exitcode, stdout, stderr
-readProcessWithExitCode cmd args input = readCreateProcessWithExitCode (proc cmd args) input
-
--- | Implementation of 'System.Process.readProcess' in terms of
--- 'readCreateProcess'.
-readProcess
-    :: ListLikePlus a c =>
-       FilePath                 -- ^ command to run
-    -> [String]                 -- ^ any arguments
-    -> a               -- ^ standard input
-    -> IO a            -- ^ stdout
-readProcess cmd args = readCreateProcess (proc cmd args)
-
--- | A polymorphic implementation of 'System.Process.readProcess' with a few generalizations:
---
---    1. The input and outputs can be any instance of 'ListLikePlus'.
---
---    2. Allows you to modify the 'CreateProcess' record before the process starts
---
---    3. Takes a 'CmdSpec', so you can launch either a 'RawCommand' or a 'ShellCommand'.
-readCreateProcess
-    :: ListLikePlus a c =>
-       CreateProcess   -- ^ process to run
-    -> a               -- ^ standard input
-    -> IO a            -- ^ stdout
-readCreateProcess p input = mask $ \restore -> do
-    (Just inh, Just outh, _, pid) <-
-        createProcess (p {std_in = CreatePipe, std_out = CreatePipe, std_err = Inherit })
-
-    flip onException
-      (do hClose inh; hClose outh;
-          terminateProcess pid; waitForProcess pid) $ restore $ do
-      out <- (if lazy input then readLazy else readStrict) inh outh
-
-      hClose outh
-
-      -- wait on the process
-      ex <- waitForProcess pid
-
-      case ex of
-        ExitSuccess   -> return out
-        ExitFailure r -> ioError (mkError "readCreateProcess: " (cmdspec p) r)
-    where
-      readLazy inh outh =
-          do -- fork off a thread to start consuming stdout
-             out <- hGetContents outh
-             waitOut <- forkWait $ void $ force $ out
-             writeInput inh
-             waitOut
-             return out
-
-      readStrict inh outh =
-          do waitOut <- forkWait $ hGetContents outh
-             writeInput inh
-             waitOut
-
-      writeInput inh = do
-         (do unless (null input) (hPutStr inh input >> hFlush inh)
-             hClose inh) `E.catch` resourceVanished (\ _ -> return ())
-
-forkWait :: IO a -> IO (IO a)
-forkWait a = do
-  res <- newEmptyMVar
-  _ <- mask $ \restore -> forkIO $ try (restore a) >>= putMVar res
-  return (takeMVar res >>= either (\ex -> throwIO (ex :: SomeException)) return)
-
--- | Wrapper for a process that provides a handler for the
--- ResourceVanished exception.  This is frequently an exception we
--- wish to ignore, because many processes will deliberately exit
--- before they have read all of their input.
-resourceVanished :: (IOError -> IO a) -> IOError -> IO a
-resourceVanished epipe e = if ioe_type e == ResourceVanished then epipe e else ioError e
-
--- | Create an exception for a process that exited abnormally.
-mkError :: String -> CmdSpec -> Int -> IOError
-mkError prefix (RawCommand cmd args) r =
-    IO.mkIOError OtherError (prefix ++ showCommandForUser cmd args ++ " (exit " ++ show r ++ ")")
-                 Nothing Nothing
-mkError prefix (ShellCommand cmd) r =
-    IO.mkIOError OtherError (prefix ++ cmd ++ " (exit " ++ show r ++ ")")
-                 Nothing Nothing
-
-force :: forall a c. ListLikePlus a c => a -> IO (LengthType a)
-force x = evaluate $ length' $ x
diff --git a/System/Process/Read/Chunks.hs b/System/Process/Read/Chunks.hs
new file mode 100644
--- /dev/null
+++ b/System/Process/Read/Chunks.hs
@@ -0,0 +1,19 @@
+module System.Process.Read.Chunks
+    ( Output(..)
+    , readProcessChunks
+    ) where
+
+import Control.DeepSeq (NFData)
+import System.Exit (ExitCode)
+import System.Process (CreateProcess)
+import System.Process.Read.Interleaved
+
+-- | This lets us use deepseq's force on the stream of data returned
+-- by readProcessChunks.
+instance NFData ExitCode
+
+data Output a = Stdout a | Stderr a | Result ExitCode | Exception IOError deriving (Eq, Show)
+
+readProcessChunks :: (Chunked a c) => CreateProcess -> a -> IO [Output a]
+readProcessChunks p input =
+    readProcessInterleaved (\ x -> [Result x]) (\ x -> [Stdout x]) (\ x -> [Stderr x]) p input
diff --git a/System/Process/Read/Instances.hs b/System/Process/Read/Instances.hs
deleted file mode 100644
--- a/System/Process/Read/Instances.hs
+++ /dev/null
@@ -1,43 +0,0 @@
-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, TypeSynonymInstances #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-module System.Process.Read.Instances where
-
-import qualified Data.ByteString as B
-import qualified Data.ByteString.Lazy as L
-import Data.Int (Int64)
-import qualified Data.Text as T
-import qualified Data.Text.Lazy as LT
-import Data.Word (Word8)
-import Prelude hiding (catch)
-import System.IO (hSetBinaryMode)
-import System.Process.Read.Chars (ListLikePlus(..))
-
-instance ListLikePlus String Char where
-  type LengthType String = Int
-  binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles (because internally this uses lazy bytestrings)
-  lazy _ = True
-  length' = length
-
-instance ListLikePlus B.ByteString Word8 where
-  type LengthType B.ByteString = Int
-  binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles
-  lazy _ = False
-  length' = B.length
-
-instance ListLikePlus L.ByteString Word8 where
-  type LengthType L.ByteString = Int64
-  binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles
-  lazy _ = True
-  length' = L.length
-
-instance ListLikePlus T.Text Char where
-  type LengthType T.Text = Int
-  binary _ _ = return ()
-  lazy _ = False
-  length' = T.length
-
-instance ListLikePlus LT.Text Char where
-  type LengthType LT.Text = Int64
-  binary _ _ = return ()
-  lazy _ = True
-  length' = LT.length
diff --git a/System/Process/Read/Interleaved.hs b/System/Process/Read/Interleaved.hs
new file mode 100644
--- /dev/null
+++ b/System/Process/Read/Interleaved.hs
@@ -0,0 +1,117 @@
+-- | Read the output of several file descriptors concurrently,
+-- preserving the order in which the chunks are read.
+{-# LANGUAGE CPP, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeSynonymInstances #-}
+{-# OPTIONS_GHC -Wall #-}
+module System.Process.Read.Interleaved
+    ( Chunked(..)
+    , readProcessInterleaved
+    , readInterleaved
+    ) where
+
+import Control.Concurrent (forkIO, MVar, newEmptyMVar, putMVar, takeMVar)
+import Control.Exception as E (onException, catch, mask, try, throwIO, SomeException)
+import Control.Monad (unless)
+import qualified Data.ByteString as ByteString
+import qualified Data.ByteString.Lazy as ByteString.Lazy
+import Data.List as List (map)
+import Data.ListLike (ListLike(..), ListLikeIO(..))
+import Data.Monoid (Monoid, (<>))
+import Data.Text (Text)
+import qualified Data.Text.Lazy as Text.Lazy (Text, toChunks, fromChunks)
+import Data.Word (Word8)
+import GHC.IO.Exception (IOErrorType(ResourceVanished), IOException(ioe_type))
+import Prelude hiding (null, length, rem)
+import System.Exit (ExitCode)
+import System.IO hiding (hPutStr, hGetContents)
+import System.IO.Unsafe (unsafeInterleaveIO)
+import System.Process (CreateProcess(..), StdStream(CreatePipe),
+                       createProcess, waitForProcess, terminateProcess)
+import System.Process.Read.ListLike (ListLikePlus(..))
+
+-- | Class of types which can also be used by 'System.Process.Read.readProcessChunks'.
+class ListLikePlus a c => Chunked a c where
+  toChunks :: a -> [a]
+
+instance Chunked ByteString.Lazy.ByteString Word8 where
+  toChunks = List.map (ByteString.Lazy.fromChunks . (: [])) . ByteString.Lazy.toChunks
+
+-- I have to assume that this is not prone to utf8 decode errors.
+-- When I was converting lazy ByteStrings to Text  I sometimes got
+-- such errors when a chunk ended in the middle of a unicode char.
+instance Chunked Text.Lazy.Text Char where
+  toChunks = List.map (Text.Lazy.fromChunks . (: [])) . Text.Lazy.toChunks
+
+-- Note that the instances that use @toChunks = (: [])@ put everything
+-- into a single chunk - lazy reading won't work with these types.
+instance Chunked ByteString.ByteString Word8 where
+  toChunks = (: [])
+
+instance Chunked String Char where
+  toChunks = (: [])
+
+instance Chunked Data.Text.Text Char where
+  toChunks = (: [])
+
+-- | A test version of readProcessC
+-- Pipes code here: http://hpaste.org/76631
+readProcessInterleaved :: (Chunked a c, Monoid b) =>
+                          (ExitCode -> b) -> (a -> b) -> (a -> b)
+                       -> CreateProcess -> a -> IO b
+readProcessInterleaved codef outf errf p input = mask $ \ restore -> do
+  (Just inh, Just outh, Just errh, pid) <-
+      createProcess (p {std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe })
+
+  binary input [inh, outh, errh]
+
+  flip onException
+    (do hClose inh; hClose outh; hClose errh;
+        terminateProcess pid; waitForProcess pid) $ restore $ do
+
+    waitOut <- forkWait $ readInterleaved [(outf, outh), (errf, errh)] $ waitForProcess pid >>= return . codef
+
+    -- now write and flush any input
+    (do unless (null input) (hPutStr inh input >> hFlush inh)
+        hClose inh) `catch` resourceVanished (\ _e -> return ())
+
+    -- wait on the output
+    waitOut
+
+-- | Simultaneously read the output from all the handles, using the
+-- associated functions to add them to the Monoid b in the order they
+-- appear.  Close each handle on EOF (even though they were open when
+-- we received them.)
+readInterleaved :: forall a b c. (Chunked a c, Monoid b) => [(a -> b, Handle)] -> IO b -> IO b
+readInterleaved pairs finish = newEmptyMVar >>= readInterleaved' pairs finish
+
+readInterleaved' :: forall a b c. (Chunked a c, Monoid b) =>
+                    [(a -> b, Handle)] -> IO b -> MVar (Either Handle b) -> IO b
+readInterleaved' pairs finish res = do
+  mapM_ (forkIO . uncurry readHandle) pairs
+  takeChunks (length pairs)
+    where
+      readHandle f h = do
+        cs <- hGetContents h
+        mapM_ (\ c -> putMVar res (Right (f c))) (toChunks cs)
+        hClose h
+        putMVar res (Left h)
+      takeChunks :: Int -> IO b
+      takeChunks 0 = finish
+      takeChunks openCount = takeMVar res >>= takeChunk openCount
+      takeChunk :: Int -> Either Handle b -> IO b
+      takeChunk openCount (Left h) = hClose h >> takeChunks (openCount - 1)
+      takeChunk openCount (Right x) =
+          do xs <- unsafeInterleaveIO $ takeChunks openCount
+             return (x <> xs)
+
+forkWait :: IO a -> IO (IO a)
+forkWait a = do
+  res <- newEmptyMVar
+  _ <- mask $ \restore -> forkIO $ try (restore a) >>= putMVar res
+  return (takeMVar res >>= either (\ex -> throwIO (ex :: SomeException)) return)
+
+-- | Wrapper for a process that provides a handler for the
+-- ResourceVanished exception.  This is frequently an exception we
+-- wish to ignore, because many processes will deliberately exit
+-- before they have read all of their input.
+resourceVanished :: (IOError -> IO a) -> IOError -> IO a
+resourceVanished epipe e = if ioe_type e == ResourceVanished then epipe e else ioError e
diff --git a/System/Process/Read/ListLike.hs b/System/Process/Read/ListLike.hs
new file mode 100644
--- /dev/null
+++ b/System/Process/Read/ListLike.hs
@@ -0,0 +1,247 @@
+-- | Versions of the functions in module 'System.Process.Read' specialized for type ByteString.
+{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies #-}
+module System.Process.Read.ListLike (
+  ListLikePlus(..),
+  readCreateProcessWithExitCode,
+  readCreateProcess,
+  readProcessWithExitCode,
+  readProcess,
+  ) where
+
+import Control.Concurrent
+import Control.Exception as E (SomeException, onException, evaluate, catch, try, throwIO, mask)
+import Control.Monad
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.Int (Int64)
+import Data.ListLike (ListLike(..), ListLikeIO(..))
+import Data.ListLike.Text.Text ()
+import Data.ListLike.Text.TextLazy ()
+import qualified Data.Text as T
+import qualified Data.Text.Lazy as LT
+import Data.Word (Word8)
+import GHC.IO.Exception (IOErrorType(OtherError, ResourceVanished), IOException(ioe_type))
+import Prelude hiding (null, length)
+import System.Exit (ExitCode(ExitSuccess, ExitFailure))
+import System.IO hiding (hPutStr, hGetContents)
+import qualified System.IO.Error as IO
+import System.Process (CreateProcess(..), StdStream(CreatePipe, Inherit), proc,
+                       CmdSpec(RawCommand, ShellCommand), showCommandForUser,
+                       createProcess, waitForProcess, terminateProcess)
+
+-- | Class of types which can be used as the input and outputs of the process functions.
+class (Integral (LengthType a), ListLikeIO a c) => ListLikePlus a c where
+  type LengthType a
+  binary :: a -> [Handle] -> IO ()
+  -- ^ This should call 'hSetBinaryMode' on each handle if a is a
+  -- ByteString type, so that it doesn't attempt to decode the text
+  -- using the current locale.
+  lazy :: a -> Bool
+  length' :: a -> LengthType a
+
+-- | A polymorphic implementation of
+-- 'System.Process.readProcessWithExitCode' with a few
+-- generalizations:
+--
+--    1. The input and outputs can be any instance of 'ListLikePlus'.
+--
+--    2. Allows you to modify the 'CreateProcess' record before the process starts
+--
+--    3. Takes a 'CmdSpec', so you can launch either a 'RawCommand' or a 'ShellCommand'.
+readCreateProcessWithExitCode
+    :: forall a c.
+       ListLikePlus a c =>
+       CreateProcess   -- ^ process to run
+    -> a               -- ^ standard input
+    -> IO (ExitCode, a, a) -- ^ exitcode, stdout, stderr, exception
+#if 1
+readCreateProcessWithExitCode p input =
+    readProcessInterleaved p input (\ a -> (a, mempty, mempty))
+                                   (\ a -> (mempty, a, mempty))
+                                   (\ code -> (mempty, mempty, code))
+
+instance forall a c. ListLikePlus a c => Monoid (a, a, ExitCode) where
+    mempty = (mempty, mempty, ExitFailure 0)
+    mappend (a, b, c) (d, e, f) = (mappend a d, mappend b e, mappend c f)
+
+instance Monoid ExitCode where
+    mempty = ExitFailure 0 -- A hack, but this should not occur.
+    mappend x (ExitFailure 0) = x
+    mappend _ x = x
+
+#else
+readCreateProcessWithExitCode p input = mask $ \restore -> do
+    (Just inh, Just outh, Just errh, pid) <-
+        createProcess (p {std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe })
+
+    flip onException
+      (do hClose inh; hClose outh; hClose errh;
+          terminateProcess pid; waitForProcess pid) $ restore $ do
+      (out, err) <- (if lazy input then readLazy else readStrict) inh outh errh
+
+      hClose outh
+      hClose errh
+
+      -- wait on the process
+      ex <- waitForProcess pid
+
+      return (ex, out, err)
+    where
+      readLazy :: Handle -> Handle -> Handle -> IO (a, a)
+      readLazy inh outh errh =
+           do out <- hGetContents outh
+              waitOut <- forkWait $ void $ force $ out
+              err <- hGetContents errh
+              waitErr <- forkWait $ void $ force $ err
+              -- now write and flush any input
+              writeInput inh
+              -- wait on the output
+              waitOut
+              waitErr
+              return (out, err)
+
+      readStrict :: Handle -> Handle -> Handle -> IO (a, a)
+      readStrict inh outh errh =
+           do -- fork off a thread to start consuming stdout
+              waitOut <- forkWait $ hGetContents outh
+              -- fork off a thread to start consuming stderr
+              waitErr <- forkWait $ hGetContents errh
+              -- now write and flush any input
+              writeInput inh
+              -- wait on the output
+              out <- waitOut
+              err <- waitErr
+              return (out, err)
+
+      writeInput :: Handle -> IO ()
+      writeInput inh = do
+        (do unless (null input) (hPutStr inh input >> hFlush inh)
+            hClose inh) `E.catch` resourceVanished (\ _ -> return ())
+#endif
+
+-- | A polymorphic implementation of
+-- 'System.Process.readProcessWithExitCode' in terms of
+-- 'readCreateProcessWithExitCode'.
+readProcessWithExitCode
+    :: ListLikePlus a c =>
+       FilePath                 -- ^ command to run
+    -> [String]                 -- ^ any arguments
+    -> a               -- ^ standard input
+    -> IO (ExitCode, a, a) -- ^ exitcode, stdout, stderr
+readProcessWithExitCode cmd args input = readCreateProcessWithExitCode (proc cmd args) input
+
+-- | Implementation of 'System.Process.readProcess' in terms of
+-- 'readCreateProcess'.
+readProcess
+    :: ListLikePlus a c =>
+       FilePath                 -- ^ command to run
+    -> [String]                 -- ^ any arguments
+    -> a               -- ^ standard input
+    -> IO a            -- ^ stdout
+readProcess cmd args = readCreateProcess (proc cmd args)
+
+-- | A polymorphic implementation of 'System.Process.readProcess' with a few generalizations:
+--
+--    1. The input and outputs can be any instance of 'ListLikePlus'.
+--
+--    2. Allows you to modify the 'CreateProcess' record before the process starts
+--
+--    3. Takes a 'CmdSpec', so you can launch either a 'RawCommand' or a 'ShellCommand'.
+readCreateProcess
+    :: ListLikePlus a c =>
+       CreateProcess   -- ^ process to run
+    -> a               -- ^ standard input
+    -> IO a            -- ^ stdout
+#if 0
+readCreateProcess p input = readProcessInterleaved (\ x -> x) (\ _ -> mempty) (\ _ -> mempty) p input
+#else
+readCreateProcess p input = mask $ \restore -> do
+    (Just inh, Just outh, _, pid) <-
+        createProcess (p {std_in = CreatePipe, std_out = CreatePipe, std_err = Inherit })
+
+    flip onException
+      (do hClose inh; hClose outh;
+          terminateProcess pid; waitForProcess pid) $ restore $ do
+      out <- (if lazy input then readLazy else readStrict) inh outh
+
+      hClose outh
+
+      -- wait on the process
+      ex <- waitForProcess pid
+
+      case ex of
+        ExitSuccess   -> return out
+        ExitFailure r -> ioError (mkError "readCreateProcess: " (cmdspec p) r)
+    where
+      readLazy inh outh =
+          do -- fork off a thread to start consuming stdout
+             out <- hGetContents outh
+             waitOut <- forkWait $ void $ force $ out
+             writeInput inh
+             waitOut
+             return out
+
+      readStrict inh outh =
+          do waitOut <- forkWait $ hGetContents outh
+             writeInput inh
+             waitOut
+
+      writeInput inh = do
+         (do unless (null input) (hPutStr inh input >> hFlush inh)
+             hClose inh) `E.catch` resourceVanished (\ _ -> return ())
+#endif
+
+forkWait :: IO a -> IO (IO a)
+forkWait a = do
+  res <- newEmptyMVar
+  _ <- mask $ \restore -> forkIO $ try (restore a) >>= putMVar res
+  return (takeMVar res >>= either (\ex -> throwIO (ex :: SomeException)) return)
+
+-- | Wrapper for a process that provides a handler for the
+-- ResourceVanished exception.  This is frequently an exception we
+-- wish to ignore, because many processes will deliberately exit
+-- before they have read all of their input.
+resourceVanished :: (IOError -> IO a) -> IOError -> IO a
+resourceVanished epipe e = if ioe_type e == ResourceVanished then epipe e else ioError e
+
+-- | Create an exception for a process that exited abnormally.
+mkError :: String -> CmdSpec -> Int -> IOError
+mkError prefix (RawCommand cmd args) r =
+    IO.mkIOError OtherError (prefix ++ showCommandForUser cmd args ++ " (exit " ++ show r ++ ")")
+                 Nothing Nothing
+mkError prefix (ShellCommand cmd) r =
+    IO.mkIOError OtherError (prefix ++ cmd ++ " (exit " ++ show r ++ ")")
+                 Nothing Nothing
+
+force :: forall a c. ListLikePlus a c => a -> IO (LengthType a)
+force x = evaluate $ length' $ x
+
+instance ListLikePlus String Char where
+  type LengthType String = Int
+  binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles (because internally this uses lazy bytestrings)
+  lazy _ = True
+  length' = length
+
+instance ListLikePlus B.ByteString Word8 where
+  type LengthType B.ByteString = Int
+  binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles
+  lazy _ = False
+  length' = B.length
+
+instance ListLikePlus L.ByteString Word8 where
+  type LengthType L.ByteString = Int64
+  binary _ = mapM_ (\ h -> hSetBinaryMode h True) -- Prevent decoding errors when reading handles
+  lazy _ = True
+  length' = L.length
+
+instance ListLikePlus T.Text Char where
+  type LengthType T.Text = Int
+  binary _ _ = return ()
+  lazy _ = False
+  length' = T.length
+
+instance ListLikePlus LT.Text Char where
+  type LengthType LT.Text = Int64
+  binary _ _ = return ()
+  lazy _ = True
+  length' = LT.length
diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -1,3 +1,11 @@
+haskell-process-listlike (0.7) unstable; urgency=low
+
+  * Add module System.Process.Read.Interleaved (from process-progress)
+  * Add module System.Process.Read.Chunks (from process-progress)
+  * Rename module System.Process.Read.Chars -> System.Process.Read.ListLike
+
+ -- David Fox <dsf@seereason.com>  Tue, 26 Aug 2014 11:16:13 -0700
+
 haskell-process-listlike (0.6.2) unstable; urgency=low
 
   * Make changelog visible in hackage.
diff --git a/process-listlike.cabal b/process-listlike.cabal
--- a/process-listlike.cabal
+++ b/process-listlike.cabal
@@ -1,8 +1,10 @@
 Name:               process-listlike
-Version:            0.6.2
+Version:            0.7
 Synopsis:           Enhanced version of process-extras
-Description:        Extra functionality for the Process library
-                    <http://hackage.haskell.org/package/process>.
+Description:        Extra functionality for the Process library <http://hackage.haskell.org/package/process>.
+  This is a drop-in replacement for <http://hackage.haskell.org/package/process-extras>,
+  which adds support for creating processes from a CreateProcess, more access to the
+  internals, and completes support for the String type.
 Homepage:           http://src.seereason.com/process-listlike
 License:            MIT
 License-file:       LICENSE
@@ -15,15 +17,16 @@
 
 source-repository head
   Type:             darcs
-  Location:         http://src.seereason.com/process-extras
+  Location:         https://github.com/ddssff/process-listlike.git
 
 Library
   ghc-options:      -Wall -O2
 
   Exposed-modules:
     System.Process.Read
-    System.Process.Read.Chars
-    System.Process.Read.Instances
+    System.Process.Read.Chunks
+    System.Process.Read.Interleaved
+    System.Process.Read.ListLike
     System.Process.ByteString
     System.Process.ByteString.Lazy
     System.Process.String
@@ -32,8 +35,8 @@
 
   Build-depends:
     base >= 4 && < 5,
-    process,
     bytestring,
+    deepseq,
     HUnit,
     ListLike >= 4.0,
     process,
@@ -46,6 +49,7 @@
   Build-Depends:
     base >= 4 && < 5,
     bytestring,
+    deepseq,
     HUnit,
     ListLike,
     process,
