diff --git a/crunghc.cabal b/crunghc.cabal
--- a/crunghc.cabal
+++ b/crunghc.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                crunghc
-version:             0.1.0.0
+version:             0.1.1.1
 synopsis:            A runghc replacement with transparent caching
 description:         crunghc is a program that acts like runghc. When it
                      executes a Haskell script, it automatically stores a
@@ -18,6 +18,10 @@
 -- extra-source-files:  
 cabal-version:       >=1.10
 
+source-repository head
+  type: git
+  location: https://github.com/takano-akio/crunghc.git
+
 executable crunghc
   main-is:  main.hs
   -- other-modules:       
@@ -27,6 +31,7 @@
                        transformers >= 0.3, filelock >= 0.0, time >= 1.4
   -- hs-source-dirs:      
   default-language:    Haskell2010
+  ghc-options:         -threaded
 
   if !os(windows)
     build-depends:    unix
diff --git a/main.hs b/main.hs
--- a/main.hs
+++ b/main.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveDataTypeable #-}
 
 import Control.Applicative
 import qualified Control.Exception as E
@@ -10,11 +11,12 @@
 import Data.Char
 import qualified Data.Digest.Pure.SHA as SHA
 import Data.List
+import Data.Maybe
+import Data.Monoid
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as T
 import Data.Time.Clock
-import Data.Maybe
-import Data.Monoid
+import Data.Typeable
 import System.Directory
 import System.Environment
 import System.Exit
@@ -25,7 +27,9 @@
 import System.Process
 
 #if USE_UNIX
+import Control.Concurrent (myThreadId)
 import System.Posix.Files (createLink)
+import qualified System.Posix.Signals as Sig
 #endif
 
 data Config = Config
@@ -47,10 +51,22 @@
 
 main :: IO ()
 main = do
+  installSignalHandlers
   config <- fromRightIO . parseConfig =<< getArgs
   plan <- chooseCachePlan config
   createDirectoryIfMissing True $ cpCachedir plan
-  (tempExeCopy, cleanup) <- withFileLock (lockfile plan) Exclusive $ \_ -> do
+  E.bracket
+    (prepareExecutable config plan)
+    snd -- cleanup
+    (runTemp config . fst)
+  `E.catch` \(KilledBySignal _) -> exitFailure
+
+-- | Prepare a cached executable by rebuilding it if necessary.
+-- Return a fresh copy or link of the executable and a cleanup action.
+prepareExecutable
+  :: Config -> CachePlan -> IO (FilePath, IO ())
+prepareExecutable config plan =
+  withFileLock (lockfile plan) Exclusive $ \_ -> do
     needRecomp <- testRecompilationNeeded config plan
     when needRecomp $ recompile config plan
 
@@ -61,7 +77,6 @@
     --  the cached executable after we unlock it and before we execute it.
     -- 2. on Windows you cannot replace an executable while it's running.
     makeTemporaryExeCopy plan
-  runTemp config tempExeCopy `E.finally` cleanup
 
 parseConfig :: [String] -> Either String Config
 parseConfig args = case span ("-" `isPrefixOf`) args of
@@ -221,6 +236,37 @@
     looksLikeSourceFile =
       ".hs" `isSuffixOf` ln ||
       ".lhs" `isSuffixOf` ln
+
+----------
+-- signals
+
+newtype KilledBySignal = KilledBySignal Signal
+  deriving (Show, Typeable)
+
+instance E.Exception KilledBySignal
+
+#if USE_UNIX
+type Signal = Sig.Signal
+#else
+type Signal = ()
+#endif
+
+-- | Install signal handlers that turn signals into KilledBySignal exceptions.
+installSignalHandlers :: IO ()
+#if USE_UNIX
+installSignalHandlers = do
+  tid <- myThreadId
+  forM_ [Sig.softwareTermination] $ \sig ->
+    void $ Sig.installHandler sig (handler tid sig) Nothing
+  where
+    handler tid sig = Sig.Catch $ do
+      E.throwTo tid $ KilledBySignal sig
+#else
+installSignalHandlers = return ()
+#endif
+
+------------
+-- utilities
 
 takeWhileEnd :: (a -> Bool) -> [a] -> [a]
 takeWhileEnd p = reverse . takeWhile p . reverse
