[llvm] [LLVM] Remove the requirement for named pipe in jobserver (PR #169154)

Michał Górny via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 1 10:52:28 PST 2025


https://github.com/mgorny updated https://github.com/llvm/llvm-project/pull/169154

>From cc861d56f5e2688b3492ceaf5489a0c1d7dcaa8a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= <mgorny at gentoo.org>
Date: Sat, 22 Nov 2025 09:02:54 +0100
Subject: [PATCH 1/2] [LLVM] Remove the requirement for named pipe in jobserver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Remove the requirement that the jobserver "fifo" is actually a named
pipe.  Named pipes are essentially stateless, and therefore carry a high
risk of a killed process leaving the server with no tokens left, and no
clear way to reclaim them.  Therefore, multiple jobserver
implementations use FUSE instead:

- [nixos-jobserver](https://github.com/NixOS/nixpkgs/pull/314888) (WIP)
  uses simple file on FUSE

- [steve](https://gitweb.gentoo.org/proj/steve.git) uses a character
  device via CUSE

- [guildmaster](https://codeberg.org/amonakov/guildmaster) uses
  a character device via CUSE

This is compatible with GNU make and Ninja, since they do not check
the file type, and seems to be the only solution that can achieve
state tracking while preserving compatibility.

Signed-off-by: Michał Górny <mgorny at gentoo.org>
---
 llvm/lib/Support/Unix/Jobserver.inc | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/llvm/lib/Support/Unix/Jobserver.inc b/llvm/lib/Support/Unix/Jobserver.inc
index 53bf7f288ca1f..300fb5e55045e 100644
--- a/llvm/lib/Support/Unix/Jobserver.inc
+++ b/llvm/lib/Support/Unix/Jobserver.inc
@@ -19,14 +19,6 @@
 #include <unistd.h>
 
 namespace {
-/// Returns true if the given file descriptor is a FIFO (named pipe).
-bool isFifo(int FD) {
-  struct stat StatBuf;
-  if (::fstat(FD, &StatBuf) != 0)
-    return false;
-  return S_ISFIFO(StatBuf.st_mode);
-}
-
 /// Returns true if the given file descriptors are valid.
 bool areFdsValid(int ReadFD, int WriteFD) {
   if (ReadFD == -1 || WriteFD == -1)
@@ -75,7 +67,7 @@ JobserverClientImpl::JobserverClientImpl(const JobserverConfig &Config) {
   case JobserverConfig::PosixFifo:
     // Open the FIFO for reading. It must be non-blocking and close-on-exec.
     ReadFD = ::open(Config.Path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC);
-    if (ReadFD < 0 || !isFifo(ReadFD)) {
+    if (ReadFD < 0) {
       if (ReadFD >= 0)
         ::close(ReadFD);
       ReadFD = -1;

>From 32e2acbee200c0802affb9a09def8ef1a0631876 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= <mgorny at gentoo.org>
Date: Mon, 1 Dec 2025 19:51:52 +0100
Subject: [PATCH 2/2] Add a test for the non-FIFO scenario
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Michał Górny <mgorny at gentoo.org>
---
 llvm/unittests/Support/JobserverTest.cpp | 35 ++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/llvm/unittests/Support/JobserverTest.cpp b/llvm/unittests/Support/JobserverTest.cpp
index df623463bb309..c36769087aba7 100644
--- a/llvm/unittests/Support/JobserverTest.cpp
+++ b/llvm/unittests/Support/JobserverTest.cpp
@@ -14,6 +14,7 @@
 #include "llvm/Support/Jobserver.h"
 #include "llvm/Config/llvm-config.h"
 #include "llvm/Support/Debug.h"
+#include "llvm/Support/FileUtilities.h"
 #include "llvm/Support/Parallel.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/ThreadPool.h"
@@ -221,6 +222,40 @@ TEST_F(JobserverClientTest, UnixClientFifo) {
   EXPECT_TRUE(S1.isValid());
 }
 
+TEST_F(JobserverClientTest, UnixClientNonFifo) {
+  // This test verifies that non-FIFO jobservers can be used, such as steve
+  // or guildmaster.
+  SmallString<64> F;
+  std::error_code EC =
+      sys::fs::createTemporaryFile("jobserver-test", "nonfifo", F);
+  ASSERT_FALSE(EC);
+  FileRemover Cleanup(F);
+
+  // Intentionally inserted \t in environment string.
+  std::string Makeflags = " \t -j4\t \t--jobserver-auth=fifo:";
+  Makeflags += F.c_str();
+  ScopedEnvironment Env("MAKEFLAGS", Makeflags.c_str());
+
+  JobserverClient *Client = JobserverClient::getInstance();
+  ASSERT_NE(Client, nullptr);
+
+  // Get the implicit token.
+  JobSlot S1 = Client->tryAcquire();
+  EXPECT_TRUE(S1.isValid());
+  EXPECT_TRUE(S1.isImplicit());
+
+  // File is empty, next acquire fails.
+  JobSlot S2 = Client->tryAcquire();
+  EXPECT_FALSE(S2.isValid());
+
+  // Release does not write to the file for the implicit token.
+  Client->release(std::move(S1));
+
+  // Re-acquire the implicit token.
+  S1 = Client->tryAcquire();
+  EXPECT_TRUE(S1.isValid());
+}
+
 #if LLVM_ENABLE_THREADS
 // Unique anchor whose address helps locate the current test binary.
 static int JobserverTestAnchor = 0;



More information about the llvm-commits mailing list