Subject: bug#56674: [Shepherd] Use of ‘waitpid’, ‘system*’, etc. in service code can cause deadlocks

From: Ludovic Courtès <[email-masked]>
Date: Mon, 14 Nov 2022 00:16:38 +0100

Hi,

Ludovic Courtès <[email-masked]> skribis:

>   1. In the best case, shepherd (as of 0.9.1) is stuck while ‘system*’
>      is in ‘waitpid’ waiting for child process completion (“stuck” as
>      in: doesn’t do anything, not even answering ‘herd’ requests or
>      inetd connections.)
>
>   2. I don’t think that can happen with ‘system*’ (because it’s in C),
>      but generally speaking, there’s a possibility that shepherd’s event
>      loop will handle child process termination before some other
>      user-made ‘waitpid’ call does.
>
> Anyway, that’s a bad situation.
>
> So I can think of several ways to address it:
>
>   1. Change the nginx service ‘stop’ method to just
>      (make-kill-destructor), which should work just as well as invoking
>      “nginx -s stop”.
>
>   2. Have Shepherd provide a replacement for ‘system*’.

These fresh Shepherd commits install a non-blocking ‘system*’ replacement:

  975b0aa service: Provide a non-blocking replacement of 'system*'.
  039c7a8 service: Spawn a fiber responsible for process monitoring.

We’ll have to do more testing and probably go for a 0.9.3 release soon.

Protip: you can test the latest shepherd with:

--8<---------------cut here---------------start------------->8---
(operating-system
  ;; …
  (essential-services
   (modify-services (operating-system-default-essential-services
                     this-operating-system)
     (shepherd-root-service-type
      config =>
      (shepherd-configuration
       (shepherd (package
                   (inherit shepherd-0.9)
                   (version "0.9.3pre")
                   (source (git-checkout
                            (url "https://git.savannah.gnu.org/git/shepherd.git")))
                   (native-inputs
                    (modify-inputs (package-native-inputs shepherd-0.9)
                      (append autoconf automake help2man texinfo gnu-gettext))))))))))
--8<---------------cut here---------------end--------------->8---

Full example attached.

Ludo’.

;; This is an operating system configuration template
;; for a "bare bones" setup, with no X11 display server.

(use-modules (gnu) (guix) (guix git))
(use-service-modules networking ssh web vpn shepherd)
(use-package-modules linux screen ssh
                     admin autotools gettext man texinfo)

(operating-system
  (host-name "komputilo")
  (timezone "Europe/Berlin")
  (locale "en_US.utf8")

  ;; Boot in "legacy" BIOS mode, assuming /dev/sdX is the
  ;; target hard disk, and "my-root" is the label of the target
  ;; root file system.
  (bootloader (bootloader-configuration
               (bootloader grub-bootloader)
               (targets '("/dev/sdX"))))
  ;; It's fitting to support the equally bare bones ‘-nographic’
  ;; QEMU option, which also nicely sidesteps forcing QWERTY.
  (kernel-arguments (list "console=ttyS0,115200"))
  (file-systems (cons (file-system
                        (device (file-system-label "my-root"))
                        (mount-point "/")
                        (type "ext4"))
                      %base-file-systems))

  ;; This is where user accounts are specified.  The "root"
  ;; account is implicit, and is initially created with the
  ;; empty password.
  (users (cons (user-account
                (name "alice")
                (comment "Bob's sister")
                (group "users")

                ;; Adding the account to the "wheel" group
                ;; makes it a sudoer.  Adding it to "audio"
                ;; and "video" allows the user to play sound
                ;; and access the webcam.
                (supplementary-groups '("wheel"
                                        "audio" "video")))
               %base-user-accounts))

  ;; Globally-installed packages.
  (packages (append (list screen strace) %base-packages))

  (essential-services
   (modify-services (operating-system-default-essential-services
                     this-operating-system)
     (shepherd-root-service-type
      config =>
      (shepherd-configuration
       (shepherd (package
                   (inherit shepherd-0.9)
                   (version "0.9.3pre")
                   (source (git-checkout
                            (url "https://git.savannah.gnu.org/git/shepherd.git")))
                   (native-inputs
                    (modify-inputs (package-native-inputs shepherd-0.9)
                      (append autoconf automake help2man texinfo gnu-gettext)))))))))

  ;; Add services to the baseline: a DHCP client and
  ;; an SSH server.
  (services (append (list (service dhcp-client-service-type)
                          (service nginx-service-type
                                   (nginx-configuration
                                    (server-blocks
                                     (list (nginx-server-configuration
                                            (listen '("80"))
                                            (server-name '("www.example.org"))
                                            (root "/srv/whatever"))))))
                          (service wireguard-service-type
                                   (wireguard-configuration
                                    (addresses (list "10.0.0.2/24"))
                                    (dns '("10.0.0.50")))) ;does not exit

                          (service openssh-service-type
                                   (openssh-configuration
                                    (openssh openssh-sans-x)
                                    (port-number 2222))))
                    %base-services)))