This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "snap-server".

The branch, master has been updated
       via  d33b527c51d69b2e145eab2c2dd34b6e3992adab (commit)
      from  50497e9726db1d3e52afb9608e8f4f8bb3b8b4e5 (commit)


Summary of changes:
 src/Snap/Internal/Http/Server.hs               |    2 +-
 src/Snap/Internal/Http/Server/SimpleBackend.hs |  103 +++++++++++++++++-------
 2 files changed, 73 insertions(+), 32 deletions(-)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit d33b527c51d69b2e145eab2c2dd34b6e3992adab
Author: Gregory Collins <[email protected]>
Date:   Wed Sep 22 18:24:11 2010 -0400

    Simple backend: do a better job of handling shutdowns

diff --git a/src/Snap/Internal/Http/Server.hs b/src/Snap/Internal/Http/Server.hs
index fd40555..6ab3b13 100644
--- a/src/Snap/Internal/Http/Server.hs
+++ b/src/Snap/Internal/Http/Server.hs
@@ -206,7 +206,7 @@ httpServe bindAddress bindPort localHostname alogPath 
elogPath handler =
         , Handler $ \(e :: AsyncException) -> do
               logE elog $
                    S.concat [ "Server.httpServe.go: got async exception, "
-                            , "terminating:\n", bshow e ]
+                            , "terminating: ", bshow e ]
               throwIO e
 
         , Handler $ \(e :: Backend.BackendTerminatedException) -> do
diff --git a/src/Snap/Internal/Http/Server/SimpleBackend.hs 
b/src/Snap/Internal/Http/Server/SimpleBackend.hs
index 7324bbd..25bf59a 100644
--- a/src/Snap/Internal/Http/Server/SimpleBackend.hs
+++ b/src/Snap/Internal/Http/Server/SimpleBackend.hs
@@ -33,6 +33,7 @@ import "monads-fd" Control.Monad.Trans
 
 import           Control.Concurrent
 import           Control.Exception
+import           Control.Monad
 import           Data.ByteString (ByteString)
 import           Data.ByteString.Internal (c2w, w2c)
 import qualified Data.ByteString as B
@@ -72,10 +73,15 @@ instance Exception BackendTerminatedException
 
 type TimeoutTable = PSQ ThreadId CTime
 
+type QueueElem = Maybe (Socket,SockAddr)
+
 data Backend = Backend
-    { _acceptSocket  :: !Socket
-    , _timeoutEdits  :: !(IORef (DList (TimeoutTable -> TimeoutTable)))
-    , _timeoutThread :: !(MVar ThreadId) }
+    { _acceptSocket    :: !Socket
+    , _acceptThread    :: !ThreadId
+    , _timeoutEdits    :: !(IORef (DList (TimeoutTable -> TimeoutTable)))
+    , _timeoutThread   :: !(MVar ThreadId)
+    , _connectionQueue :: !(Chan QueueElem)
+    }
 
 data Connection = Connection 
     { _backend     :: Backend
@@ -127,16 +133,37 @@ bindIt bindAddress bindPort = do
     return sock
 
 
+acceptThread :: Socket -> Chan QueueElem -> IO ()
+acceptThread sock connq = loop `finally` cleanup
+  where
+    loop = do
+        debug $ "acceptThread: calling accept()"
+        s@(_,addr) <- accept sock
+        debug $ "acceptThread: accepted connection from remote: " ++ show addr
+        debug $ "acceptThread: queueing"
+        writeChan connq $ Just s
+        loop
+
+    cleanup = block $ do
+        debug $ "acceptThread: cleanup, closing socket and notifying "
+                  ++ "chan listeners"
+        sClose sock
+        replicateM 10 $ writeChan connq Nothing
+
+
 new :: Socket   -- ^ value you got from bindIt
     -> Int
     -> IO Backend
-new sock _ = do
+new sock cpu = do
     debug $ "Backend.new: listening"
 
-    ed  <- newIORef D.empty
-    t   <- newEmptyMVar
+    ed        <- newIORef D.empty
+    t         <- newEmptyMVar
 
-    let b = Backend sock ed t
+    connq     <- newChan
+    accThread <- forkOnIO cpu $ acceptThread sock connq
+
+    let b = Backend sock accThread ed t connq
 
     tid <- forkIO $ timeoutThread b
     putMVar t tid
@@ -155,14 +182,16 @@ timeoutThread backend = do
     loop `catch` (\(_::SomeException) -> killAll tref)
 
   where
+    applyEdits table = do
+        edits <- atomicModifyIORef tedits $ \t -> (D.empty, D.toList t)
+        return $ foldl' (flip ($)) table edits
+
     killTooOld tref = do
         !table <- readIORef tref
         -- atomic swap edit list
-        now   <- getCurrentDateTime
-        edits <- atomicModifyIORef tedits $ \t -> (D.empty, D.toList t)
-
-        let table' = foldl' (flip ($)) table edits
-        !t'   <- killOlderThan now table'
+        now    <- getCurrentDateTime
+        table' <- applyEdits table
+        !t'    <- killOlderThan now table'
         writeIORef tref t'
 
 
@@ -171,13 +200,14 @@ timeoutThread backend = do
 
     killAll !tref = do
         debug "Backend.timeoutThread: shutdown, killing all connections"
-        !table <- readIORef tref
-        go table
+        !table  <- readIORef tref
+        !table' <- applyEdits table
+        go table'
       where
-        go t = maybe (return ())
-                     (\m -> (killThread $ PSQ.key m) >>
-                            (go $ PSQ.deleteMin t))
-                     (PSQ.findMin t)
+        go !t = maybe (return ())
+                      (\m -> (killThread $ PSQ.key m) >>
+                             (go $ PSQ.deleteMin t))
+                      (PSQ.findMin t)
 
     killOlderThan now !table = do
         debug "Backend.timeoutThread: killing old connections"
@@ -199,14 +229,20 @@ timeoutThread backend = do
 
 
 stop :: Backend -> IO ()
-stop (Backend s _ t) = do
-    debug $ "Backend.stop"
-    sClose s
+stop backend = do
+    debug $ "Backend.stop: killing accept thread"
+    killThread acthr
 
-    -- kill timeout thread and current thread; timeout thread handler will stop
-    -- all of the running connection threads
-    readMVar t >>= killThread
-    myThreadId >>= killThread
+    debug $ "Backend.stop: killing timeout thread"
+
+    -- kill timeout thread; timeout thread handler will stop all of the running
+    -- connection threads
+    readMVar tthr >>= killThread
+    debug $ "Backend.stop: exiting.."
+
+  where
+    acthr = _acceptThread  backend
+    tthr  = _timeoutThread backend
 
 
 data AddressNotSupportedException = AddressNotSupportedException String
@@ -220,14 +256,19 @@ instance Exception AddressNotSupportedException
 
 withConnection :: Backend -> Int -> (Connection -> IO ()) -> IO ()
 withConnection backend cpu proc = do
-    debug $ "Backend.withConnection: calling accept()"
-    let asock = _acceptSocket backend
-    (sock,addr) <- accept asock
+    debug $ "Backend.withConnection: reading from chan"
+
+    qelem <- readChan $ _connectionQueue backend
+    when (qelem == Nothing) $ do
+        debug $ "Backend.withConnection: channel terminated, throwing "
+                  ++ "BackendTerminatedException"
+        throwIO BackendTerminatedException
 
+    let (Just (sock,addr)) = qelem
     let fd = fdSocket sock
 
-    debug $ "Backend.withConnection: accepted connection"
-    debug $ "Backend.withConnection: remote: " ++ show addr
+    debug $ "Backend.withConnection: dequeued connection from remote: "
+              ++ show addr
 
     (port,host) <-
         case addr of
@@ -253,7 +294,7 @@ withConnection backend cpu proc = do
         labelMe $ "connHndl " ++ show fd
         bracket (return c)
                 (\_ -> block $ do
-                     debug "sClose sock"
+                     debug "thread killed, closing socket"
                      thr <- readMVar tmvar
 
                      -- remove thread from timeout table
-----------------------------------------------------------------------


hooks/post-receive
-- 
snap-server
_______________________________________________
Snap mailing list
[email protected]
http://mailman-mail5.webfaction.com/listinfo/snap

Reply via email to