Skip to content

Commit

Permalink
Merge pull request #10 from denibertovic/master
Browse files Browse the repository at this point in the history
Adds ability to only SIGTERM the immediate process
  • Loading branch information
snoyberg committed Oct 12, 2021
2 parents 0ebece9 + db9fa58 commit 6f2e150
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 7 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ Where:
* `-w`, `--workdir` `DIR` - chdir to `DIR` before executing COMMAND
* `-t`, `--timeout` `TIMEOUT` - timeout (in seconds) to wait for all child processes to exit

`WARNING`: by default pid1 will first send the TERM signal to it's "immediate child" process.
In most scenarios that will be the only process running but in some cases that will be the
"main" process that could have spawned it's own children. In this scenario it's prudent to shutdown
the "main" process first, since usually it has mechanisms in place to shut down it's children. If
we were to shutdown a child process before "main" was shutdown it might try to restart it.
This is why, if the "main" process doesn't exit within `timeout` we will proceed to send the TERM
signal to all processes and wait **again** for `timeout` until we finally send the KILL signal to all
processes. This is a **breaking change since 0.1.3.0**.

The recommended use case for this executable is to embed it in a Docker image.
Assuming you've placed it at `/sbin/pid1`, the two commonly recommended usages
are:
Expand Down
2 changes: 1 addition & 1 deletion pid1.cabal
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: pid1
version: 0.1.2.0
version: 0.1.3.0
synopsis: Do signal handling and orphan reaping for Unix PID1 init processes
description: Please see README.md or view Haddocks at <https://www.stackage.org/package/pid1>
homepage: https://github.com/fpco/pid1#readme
Expand Down
24 changes: 18 additions & 6 deletions src/System/Process/PID1.hs
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,6 @@ runAsPID1 cmd args env' timeout = do
-- children processes. Then start a thread waiting for that
-- variable to be filled and do the actual killing.
killChildrenVar <- newEmptyMVar
_ <- forkIO $ do
takeMVar killChildrenVar
killAllChildren timeout

-- Helper function to start killing, used below
let startKilling = void $ tryPutMVar killChildrenVar ()
Expand All @@ -206,6 +203,10 @@ runAsPID1 cmd args env' timeout = do
ClosedHandle e -> assert False (exitWith e)
OpenHandle pid -> return pid

_ <- forkIO $ do
takeMVar killChildrenVar
killAllChildren child timeout

-- Loop on reaping child processes
reap startKilling child

Expand Down Expand Up @@ -247,9 +248,20 @@ reap startKilling child = do
startKilling
| otherwise -> return ()

killAllChildren :: Int -> IO ()
killAllChildren timeout = do
-- Send all children processes the TERM signal
killAllChildren :: CPid -> Int -> IO ()
killAllChildren cid timeout = do
-- Send the direct child process the TERM signal
signalProcess sigTERM cid `catch` \e ->
if isDoesNotExistError e
then return ()
else throwIO e

-- Wait for `timeout` seconds and allow the 'main' process to take care
-- of shutting down any child processes itself.
threadDelay $ timeout * 1000 * 1000

-- If the 'main' process did not handle shutting down the rest of the
-- child processes we will signal SIGTERM to them directly.
signalProcess sigTERM (-1) `catch` \e ->
if isDoesNotExistError e
then return ()
Expand Down

0 comments on commit 6f2e150

Please sign in to comment.