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".

The branch, master has been updated
       via  ba3d8ac60131a4277e4549a3fe21eac118a6751c (commit)
      from  b96c4bb62b533bcab9872403700a0d05bf183af4 (commit)


Summary of changes:
 project_template/default/src/Main.hs         |    9 +-
 src/Snap/Extension/Loader/Devel.hs           |    2 +-
 src/Snap/Extension/Loader/Devel/Evaluator.hs |  138 ++++++++++++++------------
 3 files changed, 80 insertions(+), 69 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 ba3d8ac60131a4277e4549a3fe21eac118a6751c
Author: Carl Howells <[email protected]>
Date:   Tue Feb 8 11:29:20 2011 -0800

    Fix handling of cleanup actions on server shutdown in development mode

diff --git a/project_template/default/src/Main.hs 
b/project_template/default/src/Main.hs
index 332ccc8..56c52d9 100644
--- a/project_template/default/src/Main.hs
+++ b/project_template/default/src/Main.hs
@@ -42,6 +42,8 @@ change.
 module Main where
 
 #ifdef DEVELOPMENT
+import           Control.Exception (SomeException, try)
+
 import           Snap.Extension.Loader.Devel
 import           Snap.Http.Server (quickHttpServe)
 #else
@@ -57,9 +59,10 @@ main = do
     -- All source directories will be watched for updates
     -- automatically.  If any extra directories should be watched for
     -- updates, include them here.
-    snap <- $(let extraWatcheDirs = ["resources/templates"]
-              in loadSnapTH 'applicationInitializer 'site extraWatcheDirs)
-    quickHttpServe snap
+    (snap, cleanup) <- $(let watchDirs = ["resources/templates"]
+                         in loadSnapTH 'applicationInitializer 'site watchDirs)
+    try $ quickHttpServe snap :: IO (Either SomeException ())
+    cleanup
 #else
 main = quickHttpServe applicationInitializer site
 #endif
diff --git a/src/Snap/Extension/Loader/Devel.hs 
b/src/Snap/Extension/Loader/Devel.hs
index 5a87d0d..47ab857 100644
--- a/src/Snap/Extension/Loader/Devel.hs
+++ b/src/Snap/Extension/Loader/Devel.hs
@@ -141,7 +141,7 @@ hintSnap :: [String] -- ^ A list of command-line options 
for the interpreter
                      -- the expression passed in.
          -> [String] -- ^ A list of paths to watch for updates
          -> String   -- ^ The string to execute
-         -> IO (Snap ())
+         -> IO (Snap (), IO ())
 hintSnap opts modules imports srcPaths action =
     protectedHintEvaluator initialize test loader
   where
diff --git a/src/Snap/Extension/Loader/Devel/Evaluator.hs 
b/src/Snap/Extension/Loader/Devel/Evaluator.hs
index 01b1c16..3820763 100644
--- a/src/Snap/Extension/Loader/Devel/Evaluator.hs
+++ b/src/Snap/Extension/Loader/Devel/Evaluator.hs
@@ -43,7 +43,7 @@ protectedHintEvaluator :: forall a.
                           IO a
                        -> (a -> IO Bool)
                        -> IO HintLoadable
-                       -> IO (Snap ())
+                       -> IO (Snap (), IO ())
 protectedHintEvaluator start test getInternals = do
     -- The list of requesters waiting for a result.  Contains the
     -- ThreadId in case of exceptions, and an empty MVar awaiting a
@@ -61,70 +61,78 @@ protectedHintEvaluator start test getInternals = do
     -- "keep them full, unless updating them."  In every case, when
     -- one of those MVars is emptied, the next action is to fill that
     -- same MVar.  This makes deadlocking on MVar wait impossible.
-    return $ do
-        let waitForNewResult :: IO (Snap ())
-            waitForNewResult = do
-                -- Need to calculate a new result
-                tid <- myThreadId
-                reader <- newEmptyMVar
-
-                readers <- takeMVar readerContainer
-
-                -- Some strictness is employed to ensure the MVar
-                -- isn't holding on to a chain of unevaluated thunks.
-                let pair = (tid, reader)
-                    newReaders = readers `seq` pair `seq` (pair : readers)
-                putMVar readerContainer $! newReaders
-
-                -- If this is the first reader to queue, clean up the
-                -- previous state, if there was any, and then begin
-                -- evaluation of the new code and state.
-                when (null readers) $ do
-                    let runAndFill = block $ do
-                            -- run the cleanup action
-                            previous <- readMVar resultContainer
-                            unblock $ cleanup previous
-
-                            -- compile the new internals and initialize
-                            stateInitializer <- unblock getInternals
-                            res <- unblock stateInitializer
-
-                            let a = fst res
-
-                            clearAndNotify (Right res) (flip putMVar a . snd)
-
-                        killWaiting :: SomeException -> IO ()
-                        killWaiting e = block $ do
-                            clearAndNotify (Left e) (flip throwTo e . fst)
-                            throwIO e
-
-                        clearAndNotify r f = do
-                            a <- unblock start
-                            _ <- swapMVar resultContainer $ Just (r, a)
-                            allReaders <- swapMVar readerContainer []
-                            mapM_ f allReaders
-
-                    _ <- forkIO $ runAndFill `catch` killWaiting
-                    return ()
-
-                -- Wait for the evaluation of the action to complete,
-                -- and return its result.
-                takeMVar reader
-
-        existingResult <- liftIO $ readMVar resultContainer
-
-        getResult <- liftIO $ case existingResult of
-            Just (res, a) -> do
-                -- There's an existing result.  Check for validity
-                valid <- test a
-                case (valid, res) of
-                    (True, Right (x, _)) -> return x
-                    (True, Left e)       -> throwIO e
-                    (False, _)           -> do
-                        _ <- swapMVar resultContainer Nothing
-                        waitForNewResult
-            Nothing -> waitForNewResult
-        getResult
+    let snap = do
+            let waitForNewResult :: IO (Snap ())
+                waitForNewResult = do
+                    -- Need to calculate a new result
+                    tid <- myThreadId
+                    reader <- newEmptyMVar
+
+                    readers <- takeMVar readerContainer
+
+                    -- Some strictness is employed to ensure the MVar
+                    -- isn't holding on to a chain of unevaluated thunks.
+                    let pair = (tid, reader)
+                        newReaders = readers `seq` pair `seq` (pair : readers)
+                    putMVar readerContainer $! newReaders
+
+                    -- If this is the first reader to queue, clean up the
+                    -- previous state, if there was any, and then begin
+                    -- evaluation of the new code and state.
+                    when (null readers) $ do
+                        let runAndFill = block $ do
+                                -- run the cleanup action
+                                previous <- readMVar resultContainer
+                                unblock $ cleanup previous
+
+                                -- compile the new internals and initialize
+                                stateInitializer <- unblock getInternals
+                                res <- unblock stateInitializer
+
+                                let a = fst res
+
+                                clearAndNotify (Right res) (flip putMVar a . 
snd)
+
+                            killWaiting :: SomeException -> IO ()
+                            killWaiting e = block $ do
+                                clearAndNotify (Left e) (flip throwTo e . fst)
+                                throwIO e
+
+                            clearAndNotify r f = do
+                                a <- unblock start
+                                _ <- swapMVar resultContainer $ Just (r, a)
+                                allReaders <- swapMVar readerContainer []
+                                mapM_ f allReaders
+
+                        _ <- forkIO $ runAndFill `catch` killWaiting
+                        return ()
+
+                    -- Wait for the evaluation of the action to complete,
+                    -- and return its result.
+                    takeMVar reader
+
+            existingResult <- liftIO $ readMVar resultContainer
+
+            getResult <- liftIO $ case existingResult of
+                Just (res, a) -> do
+                    -- There's an existing result.  Check for validity
+                    valid <- test a
+                    case (valid, res) of
+                        (True, Right (x, _)) -> return x
+                        (True, Left e)       -> throwIO e
+                        (False, _)           -> do
+                            _ <- swapMVar resultContainer Nothing
+                            waitForNewResult
+                Nothing -> waitForNewResult
+            getResult
+
+        clean = do
+             let msg = "invalid dynamic loader state.  " ++
+                       "The cleanup action has been executed"
+             contents <- swapMVar resultContainer $ error msg
+             cleanup contents
+
+    return (snap, clean)
   where
     newReaderContainer :: IO (MVar [(ThreadId, MVar (Snap ()))])
     newReaderContainer = newMVar []
-----------------------------------------------------------------------


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

Reply via email to