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__":