posix-api 0.6.0.1 → 0.6.1.0
raw patch · 5 files changed
+75/−11 lines, 5 files
Files
- CHANGELOG.md +6/−0
- cbits/HaskellPosix.c +4/−2
- posix-api.cabal +1/−1
- src/Linux/Socket.hs +31/−4
- src/Posix/File.hs +33/−4
CHANGELOG.md view
@@ -7,6 +7,12 @@ This project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/). +## [0.6.1.0] - 2023-08-14++- Add `uninterruptibleWriteBytesCompletelyErrno`+- Add `writeBytesCompletelyErrno`+- Add `uninterruptibleAccept4_`+ ## [0.6.0.1] - 2023-07-13 - Fix mistake in header file that caused builds to fail
cbits/HaskellPosix.c view
@@ -26,13 +26,15 @@ // way to support providing an offset (without just copying the bytes // into pinned memory) is to use a wrapper. -ssize_t write_offset_loop(int fd, const char *message, HsInt offset, size_t length){+// This returns an error code, not a length of written bytes. The error+// code zero means "no error".+int write_offset_loop(int fd, const char *message, HsInt offset, size_t length){ ssize_t r; size_t bytesSent; const char* buf = message + offset; while(length > 0){ if ((r = write(fd, (const void*)buf, length)) == -1) {- return (-1);+ return errno; } else { bytesSent = (size_t)r; buf = buf + bytesSent;
posix-api.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: posix-api-version: 0.6.0.1+version: 0.6.1.0 synopsis: posix bindings description: This library provides a very thin wrapper around POSIX APIs. It can be
src/Linux/Socket.hs view
@@ -12,6 +12,7 @@ , uninterruptibleReceiveMultipleMessageC , uninterruptibleReceiveMultipleMessageD , uninterruptibleAccept4+ , uninterruptibleAccept4_ -- * Types , SocketFlags(..) -- * Option Names@@ -49,26 +50,28 @@ import Control.Monad (when) import Data.Bits ((.|.))-import Data.Primitive.Addr (Addr(..),plusAddr,nullAddr) import Data.Primitive (MutableByteArray(..),ByteArray(..),MutablePrimArray(..))+import Data.Primitive.Addr (Addr(..),plusAddr,nullAddr) import Data.Primitive.Unlifted.Array (MutableUnliftedArray,UnliftedArray) import Data.Primitive.Unlifted.Array (MutableUnliftedArray_(MutableUnliftedArray))+import Data.Primitive.Unlifted.Array.Primops (MutableUnliftedArray#(MutableUnliftedArray#))+import Data.Void (Void) import Data.Word (Word8) import Foreign.C.Error (Errno,getErrno) import Foreign.C.Types (CInt(..),CSize(..),CUInt(..))+import Foreign.Ptr (nullPtr) import GHC.Exts (Ptr(..),RealWorld,MutableArray#,MutableByteArray#,Addr#,Int(I#)) import GHC.Exts (shrinkMutableByteArray#,touch#,nullAddr#) import GHC.IO (IO(..)) import Linux.Socket.Types (SocketFlags(..)) import Posix.Socket (Type(..),MessageFlags(..),Message(Receive),SocketAddress(..)) import System.Posix.Types (Fd(..),CSsize(..))-import Data.Primitive.Unlifted.Array.Primops (MutableUnliftedArray#(MutableUnliftedArray#)) +import qualified Control.Monad.Primitive as PM import qualified Data.Primitive as PM import qualified Data.Primitive.Unlifted.Array as PM-import qualified Control.Monad.Primitive as PM-import qualified Posix.Socket as S import qualified Linux.Socket.Types as LST+import qualified Posix.Socket as S foreign import ccall unsafe "sys/socket.h recvmmsg" c_unsafe_addr_recvmmsg :: Fd@@ -85,6 +88,17 @@ -> SocketFlags -> IO Fd +-- Variant of c_unsafe_ptr_accept4 that uses Ptr instead of MutableByteArray.+-- Currently, we expect that the two pointers are set to NULL.+-- This is only used internally.+foreign import ccall unsafe "sys/socket.h accept4"+ c_unsafe_ptr_accept4 ::+ Fd+ -> Ptr Void -- SocketAddress+ -> Ptr Void -- Ptr CInt+ -> SocketFlags+ -> IO Fd+ foreign import ccall unsafe "HaskellPosix.h recvmmsg_sockaddr_in" c_unsafe_recvmmsg_sockaddr_in :: Fd@@ -366,6 +380,19 @@ else pure () sockAddr <- PM.unsafeFreezeByteArray sockAddrBuf pure (Right (sz,SocketAddress sockAddr,r))+ else fmap Left getErrno++-- | Variant of 'uninterruptibleAccept4' that requests that the kernel not+-- include the socket address in its reponse.+uninterruptibleAccept4_ ::+ Fd -- ^ Listening socket+ -> SocketFlags -- ^ Set non-blocking and close-on-exec without extra syscall+ -> IO (Either Errno Fd) -- ^ Connected socket+{-# inline uninterruptibleAccept4_ #-}+uninterruptibleAccept4_ !sock !flags = do+ r <- c_unsafe_ptr_accept4 sock nullPtr nullPtr flags+ if r > (-1)+ then pure (Right r) else fmap Left getErrno cintToInt :: CInt -> Int
src/Posix/File.hs view
@@ -1,5 +1,6 @@ {-# language BangPatterns #-} {-# language BinaryLiterals #-}+{-# language LambdaCase #-} {-# language MagicHash #-} {-# language TypeApplications #-} {-# language UnliftedFFITypes #-}@@ -11,6 +12,8 @@ , uninterruptibleWriteByteArray , uninterruptibleWriteBytes , uninterruptibleWriteBytesCompletely+ , uninterruptibleWriteBytesCompletelyErrno+ , writeBytesCompletelyErrno , uninterruptibleOpen , uninterruptibleOpenMode , writeByteArray@@ -44,7 +47,7 @@ import Assertion (assertByteArrayPinned,assertMutableByteArrayPinned) import Data.Bits ((.&.),(.|.)) import Data.Primitive (ByteArray(..))-import Foreign.C.Error (Errno,getErrno)+import Foreign.C.Error (Errno(Errno),getErrno,eOK) import Foreign.C.String.Managed (ManagedCString(..)) import Foreign.C.Types (CInt(..),CSize(..)) import GHC.Exts (ByteArray#,MutableByteArray#,RealWorld)@@ -76,8 +79,11 @@ c_unsafe_bytearray_write :: Fd -> ByteArray# -> Int -> CSize -> IO CSsize foreign import ccall unsafe "HaskellPosix.h write_offset_loop"- c_unsafe_bytearray_write_loop :: Fd -> ByteArray# -> Int -> CSize -> IO CInt+ c_unsafe_bytearray_write_loop :: Fd -> ByteArray# -> Int -> CSize -> IO Errno +foreign import ccall safe "HaskellPosix.h write_offset_loop"+ c_safe_bytearray_write_loop :: Fd -> ByteArray# -> Int -> CSize -> IO Errno+ foreign import ccall safe "HaskellPosix.h write_offset" c_safe_bytearray_write :: Fd -> ByteArray# -> Int -> CSize -> IO CSsize @@ -137,11 +143,32 @@ Fd -- ^ File descriptor -> Bytes -- ^ Source bytes -> IO (Either Errno ())-uninterruptibleWriteBytesCompletely !fd (Bytes (ByteArray buf) off len) =+uninterruptibleWriteBytesCompletely !fd !b = do+ e <- uninterruptibleWriteBytesCompletelyErrno fd b+ if e == eOK+ then pure (Right ())+ else pure (Left e)++-- | Variant of 'uninterruptibleWriteBytesCompletely' that uses errno 0+-- to communicate success.+uninterruptibleWriteBytesCompletelyErrno ::+ Fd -- ^ File descriptor+ -> Bytes -- ^ Source bytes+ -> IO Errno+uninterruptibleWriteBytesCompletelyErrno !fd (Bytes (ByteArray buf) off len) = c_unsafe_bytearray_write_loop fd buf off (fromIntegral @Int @CSize len)- >>= errorsFromInt_ -- | Wrapper for @write(2)@ that takes a slice of bytes and an offset.+-- The byte array backing the slice must be pinned.+writeBytesCompletelyErrno ::+ Fd -- ^ File descriptor+ -> Bytes -- ^ Source bytes+ -> IO Errno+writeBytesCompletelyErrno !fd (Bytes buf0 off len) =+ let !(ByteArray buf1) = assertByteArrayPinned buf0+ in c_safe_bytearray_write_loop fd buf1 off (fromIntegral @Int @CSize len)++-- | Wrapper for @write(2)@ that takes a slice of bytes and an offset. -- The byte array backing the slice does not need to be pinned. uninterruptibleWriteBytes :: Fd -- ^ File descriptor@@ -173,6 +200,8 @@ writeByteArray !fd !buf0 !off !len = let !(ByteArray buf1) = assertByteArrayPinned buf0 in c_safe_bytearray_write fd buf1 off len >>= errorsFromSize++-- writeByteArrayCompletely :: -- | Variant of 'writeByteArray' that operates on mutable byte array. -- Uses @safe@ FFI. The byte array must be pinned.