commit:     1c6bf9cc47dca46d7ffe3007c8c3f3b37e45133b
Author:     Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Fri Nov  7 19:26:21 2025 +0000
Commit:     Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Fri Nov  7 19:26:21 2025 +0000
URL:        https://gitweb.gentoo.org/proj/steve.git/commit/?id=1c6bf9cc

Add control FIFO support

Signed-off-by: Michał Górny <mgorny <AT> gentoo.org>

 README.rst | 22 ++++++++++++++++++++++
 steve.py   | 24 ++++++++++++++++++++++--
 2 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/README.rst b/README.rst
index 94ef959..76ae7c7 100644
--- a/README.rst
+++ b/README.rst
@@ -14,3 +14,25 @@ Then for GNU make / ninja invocations, set::
 Make sure that your build processes can access the FIFO.  When using
 with Portage, change the ownership to ``portage:portage`` and add it
 to ``SANDBOX_WRITE`` if necessary.
+
+Normally steve runs until explicitly terminated via ^c or SIGTERM.
+
+
+Control FIFO
+------------
+Optionally, steve can be started with a control/locking FIFO using::
+
+    steve -c ${path_to_control} ${path_to_fifo}
+
+Steve then opens the read end of the pipe and waits for a client (such
+as ``emerge``) to open the write end before actually writing any job
+tokens.  If multiple processes need to use Steve, they should all hold
+the write end open.  Steve reads the FIFO until EOF, then exits
+-- effectively waiting for all locked processes to terminate.
+
+This effectively means that the first process needing steve can start
+a shared instance dynamically, and it will continue running until
+the last process exits.
+
+In the future, the control FIFO may be used to pass explicit commands
+to steve.

diff --git a/steve.py b/steve.py
index abb04c1..44bc4df 100755
--- a/steve.py
+++ b/steve.py
@@ -31,6 +31,12 @@ def main() -> None:
     signal.signal(signal.SIGTERM, exit_sig_handler)
 
     argp = argparse.ArgumentParser()
+    argp.add_argument(
+        "-c",
+        "--control-fifo",
+        type=Path,
+        help="Path for the control/lock FIFO",
+    )
     argp.add_argument(
         "-j",
         "--jobs",
@@ -52,19 +58,33 @@ def main() -> None:
     if args.jobs <= 0:
         argp.error("--jobs must be larger than 0")
 
+    if args.control_fifo is not None:
+        os.mkfifo(args.control_fifo)
+
     os.mkfifo(args.path)
     try:
         _ = os.open(args.path, os.O_RDONLY | os.O_NONBLOCK)
         write_fd = os.open(args.path, os.O_WRONLY)
+        if args.control_fifo is not None:
+            print(f"Waiting for clients to open {args.control_fifo}")
+            control_file = args.control_fifo.open("rb")
 
         os.write(write_fd, b"." * args.jobs)
 
         print(f"Started for {args.jobs} jobs")
         print(f'MAKEFLAGS="--jobserver-auth=fifo:{args.path}"')
-        while True:
-            signal.pause()
+
+        if args.control_fifo is not None:
+            print("Running until the last client closes the control FIFO")
+            control_file.read()
+            print("Control FIFO released, exiting")
+        else:
+            while True:
+                signal.pause()
     finally:
         args.path.unlink()
+        if args.control_fifo is not None:
+            args.control_fifo.unlink()
 
 
 if __name__ == "__main__":

Reply via email to