packages feed

amqp 0.22.0 → 0.22.1

raw patch · 3 files changed

+21/−10 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

Network/AMQP/Internal.hs view
@@ -148,7 +148,8 @@     connBlockedHandlers :: MVar [(Text -> IO (), IO ())],
     connLastReceived :: MVar Int64, -- the timestamp from a monotonic clock when the last frame was received
     connLastSent :: MVar Int64, -- the timestamp from a monotonic clock when the last frame was written
-    connServerProperties :: FieldTable -- the server properties sent in Connection_start
+    connServerProperties :: FieldTable, -- the server properties sent in Connection_start
+    connThread :: MVar (Maybe ThreadId)
 }
 
 -- | Represents the parameters to connect to a broker or a cluster of brokers.
@@ -278,10 +279,12 @@     cBlockedHandlers <- newMVar []
     cLastReceived <- getTimestamp >>= newMVar
     cLastSent <- getTimestamp >>= newMVar
-    let conn = Connection handle cChanAllocator cChannels (fromIntegral maxFrameSize) cClosed ccl writeLock cClosedHandlers cBlockedHandlers cLastReceived cLastSent serverProps
+    cThread <- newMVar Nothing
 
+    let conn = Connection handle cChanAllocator cChannels (fromIntegral maxFrameSize) cClosed ccl writeLock cClosedHandlers cBlockedHandlers cLastReceived cLastSent serverProps cThread
+
     --spawn the connectionReceiver
-    connThread <- forkFinally' (connectionReceiver conn) $ \res -> do
+    connThreadId <- forkFinally' (connectionReceiver conn) $ \res -> do
         -- try closing socket
         CE.catch (Conn.connectionClose handle) (\(_ :: CE.SomeException) -> return ())
 
@@ -309,9 +312,10 @@     case heartbeatTimeout of
         Nothing      -> return ()
         Just timeout -> do
-            heartbeatThread <- watchHeartbeats conn (fromIntegral timeout) connThread
+            heartbeatThread <- watchHeartbeats conn (fromIntegral timeout) connThreadId
             addConnectionClosedHandler conn True (killThread heartbeatThread)
 
+    modifyMVar_ cThread $ \_ -> return $ Just connThreadId
     return conn
   where
     connect excs ((host, port) : rest) = do
@@ -408,9 +412,9 @@ 
 -- | kill the connection thread abruptly
 killConnection :: Connection -> CloseType -> CE.SomeException -> ThreadId -> IO ()
-killConnection conn closeType ex connThread = do
+killConnection conn closeType ex connThreadId = do
     modifyMVar_ (connClosed conn) $ const $ return $ Just (closeType, show ex)
-    throwTo connThread ex
+    throwTo connThreadId ex
 
 -- | closes a connection
 --
@@ -425,9 +429,12 @@             0 -- class_id
             0 -- method_id
         )
-        (\ (_ :: CE.IOException) ->
-            --do nothing if connection is already closed
-            return ()
+        (\ (e :: CE.IOException) -> do
+            -- Make sure the connection is closed.
+            -- (This pattern match can't fail, since openConnection'' will always fill
+            --  the variable in, and there's no other way to get a connection.)
+            Just thrID <- readMVar (connThread c)
+            killConnection c Abnormal (CE.toException e) thrID
         )
 
     -- wait for connection_close_ok by the server; this MVar gets filled in the CE.finally handler in openConnection'
amqp.cabal view
@@ -1,5 +1,5 @@ Name:                amqp
-Version:             0.22.0
+Version:             0.22.1
 Synopsis:            Client library for AMQP servers (currently only RabbitMQ)
 Description:         Client library for AMQP servers (currently only RabbitMQ)
 License:             BSD3
changelog.md view
@@ -1,3 +1,7 @@+### Version 0.22.1
+
+* fix a potential deadlock in `closeConnection`
+
 ### Version 0.22.0
 
 * `closeChannel` now uses a `ChannelClosedException` to kill the channel-thread instead of `ThreadKilled`. This fixes a bug in 0.21.0 that led to errors being printed on the screen when `closeChannel` was called.