diff options
author | Tamar Christina <tamar@zhox.com> | 2020-07-12 22:00:47 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-07-24 18:13:00 -0400 |
commit | c1f4f81d3a439cd1a8128e4ab11c7caac7cc0ad8 (patch) | |
tree | 93d9a7411500b39d0478a6f4b471eb9eda2540c4 /libraries/base/GHC/Event/Windows/FFI.hsc | |
parent | cdd0ff16f20ce920c74f9128a1067cbe1bd378c2 (diff) | |
download | haskell-c1f4f81d3a439cd1a8128e4ab11c7caac7cc0ad8.tar.gz |
winio: change memory allocation strategy and fix double free errors.
Diffstat (limited to 'libraries/base/GHC/Event/Windows/FFI.hsc')
-rw-r--r-- | libraries/base/GHC/Event/Windows/FFI.hsc | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/libraries/base/GHC/Event/Windows/FFI.hsc b/libraries/base/GHC/Event/Windows/FFI.hsc index b9c766c977..f8ea13b4a0 100644 --- a/libraries/base/GHC/Event/Windows/FFI.hsc +++ b/libraries/base/GHC/Event/Windows/FFI.hsc @@ -30,6 +30,11 @@ module GHC.Event.Windows.FFI ( postQueuedCompletionStatus, getOverlappedResult, + -- * Completion Data + CompletionData(..), + CompletionCallback, + withRequest, + -- * Overlapped OVERLAPPED, LPOVERLAPPED, @@ -216,6 +221,51 @@ postQueuedCompletionStatus iocp numBytes completionKey lpol = c_PostQueuedCompletionStatus iocp numBytes completionKey lpol ------------------------------------------------------------------------ +-- Completion Data + +-- | Called when the completion is delivered. +type CompletionCallback a = ErrCode -- ^ 0 indicates success + -> DWORD -- ^ Number of bytes transferred + -> IO a + +-- | Callback type that will be called when an I/O operation completes. +type IOCallback = CompletionCallback () + +-- | Wrap the IOCallback type into a FunPtr. +foreign import ccall "wrapper" + wrapIOCallback :: IOCallback -> IO (FunPtr IOCallback) + +-- | Unwrap a FunPtr IOCallback to a normal Haskell function. +foreign import ccall "dynamic" + mkIOCallback :: FunPtr IOCallback -> IOCallback + +-- | Structure that the I/O manager uses to associate callbacks with +-- additional payload such as their OVERLAPPED structure and Win32 handle +-- etc. *Must* be kept in sync with that in `winio_structs.h` or horrible things +-- happen. +-- +-- We keep the handle around for the benefit of ghc-external libraries making +-- use of the manager. +data CompletionData = CompletionData { cdHandle :: !HANDLE + , cdCallback :: !IOCallback + } + +instance Storable CompletionData where + sizeOf _ = #{size CompletionData} + alignment _ = #{alignment CompletionData} + + peek ptr = do + cdCallback <- mkIOCallback `fmap` #{peek CompletionData, cdCallback} ptr + cdHandle <- #{peek CompletionData, cdHandle} ptr + let !cd = CompletionData{..} + return cd + + poke ptr CompletionData{..} = do + cb <- wrapIOCallback cdCallback + #{poke CompletionData, cdCallback} ptr cb + #{poke CompletionData, cdHandle} ptr cdHandle + +------------------------------------------------------------------------ -- Overlapped -- | Tag type for @LPOVERLAPPED@. @@ -294,6 +344,30 @@ pokeOffsetOverlapped lpol offset = do {-# INLINE pokeOffsetOverlapped #-} ------------------------------------------------------------------------ +-- Request management + +withRequest :: Word64 -> CompletionData + -> (Ptr HASKELL_OVERLAPPED -> Ptr CompletionData -> IO a) + -> IO a +withRequest offset cbData f = + -- Create the completion record and store it. + -- We only need the record when we enqueue a request, however if we + -- delay creating it then we will run into a race condition where the + -- driver may have finished servicing the request before we were ready + -- and so the request won't have the book keeping information to know + -- what to do. So because of that we always create the payload, If we + -- need it ok, if we don't that's no problem. This approach prevents + -- expensive lookups in hash-tables. + -- + -- Todo: Use a memory pool for this so we don't have to hit malloc every + -- time. This would allow us to scale better. + allocaBytes #{size HASKELL_OVERLAPPED} $ \hs_lpol -> + with cbData $ \cdData -> do + zeroOverlapped hs_lpol + pokeOffsetOverlapped (castPtr hs_lpol) offset + f hs_lpol cdData + +------------------------------------------------------------------------ -- Cancel pending I/O -- | CancelIo shouldn't block, but cancellation happens infrequently, |