Skip to content

Commit

Permalink
Change *EventNonBlocking to throw an exception on closed descriptors
Browse files Browse the repository at this point in the history
  • Loading branch information
lpsmith committed Nov 20, 2015
1 parent 9fde5c6 commit 27b38ca
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 17 deletions.
9 changes: 9 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
Version 0.3.0.1: (2015-11-20)
* `getEventNonBlocking` and `peekEventNonBlocking` now raise an
`IOException` when they are called on an inotify descriptor that
has been closed and have an empty buffer, instead of returning
`Nothing`. This is more in line with the behavior of other IO
functions such as `Data.ByteString.hGetNonBlocking`.

* Attempted to improve documentation.

Version 0.3.0.0: (2015-11-20)
* Use-after-close now result in exceptions rather than undefined behavior.

Expand Down
4 changes: 2 additions & 2 deletions linux-inotify.cabal
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: linux-inotify
version: 0.3.0.0
version: 0.3.0.1
synopsis: Thinner binding to the Linux Kernel's inotify interface
description:
This is a binding for GHC 7 to the Linux Kernel's inotify interface,
Expand Down Expand Up @@ -60,4 +60,4 @@ source-repository head
source-repository this
type: git
location: http://github.com/lpsmith/linux-inotify
tag: v0.2.0.1
tag: v0.3.0.1
45 changes: 30 additions & 15 deletions src/System/Linux/Inotify.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ import Data.Monoid
import Data.Typeable
import Data.Function ( on )
import Data.Word
import Control.Exception ( throwIO, mask_, onException )
import Control.Exception ( IOException, throwIO, mask_, onException )
import GHC.Conc ( closeFdWith, threadWaitReadSTM, atomically )
import GHC.IO.Exception
import GHC.IO.Exception hiding ( IOException )
import Control.Concurrent.MVar
import Control.Monad
import System.Posix
Expand Down Expand Up @@ -458,8 +458,10 @@ rmWatch' (Inotify (Fd !fd)) (Watch !wd) = do
--
-- If the inotify descriptor is closed, this function will return
-- an event from the buffer, if available. Otherwise, it will
-- throw an 'IOException'. It is safe to call this function from
-- multiple threads at the same time.
-- throw an 'IOException'.
--
-- It is safe to call this function from multiple threads at the
-- same time.

getEvent :: Inotify -> IO Event
getEvent inotify@Inotify{..} = loop
Expand Down Expand Up @@ -489,7 +491,7 @@ getEvent inotify@Inotify{..} = loop
--
-- If the inotify descriptor is closed, this function will return
-- an event from the buffer, if available. Otherwise, it will
-- throw an 'IOError'.
-- throw an 'IOException'.
--
-- It is safe to call this function from multiple threads at the same
-- time.
Expand Down Expand Up @@ -554,11 +556,13 @@ getMessage Inotify{..} start doConsume = withForeignPtr buffer $ \ptr0 -> do
--
-- If the inotify descriptor is closed, this function will return
-- an event from the buffer, if available. Otherwise, it will
-- return 'Nothing'.
-- throw an 'IOException'.
--
-- One possible downside of the current implementation is that
-- returning 'Nothing' necessarily results in a system call, unless
-- the inotify descriptor has been closed.
-- returning 'Nothing' necessarily results in a system call.
--
-- It is safe to call this function from multiple threads at the
-- same time.

getEventNonBlocking :: Inotify -> IO (Maybe Event)
getEventNonBlocking inotify@Inotify{..} = act
Expand All @@ -570,7 +574,7 @@ getEventNonBlocking inotify@Inotify{..} = act
if start < end
then Just <$> getMessage inotify start True
else fillBuffer funcName inotify
(return Nothing)
(throwIO $! fdClosed funcName)
(\_fd -> return Nothing)
(Just <$> getMessage inotify 0 True)

Expand All @@ -582,11 +586,13 @@ getEventNonBlocking inotify@Inotify{..} = act
--
-- If the inotify descriptor is closed, this function will return
-- an event from the buffer, if available. Otherwise, it will
-- return 'Nothing'.
-- throw an 'IOException'.
--
-- One possible downside of the current implementation is that
-- returning 'Nothing' necessarily results in a system call, unless
-- the inotify descriptor has been closed.
-- returning 'Nothing' necessarily results in a system call.
--
-- It is safe to call this function from multiple threads at the
-- same time.

peekEventNonBlocking :: Inotify -> IO (Maybe Event)
peekEventNonBlocking inotify@Inotify{..} = act
Expand All @@ -598,14 +604,19 @@ peekEventNonBlocking inotify@Inotify{..} = act
if start < end
then Just <$> getMessage inotify start False
else fillBuffer funcName inotify
(return Nothing)
(throwIO $! fdClosed funcName)
(\_fd -> return Nothing)
(do
writeIORef startRef 0
Just <$> getMessage inotify 0 False)

-- | Returns an inotify event only if one is available in 'Inotify'\'s
-- buffer. This won't ever make a system call.
-- buffer. This won't ever make a system call, and should not
-- ever throw an exception.
--
-- It is safe to call this function from multiple threads at the
-- same time.


getEventFromBuffer :: Inotify -> IO (Maybe Event)
getEventFromBuffer inotify@Inotify{..} = act
Expand All @@ -618,11 +629,15 @@ getEventFromBuffer inotify@Inotify{..} = act
else return Nothing

-- | Returns an inotify event only if one is available in 'Inotify'\'s
-- buffer. This won't ever make a system call.
-- buffer. This won't ever make a system call, and should not ever
-- throw an exception.
--
-- If this returns an event, then the next read from the inotify
-- descriptor will return the same event, and this read will not
-- result in a system call.
--
-- It is safe to call this function from multiple threads at the
-- same time.

peekEventFromBuffer :: Inotify -> IO (Maybe Event)
peekEventFromBuffer inotify@Inotify{..} = act
Expand Down

0 comments on commit 27b38ca

Please sign in to comment.