[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[shepherd] 03/04: service: 'fork+exec-command' blocks handled signals be
From: |
Ludovic Courtès |
Subject: |
[shepherd] 03/04: service: 'fork+exec-command' blocks handled signals before forking. |
Date: |
Tue, 2 Jun 2020 17:36:48 -0400 (EDT) |
civodul pushed a commit to branch master
in repository shepherd.
commit 576ac6155dcabea47dfdf69fb9a8cc07cecf9695
Author: Ludovic Courtès <ludo@gnu.org>
AuthorDate: Sat May 30 19:32:43 2020 +0200
service: 'fork+exec-command' blocks handled signals before forking.
This is a followup to d190773751ddeddbe0daa8e4a43f76b73c4fd7ac, which
addressed only SIGTERM instead of all of %PRECIOUS-SIGNALS.
Furthermore, setting the SIGTERM handler introduced a window in the
shepherd process during which SIGTERM instances would be lost.
* modules/shepherd/service.scm (%precious-signals): New variable.
(fork+exec-command): Remove calls to 'sigaction' for SIGTERM. Wrap
'let' in 'with-blocked-signals'. Restore default signal handlers in the
child before unblocking signals.
---
modules/shepherd/service.scm | 53 ++++++++++++++++++++++----------------------
1 file changed, 26 insertions(+), 27 deletions(-)
diff --git a/modules/shepherd/service.scm b/modules/shepherd/service.scm
index f3ac32a..1bc77b1 100644
--- a/modules/shepherd/service.scm
+++ b/modules/shepherd/service.scm
@@ -870,6 +870,10 @@ false."
program (strerror (system-error-errno args)))
(primitive-exit 1))))))))
+(define %precious-signals
+ ;; Signals that the shepherd process handles.
+ (list SIGCHLD SIGINT SIGHUP SIGTERM))
+
(define* (fork+exec-command command
#:key
(user #f)
@@ -886,33 +890,28 @@ its PID."
(sigaction SIGCHLD handle-SIGCHLD SA_NOCLDSTOP)
(set! %sigchld-handler-installed? #t))
- ;; When forking a process, the signal handlers are inherited, until it
- ;; forks. If SIGTERM is received by the forked process, before it calls
- ;; execv, the installed SIGTERM handler, stopping Shepherd will be called.
- ;; To avoid this, save the SIGTERM handler, disable it, and restore it once,
- ;; the process has been forked. This way, the forked process will use the
- ;; default SIGTERM handler stopping the process.
- (let ((term-handler (match (sigaction SIGTERM)
- ((proc . _)
- proc)))
- (pid (and (sigaction SIGTERM SIG_DFL)
- (primitive-fork))))
- (if (zero? pid)
- (begin
- ;; Unblock any signals that might have been blocked by the parent
- ;; process if using 'signalfd'.
- (unblock-signals (list SIGCHLD SIGINT SIGHUP SIGTERM))
-
- (exec-command command
- #:user user
- #:group group
- #:log-file log-file
- #:directory directory
- #:file-creation-mask file-creation-mask
- #:environment-variables environment-variables))
- (begin
- ;; Restore the initial SIGTERM handler.
- (sigaction SIGTERM term-handler)
+ ;; Child processes inherit signal handlers until they exec. If one of
+ ;; %PRECIOUS-SIGNALS is received by the child before it execs, the installed
+ ;; handler, which stops shepherd, is called. To avoid this, block signals
+ ;; so that the child process never executes those handlers.
+ (with-blocked-signals %precious-signals
+ (let ((pid (primitive-fork)))
+ (if (zero? pid)
+ (begin
+ ;; First restore the default handlers.
+ (for-each (cut sigaction <> SIG_DFL) %precious-signals)
+
+ ;; Unblock any signals that have been blocked by the parent
+ ;; process.
+ (unblock-signals %precious-signals)
+
+ (exec-command command
+ #:user user
+ #:group group
+ #:log-file log-file
+ #:directory directory
+ #:file-creation-mask file-creation-mask
+ #:environment-variables environment-variables))
pid))))
(define* (make-forkexec-constructor command