1//===- llvm/Support/Jobserver.h - Jobserver Client --------------*- C++ -*-===//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//===----------------------------------------------------------------------===//
9// This file defines a client for the GNU Make jobserver protocol. This allows
10// LLVM tools to coordinate parallel execution with a parent `make` process.
12// The jobserver protocol is a mechanism for GNU Make to share its pool of
13// available "job slots" with the subprocesses it invokes. This is particularly
14// useful for tools that can perform parallel operations themselves (e.g., a
15// multi-threaded linker or compiler). By participating in this protocol, a
16// tool can ensure the total number of concurrent jobs does not exceed the
17// limit specified by the user (e.g., `make -j8`).
22// A child process discovers the jobserver by inspecting the `MAKEFLAGS`
23// environment variable. If a jobserver is active, this variable will
24// contain a `--jobserver-auth=<value>` argument. The format of `<value>`
25// determines how to communicate with the server.
27// 2. The Implicit Slot:
28// Every command invoked by `make` is granted one "implicit" job slot. This
29// means a tool can always perform at least one unit of work without needing
30// to communicate with the jobserver. This implicit slot should NEVER be
31// released back to the jobserver.
33// 3. Acquiring and Releasing Slots:
34// On POSIX systems, the jobserver is implemented as a pipe. The
35// `--jobserver-auth` value specifies either a path to a named pipe
36// (`fifo:PATH`) or a pair of file descriptors (`R,W`). The pipe is
37// pre-loaded with single-character tokens, one for each available job slot.
39// - To acquire an additional slot, a client reads a single-character token
41// - To release a slot, the client must write the *exact same* character
42// token back to the pipe.
44// It is critical that a client releases all acquired slots before it exits,
45// even in cases of error, to avoid deadlocking the build.
48// A multi-threaded linker invoked by `make -j8` wants to use multiple
49// threads. It first checks for the jobserver. It knows it has one implicit
50// slot, so it can use one thread. It then tries to acquire 7 more slots by
51// reading 7 tokens from the jobserver pipe. If it only receives 3 tokens,
52// it knows it can use a total of 1 (implicit) + 3 (acquired) = 4 threads.
53// Before exiting, it must write the 3 tokens it read back to the pipe.
55// For more context, see:
56// - GNU Make manual on job slots:
57// https://www.gnu.org/software/make/manual/html_node/Job-Slots.html
58// - LLVM RFC discussion on jobserver support:
59// https://discourse.llvm.org/t/rfc-adding-gnu-make-jobserver-
60// support-to-llvm-for-coordinated-parallelism/87034
61// - Ninja’s jobserver support PR:
62// https://github.com/ninja-build/ninja/pull/2506
64//===----------------------------------------------------------------------===//
66#ifndef LLVM_SUPPORT_JOBSERVER_H
67#define LLVM_SUPPORT_JOBSERVER_H
75/// A JobSlot represents a single job slot that can be acquired from or released
76/// to a jobserver pool. This class is move-only.
79 /// Default constructor creates an invalid instance.
82 // Move operations are allowed.
84 Other.Value = kInvalidValue;
88 this->Value =
Other.Value;
89 Other.Value = kInvalidValue;
94 // Copy operations are disallowed.
98 /// Returns true if this instance is valid (either implicit or explicit).
99 bool isValid()
const {
return Value >= 0; }
101 /// Returns true if this instance represents the implicit job slot.
105 return JobSlot(
static_cast<int16_t
>(V));
117 JobSlot(int16_t V) : Value(V) {}
119 /// The jobserver pipe carries explicit tokens (bytes 0–255). We reserve two
120 /// sentinels in Value for special cases:
121 /// kInvalidValue (-1): no slot held
122 /// kImplicitValue (INT16_MAX): implicit slot granted at startup (no pipe
125 /// We use int16_t so Value can store 0–255 explicit tokens and
126 /// sentinels without overflow, enforces fixed 16-bit width, and avoids
127 /// unsigned/signed mix-ups.
128 static constexpr int16_t kInvalidValue = -1;
129 static constexpr int16_t kImplicitValue = INT16_MAX;
130 int16_t
Value = kInvalidValue;
133/// The public interface for a jobserver client.
134/// This client is a lazy-initialized singleton that is created on first use.
139 /// Tries to acquire a job slot from the pool. On failure (e.g., if the pool
140 /// is empty), this returns an invalid JobSlot instance. The first successful
141 /// call will always return the implicit slot.
144 /// Releases a job slot back to the pool.
147 /// Returns the number of job slots available, as determined on first use.
148 /// This value is cached. Returns 0 if no jobserver is active.
151 /// Returns the singleton instance of the JobserverClient.
152 /// The instance is created on the first call to this function.
153 /// Returns a nullptr if no jobserver is configured or an error occurs.
156 /// Resets the singleton instance. For testing purposes only.
160}
// end namespace llvm
162#endif // LLVM_SUPPORT_JOBSERVER_H
A JobSlot represents a single job slot that can be acquired from or released to a jobserver pool.
static JobSlot createExplicit(uint8_t V)
JobSlot()=default
Default constructor creates an invalid instance.
JobSlot & operator=(const JobSlot &)=delete
uint8_t getExplicitValue() const
JobSlot(JobSlot &&Other) noexcept
bool isImplicit() const
Returns true if this instance represents the implicit job slot.
JobSlot & operator=(JobSlot &&Other) noexcept
bool isValid() const
Returns true if this instance is valid (either implicit or explicit).
friend class JobserverClient
friend class JobserverClientImpl
static JobSlot createImplicit()
JobSlot(const JobSlot &)=delete
The public interface for a jobserver client.
virtual JobSlot tryAcquire()=0
Tries to acquire a job slot from the pool.
virtual void release(JobSlot Slot)=0
Releases a job slot back to the pool.
static JobserverClient * getInstance()
Returns the singleton instance of the JobserverClient.
static void resetForTesting()
Resets the singleton instance. For testing purposes only.
virtual ~JobserverClient()
virtual unsigned getNumJobs() const =0
Returns the number of job slots available, as determined on first use.
LLVM Value Representation.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value