packages feed

splice 0.3.2 → 0.4

raw patch · 3 files changed

+101/−40 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Network.Socket.Splice: fdSplice :: ChunkSize -> Fd -> Fd -> IO ()
+ Network.Socket.Splice: hSplice :: Int -> Handle -> Handle -> IO ()
- Network.Socket.Splice: splice :: ChunkSize -> Socket -> Socket -> IO ()
+ Network.Socket.Splice: splice :: ChunkSize -> (Socket, Maybe Handle) -> (Socket, Maybe Handle) -> IO ()

Files

splice.cabal view
@@ -1,5 +1,5 @@ name:          splice-version:       0.3.2+version:       0.4 stability:     stable on GNU/Linux, experimental on other operating systems synopsis:      Socket to Socket Data Splicing (supports all operating systems) description:   A library that implements most efficient socket to socket@@ -33,7 +33,7 @@   flag portable-    description: explicitly enable portable splice implemented in Haskell+    description: force portable 'splice' implementation on GNU\/Linux     default    : False  @@ -50,9 +50,9 @@                      network >= 2 && <= 4,                      unix    >= 2 && <= 4       cpp-options: -DLINUX_SPLICE-      ghc-options: -W -O2 -O3 -fllvm -optlo-O3+      ghc-options: -Wall -O2 -O3 -fllvm -optlo-O3     else       build-depends: base    >= 4 && <= 6,                      network >= 2 && <= 4       cpp-options: -ULINUX_SPLICE-      ghc-options: -W -O2 -O3+      ghc-options: -Wall -O2 -O3
src/Network/Socket/Splice.hs view
@@ -5,12 +5,12 @@   On GNU\/Linux, it uses and exposes the zero-copy @splice()@ system call:   <http://kerneltrap.org/node/6505>. -  On other operating systems, it currently falls back to a portable Haskell-  implementation – which first allocates a constant-sized memory buffer in user-  address, then enters an inner loop which uses 'System.IO.hGetBufSome'-  and 'System.IO.hPutBuf' on this user-space buffer. This avoids tony of tiny-  allocations as might otherwise be caused by 'Network.Socket.ByteString.recv'-  and 'Network.Socket.ByteString.sendAll' from the @bytestring@ package.+  On all other operating systems, it currently falls back to a portable Haskell+  implementation – which allocates a single memory buffer in user address space,+  then enters an inner loop that uses 'System.IO.hGetBufSome' and+  'System.IO.hPutBuf'. This avoids lots of tiny allocations as would otherwise+  be caused by 'Network.Socket.ByteString.recv' and+  'Network.Socket.ByteString.sendAll' from the @bytestring@ package. -} --   -- Module      : Network.Socket.Splice
src/Network/Socket/Splice/Internal.hsc view
@@ -1,4 +1,5 @@ -- | Implementation.+-- -- Module      : Network.Socket.Splice.Internal -- Copyright   : (c) Cetin Sert 2012 -- License     : BSD3@@ -20,11 +21,14 @@   {- | 'splice' is the cross-platform API for continous, uni-directional        data transfer between two network sockets. -       It is an /infinite loop/ that is intended to be used with-       'Control.Concurrent.forkIO':+       'splice' and its implementation primitives 'hSplice' and 'fdSplice' are+       /infinite/ loops that are intended to be used with exception handlers and+       'Control.Concurrent.forkIO'. -       > void . forkIO . try_ $ splice 1024 sourceSocket targetSocket-       > void . forkIO . try_ $ splice 1024 targetSocket sourceSocket+       [Initiate bi-directional continuous data transfer between two sockets:]+    +       > void . forkIO . try_ $ splice 1024 (sourceSocket, _) (targetSocket, _)+       > void . forkIO . try_ $ splice 1024 (targetSocket, _) (sourceSocket, _)   -}      splice@@ -34,15 +38,26 @@   -- * Combinators for Exception Handling   , try_ +  -- * Implementation Primitives+  {- | Infinite loops used in the cross-platform implementation of 'splice'.+  -}++  , hSplice+#ifdef LINUX_SPLICE+  , fdSplice+#endif+   ) where   import Data.Word import Foreign.Ptr +import System.IO import Network.Socket import Control.Monad import Control.Exception+import Foreign.Marshal.Alloc  #ifdef LINUX_SPLICE import Data.Int@@ -54,9 +69,7 @@ import System.Posix.Internals import qualified System.IO.Splice.Linux as L #else-import System.IO-import GHC.IO.Handle.FD-import Foreign.Marshal.Alloc+import Data.Maybe #endif  @@ -85,38 +98,74 @@ #endif  +throwRecv0 :: a+throwRecv0 = error "Network.Socket.Splice.splice ended"+ -- | Pipes data from one socket to another in an /infinite loop/. -----   On Linux this uses the @splice()@ system call and eliminates copying---   between kernel and user address spaces.+--   'splice' currently has two implementations: -----   On other operating systems, a portable Haskell implementation utilizes a---   user space buffer.+--   [on GNU\/Linux using 'fdSplice' ≅]+--+--   > splice len (sIn, _       ) (sOut, _        ) = ... fdSplice ...+--+--   [on all other operating systems using 'hSplice' ≅]+--+--   > splice len (_  , Just hIn) (_   , Just hOut) = ... hSplice  ...+--+--   [Notes]+--+--     * 'fdSplice' and 'fdSplice' implementation of 'splice' are only available+--        on GNU\/Linux.+--+--     * 'hSplice' is always available and the 'hSplice' implementation of+--       'splice' can be forced on GNU\/Linux by defining the @portable@ flag at+--       compile time.+-- splice-  :: ChunkSize -- ^ chunk size.-  -> Socket    -- ^ source socket.-  -> Socket    -- ^ target socket.-  -> IO ()     -- ^ infinite loop.-splice len sIn sOut = do+  :: ChunkSize               -- ^ chunk size.+  -> (Socket, Maybe Handle)  -- ^ source socket and possibly its opened handle.+  -> (Socket, Maybe Handle)  -- ^ target socket and possibly its opened handle.+  -> IO ()                   -- ^ infinite loop.+#ifdef LINUX_SPLICE+splice len (sIn, _  ) (sOut, _   ) = do+#else+splice len (_  , hIn) (_   , hOut) = do+#endif+#ifdef LINUX_SPLICE+  let s = Fd $ fdSocket sIn+  let t = Fd $ fdSocket sOut+  fdSplice len s t+#else+  let s = fromJust hIn+  let t = fromJust hOut+  hSplice (fromIntegral len) s t+#endif -  let throwRecv0 = error "Network.Socket.Splice.splice ended" -  let fdIn  = fdSocket sIn-  let fdOut = fdSocket sOut   #ifdef LINUX_SPLICE -  (r,w) <- createPipe     -- r,w: read / write ends of pipe-  let s = Fd fdIn         -- s  : source socket-  let t = Fd fdOut        -- t  : target socket+{- | GNU\/Linux @splice()@ system call loop.++       1. creates a pipe in kernel address space++       2. uses it until the loop terminates by exception++       3. closes the pipe and returns+-}+fdSplice :: ChunkSize -> Fd -> Fd -> IO ()+fdSplice len s@(Fd fdIn) t@(Fd fdOut) = do++  (r,w) <- createPipe   let n = nullPtr     let u = unsafeCoerce :: (#type ssize_t) -> (#type size_t)   let check = throwErrnoIfMinus1 "Network.Socket.Splice.splice"   let flags = L.sPLICE_F_MOVE .|. L.sPLICE_F_MORE   let setNonBlockingMode v = do setNonBlockingFD fdIn  v                                 setNonBlockingFD fdOut v-   setNonBlockingMode False+   finally     (forever $ do         bytes <- check $ L.c_splice s n w n    len    flags@@ -127,12 +176,25 @@         closeFd w         try_ $ setNonBlockingMode True) -#else+#endif -  s <- fdToHandle fdIn ; hSetBuffering s NoBuffering-  t <- fdToHandle fdOut; hSetBuffering t NoBuffering-  a <- mallocBytes len :: IO (Ptr Word8) ++{- | The portable Haskell loop.++       1. allocates a /single/ memory buffer in user address space++       2. uses it until the loop terminates by exception++       3. frees the buffer and returns+-} +hSplice :: Int -> Handle -> Handle -> IO ()+hSplice len s t = do++  sb <- hGetBuffering s; hSetBuffering s NoBuffering+  tb <- hGetBuffering s; hSetBuffering t NoBuffering+  a  <- mallocBytes len :: IO (Ptr Word8)+   finally     (forever $ do        bytes <-   hGetBufSome s a len@@ -140,10 +202,9 @@          then     hPutBuf     t a bytes          else     throwRecv0)     (do free a-        try_ $ hClose s-        try_ $ hClose t)+        try_ $ hSetBuffering s sb+        try_ $ hSetBuffering s tb) -#endif   -- | Similar to 'Control.Exception.Base.try' but used when an obvious exception