guix-commits
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]