Skip to content

Commit a03b4a7

Browse files
robxmergify-bot
authored and
mergify-bot
committed
Handle SIGTERM by throwing an asynchronous exception
That's roughly how Ctrl-C (SIGINT) is handled by the GHC runtime. This way, killing cabal via SIGTERM will give it a chance to terminate any running children. Previously, it would exit directly, leaving children behind to exit on their own.
1 parent 0284bfb commit a03b4a7

File tree

3 files changed

+53
-0
lines changed

3 files changed

+53
-0
lines changed

cabal-install/cabal-install.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ library
165165
Distribution.Client.Security.HTTP
166166
Distribution.Client.Setup
167167
Distribution.Client.SetupWrapper
168+
Distribution.Client.Signal
168169
Distribution.Client.SolverInstallPlan
169170
Distribution.Client.SourceFiles
170171
Distribution.Client.SrcDist

cabal-install/main/Main.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ import Distribution.Client.Manpage (manpageCmd)
113113
import Distribution.Client.ManpageFlags (ManpageFlags (..))
114114
import Distribution.Client.Utils
115115
( determineNumJobs, relaxEncodingErrors )
116+
import Distribution.Client.Signal
117+
( installTerminationHandler )
116118
import Distribution.Client.Version
117119
( cabalInstallVersion )
118120

@@ -170,6 +172,7 @@ import Control.Exception (try)
170172
--
171173
main :: IO ()
172174
main = do
175+
installTerminationHandler
173176
-- Enable line buffering so that we can get fast feedback even when piped.
174177
-- This is especially important for CI and build systems.
175178
hSetBuffering stdout LineBuffering
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{-# LANGUAGE CPP #-}
2+
module Distribution.Client.Signal
3+
( installTerminationHandler
4+
, Terminated(..)
5+
)
6+
where
7+
8+
import qualified Control.Exception as Exception
9+
10+
#ifndef mingw32_HOST_OS
11+
import Control.Concurrent (myThreadId)
12+
import Control.Monad (void)
13+
import qualified System.Posix.Signals as Signals
14+
#endif
15+
16+
-- | Terminated is an asynchronous exception, thrown when
17+
-- SIGTERM is received. It's to 'kill' what 'UserInterrupt'
18+
-- is to Ctrl-C.
19+
data Terminated = Terminated
20+
21+
instance Exception.Exception Terminated where
22+
toException = Exception.asyncExceptionToException
23+
fromException = Exception.asyncExceptionFromException
24+
25+
instance Show Terminated where
26+
show Terminated = "terminated"
27+
28+
-- | Install a signal handler that initiates a controlled shutdown on receiving
29+
-- SIGTERM by throwing an asynchronous exception at the main thread. Must be
30+
-- called from the main thread.
31+
--
32+
-- It is a noop on Windows.
33+
--
34+
installTerminationHandler :: IO ()
35+
36+
#ifdef mingw32_HOST_OS
37+
38+
installTerminationHandler = return ()
39+
40+
#else
41+
42+
installTerminationHandler = do
43+
mainThreadId <- myThreadId
44+
void $ Signals.installHandler
45+
Signals.sigTERM
46+
(Signals.CatchOnce $ Exception.throwTo mainThreadId Terminated)
47+
Nothing
48+
49+
#endif

0 commit comments

Comments
 (0)