From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp12.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id cC3vHUpj+2P6SgEAbAwnHQ (envelope-from ) for ; Sun, 26 Feb 2023 14:48:58 +0100 Received: from aspmx1.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp12.migadu.com with LMTPS id QLTFHUpj+2PVCAAAauVa8A (envelope-from ) for ; Sun, 26 Feb 2023 14:48:58 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 20801D8A7 for ; Sun, 26 Feb 2023 14:48:58 +0100 (CET) Authentication-Results: aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=tilde.club header.s=mail header.b=akrLCwLu; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=tilde.club (policy=none) ARC-Seal: i=1; s=key1; d=yhetil.org; t=1677419338; a=rsa-sha256; cv=none; b=VxrHTnN+HGEGBYjjBFymAckpioKDBKW7v6nK3upMUhTH7ZA4JWnb0+r961Pu6fLw32M3Uu IijcIlAWZCI/RDE/wNv6VKaRasEPhHw/Lp5ZkNuFXnBbEOqzt+HrjdTaoNroqCESFyJdaN 7W2pz+LB70UyJC7xeat32mZAn+U9/LD88swGGccJwrs8EmnJ9uATuYA7AH6u/RaLC2T+jn WZ3UtX6ljxiBkCLnGfhf2SzQ1Fu1LKYlm3rwDh0x5wvUmgc3YDLWbpEOcWcM1ATA0DA+eq AxJKGkOx0N+AAeBxX2W4n1YBF69Fx32E8yJZnumkPwoRrDVVCgDrsMNCC0mE2w== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("headers rsa verify failed") header.d=tilde.club header.s=mail header.b=akrLCwLu; spf=pass (aspmx1.migadu.com: domain of "guix-patches-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="guix-patches-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed)" header.from=tilde.club (policy=none) ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1677419338; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type:resent-cc:resent-from:resent-sender: resent-message-id:list-id:list-help:list-unsubscribe:list-subscribe: list-post:dkim-signature; bh=Ait68GwLqwGJwfLRsfcR0y3gYTzzs7oIK7LnPAJ2mcY=; b=Y5IR2llKYzjlAgbRY+Qj2fFOeBKViVWPXy3JpM4DonZ4HUpJ2APCMF5dgOFtNf+ZUaZfCS 2DNSzNQZ5QUspNaMIp9ZfeyeFTpncnpfVTb5sCv5GVVyBstIeV4dP+Ki+F8JJEqI09L1ai 7EVFXm3l+VVsuy0eumbfRhYZT53kx/wAYbsg8R+ztutg7e1WoGl9/43QooFYB/7meIu0K6 VFEJ7GFvLemanDtZMpGZapjiZziLZhAp3N/ugojAUgwnn2tZhUvYoqFphIvUpI9mLiKGPZ WnO6dPMUjDbiL0rMhI+LLOwiHO18XV7zjXw8s3aUsczfKhWn3KZDWnh7h4lv/Q== Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pWHOS-0007Ic-1B; Sun, 26 Feb 2023 08:48:48 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pWCRu-0004Ii-RI for guix-patches@gnu.org; Sun, 26 Feb 2023 03:32:03 -0500 Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pWCRu-00043M-HX for guix-patches@gnu.org; Sun, 26 Feb 2023 03:32:02 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1pWCRu-0005MO-DJ for guix-patches@gnu.org; Sun, 26 Feb 2023 03:32:02 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#61803] [PATCH 0/3] [shepherd] improve race-free spawn+wait Resent-From: Ulf Herrman Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 26 Feb 2023 08:32:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 61803 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 61803@debbugs.gnu.org X-Debbugs-Original-To: guix-patches@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.167740028220549 (code B ref -1); Sun, 26 Feb 2023 08:32:02 +0000 Received: (at submit) by debbugs.gnu.org; 26 Feb 2023 08:31:22 +0000 Received: from localhost ([127.0.0.1]:42287 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pWCRD-0005LJ-BK for submit@debbugs.gnu.org; Sun, 26 Feb 2023 03:31:22 -0500 Received: from lists.gnu.org ([209.51.188.17]:49856) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pW2iF-0006yJ-Ld for submit@debbugs.gnu.org; Sat, 25 Feb 2023 17:08:16 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pW2iF-0003ji-DN for guix-patches@gnu.org; Sat, 25 Feb 2023 17:08:15 -0500 Received: from tilde.club ([2607:5300:204:4340::114]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pW2iD-0005B2-8c for guix-patches@gnu.org; Sat, 25 Feb 2023 17:08:15 -0500 Received: by tilde.club (Postfix, from userid 5378) id DA07B220B360C; Sat, 25 Feb 2023 22:08:07 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 tilde.club DA07B220B360C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tilde.club; s=mail; t=1677362887; bh=d/Jb/ZYM6YsbWvuZyUZ8Uxm81yEvsmppozkuXCRm9wU=; h=From:To:Subject:Date:From; b=akrLCwLuKpjHpbiZVZIa2GX7CyNlO3Q/ey78T85zSVKCVg0ZXn2QH67mB7eyTOH7+ /AENJkJv7rg4Z4ltlL06eL/xlpOW6R/so2SlPYgCmXP8Dio7J4upX0RlyFZz52omRQ NK3fY8Alc3oU6tpOLrRr+yPcJGA0eSr+TNMlv33w= From: Ulf Herrman User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.2 (gnu/linux) Date: Sat, 25 Feb 2023 16:08:01 -0600 Message-ID: <87cz5x1jr2.fsf@tilde.club> MIME-Version: 1.0 Content-Type: multipart/signed; boundary="==-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" Received-SPF: pass client-ip=2607:5300:204:4340::114; envelope-from=striness@tilde.club; helo=tilde.club X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Sun, 26 Feb 2023 03:31:18 -0500 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-Mailman-Approved-At: Sun, 26 Feb 2023 08:48:46 -0500 X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: X-Migadu-Queue-Id: 20801D8A7 X-Spam-Score: -4.99 X-Migadu-Spam-Score: -4.99 X-Migadu-Scanner: scn0.migadu.com List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: guix-patches-bounces+larch=yhetil.org@gnu.org X-Migadu-Flow: FLOW_IN X-Migadu-Country: US X-TUID: zySXPHcJOX3S --==-=-= Content-Type: multipart/mixed; boundary="=-=-=" --=-=-= Content-Type: text/plain These patches fill out shepherd's procedures for running processes to completion. They add a replacement for 'system' to complement the existing replacement for 'system*', and add a 'fork+exec+wait-process' procedure so that the flexibility of that family of procedures is available for this use case as well. It also improves error handling in the event that an exception occurs while spawning a process in the process monitor, which would normally kill that essential fiber. Note: I previously tried to send this to guix-devel, but it didn't seem to make it (I didn't see it in the archives after half a day), and after some consideration I recalled that guix-patches exists. Is this the right place for shepherd patches? --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-service-Propagate-exceptions-while-spawning-in-proce.patch Content-Transfer-Encoding: quoted-printable From=2064370a98dfc17f0531de7397a38362c03a1d89bc Mon Sep 17 00:00:00 2001 From: ulfvonbelow Date: Sat, 25 Feb 2023 00:42:41 -0600 Subject: [PATCH 1/3] service: Propagate exceptions while spawning in process monitor. * modules/shepherd/service.scm (unboxed-errors): new procedure. (boxed-errors): new syntax. (process-monitor): use it to propagate exceptions from fork+exec-command = via reply channel. (spawn-via-monitor): new procedure. (spawn-command): use it. =2D-- modules/shepherd/service.scm | 47 ++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/modules/shepherd/service.scm b/modules/shepherd/service.scm index fd2ef1b..196ee44 100644 =2D-- a/modules/shepherd/service.scm +++ b/modules/shepherd/service.scm @@ -1825,6 +1825,24 @@ otherwise by updating its state." ;; loop so we don't miss any terminated child process. (loop))))) =20 +(define-syntax-rule (boxed-errors exps ...) + (catch #t + (lambda () + (call-with-values + (lambda () + exps ...) + (lambda results + (list 'success results)))) + (lambda args + (list 'exception args)))) + +(define unboxed-errors + (match-lambda + (('success vals) + (apply values vals)) + (('exception args) + (apply throw args)))) + (define (process-monitor channel) "Run a process monitor that handles requests received over @var{channel}= ." (let loop ((waiters vlist-null)) @@ -1860,11 +1878,17 @@ otherwise by updating its state." waiters))) =20 (('spawn command reply) =2D ;; Spawn COMMAND; send its exit status to REPLY when it terminate= s. =2D ;; This operation is atomic: the WAITERS table is updated before =2D ;; termination of PID can possibly be handled. =2D (let ((pid (fork+exec-command command))) =2D (loop (vhash-consv pid reply waiters)))) + ;; Spawn COMMAND; send the spawn result (pid or exception) to REPLY; + ;; send its exit status to REPLY when it terminates. This operatio= n is + ;; atomic: the WAITERS table is updated before termination of PID c= an + ;; possibly be handled. + (let ((result (boxed-errors (fork+exec-command command)))) + (put-message reply result) + (match result + (('exception . _) + (loop waiters)) + (('success (pid)) + (loop (vhash-consv pid reply waiters)))))) =20 (('await pid reply) ;; Await the termination of PID and send its status on REPLY. @@ -1900,14 +1924,17 @@ context. The process monitoring fiber is responsib= le for handling @code{SIGCHLD} and generally dealing with process creation and termination= ." (call-with-process-monitor (lambda () exp ...))) =20 +(define (spawn-via-monitor command) + (let ((reply (make-channel))) + (put-message (current-process-monitor) + `(spawn ,command ,reply)) + (unboxed-errors (get-message reply)) + (get-message reply))) + (define (spawn-command program . arguments) "Like 'system*' but do not block while waiting for PROGRAM to terminate." (if (current-process-monitor) =2D (let ((reply (make-channel))) =2D (put-message (current-process-monitor) =2D `(spawn ,(cons program arguments) =2D ,reply)) =2D (get-message reply)) + (spawn-via-monitor (cons program arguments)) (apply system* program arguments))) =20 (define default-process-termination-grace-period =2D-=20 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-service-accept-fork-exec-command-argument-list-in-mo.patch Content-Transfer-Encoding: quoted-printable From=2051ee63ace6f3f52eb196c990664cc6b9af3d3683 Mon Sep 17 00:00:00 2001 From: ulfvonbelow Date: Sat, 25 Feb 2023 00:46:27 -0600 Subject: [PATCH 2/3] service: accept fork+exec-command argument list in monitor. Sometimes it's necessary to run startup / shutdown programs as a certain us= er, in a certain directory, with certain environment variables, etc. Shepherd currently provides a replacement for system* that won't race against the child process auto-reaper, but this lacks the flexibility Shepherd users are used to. * modules/shepherd/service.scm (process-monitor): treat command instead as argument list to fork+exec-command. (spawn-via-monitor): update to new convention. (fork+exec+wait-command): new procedure. =2D-- modules/shepherd/service.scm | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/modules/shepherd/service.scm b/modules/shepherd/service.scm index 196ee44..a36e486 100644 =2D-- a/modules/shepherd/service.scm +++ b/modules/shepherd/service.scm @@ -94,6 +94,7 @@ default-process-termination-grace-period exec-command fork+exec-command + fork+exec+wait-command default-pid-file-timeout read-pid-file make-system-constructor @@ -1877,12 +1878,12 @@ otherwise by updating its state." vlist-null waiters))) =20 =2D (('spawn command reply) + (('spawn args reply) ;; Spawn COMMAND; send the spawn result (pid or exception) to REPLY; ;; send its exit status to REPLY when it terminates. This operatio= n is ;; atomic: the WAITERS table is updated before termination of PID c= an ;; possibly be handled. =2D (let ((result (boxed-errors (fork+exec-command command)))) + (let ((result (boxed-errors (apply fork+exec-command args)))) (put-message reply result) (match result (('exception . _) @@ -1924,19 +1925,26 @@ context. The process monitoring fiber is responsib= le for handling @code{SIGCHLD} and generally dealing with process creation and termination= ." (call-with-process-monitor (lambda () exp ...))) =20 =2D(define (spawn-via-monitor command) +(define (spawn-via-monitor arguments) (let ((reply (make-channel))) (put-message (current-process-monitor) =2D `(spawn ,command ,reply)) + `(spawn ,arguments ,reply)) (unboxed-errors (get-message reply)) (get-message reply))) =20 (define (spawn-command program . arguments) "Like 'system*' but do not block while waiting for PROGRAM to terminate." (if (current-process-monitor) =2D (spawn-via-monitor (cons program arguments)) + (spawn-via-monitor (list (cons program arguments))) (apply system* program arguments))) =20 +(define (fork+exec+wait-command command . arguments) + "Like 'fork+exec' but also wait for PROGRAM to terminate, giving its exit +status." + (if (current-process-monitor) + (spawn-via-monitor (cons command arguments)) + (waitpid (apply fork+exec-command command arguments)))) + (define default-process-termination-grace-period ;; Default process termination "grace period" before we send SIGKILL. (make-parameter 5)) =2D-=20 2.38.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-service-add-spawn-shell-command-replacement-for-syst.patch Content-Transfer-Encoding: quoted-printable From=20177592ee9d4b7fc6dcc80e545e8ad615a1d6786c Mon Sep 17 00:00:00 2001 From: ulfvonbelow Date: Sat, 25 Feb 2023 00:56:57 -0600 Subject: [PATCH 3/3] service: add spawn-shell-command replacement for `system'. We already have a replacement for `system*' that avoids racing, but not for `system'. * configure.ac (SHELL): new substitution variable. * modules/shepherd/system.scm.in (%shell-filename): new variable. * modules/shepherd/service.scm (spawn-shell-command, real-system): new procedures. * modules/shepherd.scm (main): replace `system' with `spawn-shell-command'. =2D-- configure.ac | 1 + modules/shepherd.scm | 7 +++++-- modules/shepherd/service.scm | 13 +++++++++++++ modules/shepherd/system.scm.in | 5 ++++- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 6f681dc..19c177a 100644 =2D-- a/configure.ac +++ b/configure.ac @@ -32,6 +32,7 @@ guilemoduledir=3D"${datarootdir}/guile/site/$GUILE_EFFECT= IVE_VERSION" guileobjectdir=3D"${libdir}/guile/$GUILE_EFFECTIVE_VERSION/site-ccache" AC_SUBST([guilemoduledir]) AC_SUBST([guileobjectdir]) +AC_SUBST([SHELL]) =20 dnl Check for extra dependencies. GUILE_MODULE_AVAILABLE([have_fibers], [(fibers)]) diff --git a/modules/shepherd.scm b/modules/shepherd.scm index cce0507..1f6342e 100644 =2D-- a/modules/shepherd.scm +++ b/modules/shepherd.scm @@ -420,8 +420,10 @@ already ~a threads running, disabling 'signalfd' suppo= rt") =20 ;; Replace the default 'system*' binding with one that ;; cooperates instead of blocking on 'waitpid'. =2D (let ((real-system* system*)) + (let ((real-system* system*) + (real-system system)) (set! system* spawn-command) + (set! system spawn-shell-command) =20 ;; Restore 'system*' after fork. (set! primitive-fork @@ -430,7 +432,8 @@ already ~a threads running, disabling 'signalfd' suppor= t") (let ((result (real-fork))) (when (zero? result) (set! primitive-fork real-fork) =2D (set! system* real-system*)) + (set! system* real-system*) + (set! system real-system)) result))))) =20 (run-daemon #:socket-file socket-file diff --git a/modules/shepherd/service.scm b/modules/shepherd/service.scm index a36e486..f8df3a9 100644 =2D-- a/modules/shepherd/service.scm +++ b/modules/shepherd/service.scm @@ -81,6 +81,7 @@ handle-SIGCHLD with-process-monitor spawn-command + spawn-shell-command %precious-signals register-services provided-by @@ -1938,6 +1939,18 @@ context. The process monitoring fiber is responsibl= e for handling (spawn-via-monitor (list (cons program arguments))) (apply system* program arguments))) =20 +(define real-system system) + +(define* (spawn-shell-command #:optional command) + "Like 'system' but do not block while waiting for COMMAND to terminate." + (if (current-process-monitor) + (if command + (spawn-command %shell-filename "-c" command) + #t) + (if command + (real-system command) + (real-system)))) + (define (fork+exec+wait-command command . arguments) "Like 'fork+exec' but also wait for PROGRAM to terminate, giving its exit status." diff --git a/modules/shepherd/system.scm.in b/modules/shepherd/system.scm.in index 29357aa..4646e81 100644 =2D-- a/modules/shepherd/system.scm.in +++ b/modules/shepherd/system.scm.in @@ -41,7 +41,8 @@ unblock-signals set-blocked-signals with-blocked-signals =2D without-automatic-finalization)) + without-automatic-finalization + %shell-filename)) =20 ;; The constants. (define RB_AUTOBOOT @RB_AUTOBOOT@) @@ -328,3 +329,5 @@ Turning finalization off shuts down the finalization th= read as a side effect." exp ...) (lambda () (%set-automatic-finalization-enabled?! enabled?))))) + +(define %shell-filename "@SHELL@") =2D-=20 2.38.1 --=-=-=-- --==-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQHIBAEBCAAyFiEEn6BUn0yca1D9JsMa1lV76sJM9mgFAmP6hsEUHHN0cmluZXNz QHRpbGRlLmNsdWIACgkQ1lV76sJM9mjtsQwAiDIHp3DBdkOB1nWU5iU9WgVZHnvg NpMxQhI0trcEluiMYltryxtyv9y4L0x1O2hKto+KbDdvS6l6NHF6IfGX4aV7hfq+ PJBntv3KQjK5NTPN96+D179aLeb8iCY//rh2/qjdLALtqxGHM8kcf83se1SQ3mr/ UtChBtz5vNQKJx3s7PSOAhGvLupNJ6rWdgKdm+BwbsWFZ/7lrb3+gNLXPMtQlEzC 3jgo7TKVEMhLLVuoYRsvCx79a5l5kayaA516B+xuKLGY3/OZIU/VT5Ts5tzAlhDU VjTI4Wg1aKyZJDehuFwbYuoPWwxnODOhZ05fZKlKDqMhBRWsFnsPR355dU2uOY4I ku4HkuvpQBHj1TPp7JqxRZ+cwU76REjoEjqJPNfKriIZj97/+OrPz/hdX8GLwPRY Uwc/IZyoa5HAYKKpPyeBaZAmEJ8hxrA576nEIetuXmfFvSeheuSYw+5Qe6NujX/M wtuZEi1t3SsHHjbCwNf9LQXPehBRVmRwtC0j =FusD -----END PGP SIGNATURE----- --==-=-=--