Ninja
jobserver.h
Go to the documentation of this file.
1// Copyright 2024 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <stdint.h>
18
19#include <memory>
20#include <string>
21#include <utility>
22
23/// Jobserver provides types related to managing a pool of "job slots"
24/// using the GNU Make jobserver ptocol described at:
25///
26/// https://www.gnu.org/software/make/manual/html_node/Job-Slots.html
27///
28struct Jobserver {
29 /// A Jobserver::Slot models a single job slot that can be acquired from.
30 /// or released to a jobserver pool. This class is move-only, and can
31 /// wrap three types of values:
32 ///
33 /// - An "invalid" value (the default), used to indicate errors, e.g.
34 /// that no slot could be acquired from the pool.
35 ///
36 /// - The "implicit" value, used to model the job slot that is implicitly
37 /// assigned to a jobserver client by the parent process that spawned
38 /// it.
39 ///
40 /// - The "explicit" values, which correspond to an actual byte read from
41 /// the slot pool's pipe (for Posix), or a semaphore decrement operation
42 /// (for Windows).
43 ///
44 /// Use IsValid(), IsImplicit(), HasValue() to test for categories.
45 ///
46 /// TECHNICAL NOTE: This design complies with the requirements laid out
47 /// on https://www.gnu.org/software/make/manual/html_node/POSIX-Jobserver.html
48 /// which requires clients to write back the exact token values they
49 /// received from a Posix pipe.
50 ///
51 /// Note that *currently* all pool implementations write the same token
52 /// values to the pipe ('+' for GNU Make, and '|' for the Rust jobserver),
53 /// and do not care about the values written back by clients.
54 ///
55 struct Slot {
56 /// Default constructor creates invalid instance.
57 Slot() = default;
58
59 /// Move operations are allowed.
60 Slot(Slot&& o) noexcept : value_(o.value_) { o.value_ = -1; }
61
62 Slot& operator=(Slot&& o) noexcept {
63 if (this != &o) {
64 this->value_ = o.value_;
65 o.value_ = -1;
66 }
67 return *this;
68 }
69
70 /// Copy operations are disallowed.
71 Slot(const Slot&) = delete;
72 Slot& operator=(const Slot&) = delete;
73
74 /// Return true if this instance is valid, i.e. that it is either
75 /// implicit or explicit job slot.
76 bool IsValid() const { return value_ >= 0; }
77
78 /// Return true if this instance represents an implicit job slot.
79 bool IsImplicit() const { return value_ == kImplicitValue; }
80
81 /// Return true if this instance represents an explicit job slot
82 bool IsExplicit() const { return IsValid() && !IsImplicit(); }
83
84 /// Return value of an explicit slot. It is a runtime error to call
85 /// this from an invalid instance.
86 uint8_t GetExplicitValue() const;
87
88 /// Create instance for explicit byte value.
89 static Slot CreateExplicit(uint8_t value) {
90 return Slot(static_cast<int16_t>(value));
91 }
92
93 /// Create instance for the implicit value.
94 static Slot CreateImplicit() { return Slot(kImplicitValue); }
95
96 private:
97 Slot(int16_t value) : value_(value) {}
98
99 static constexpr int16_t kImplicitValue = 256;
100
102 };
103
104 /// A Jobserver::Config models how to access or implement a GNU jobserver
105 /// implementation.
106 struct Config {
107 /// Different implementation modes for the slot pool.
108 ///
109 /// kModeNone means there is no pool.
110 ///
111 /// kModePipe means that `--jobserver-auth=R,W` is used to
112 /// pass a pair of file descriptors to client processes. This also
113 /// matches `--jobserver-fds=R,W` which is an old undocumented
114 /// variant of the same scheme. This mode is not supported by
115 /// Ninja, but recognized by the parser.
116 ///
117 /// kModePosixFifo means that `--jobserver-auth=fifo:PATH` is used to
118 /// pass the path of a Posix FIFO to client processes. This is not
119 /// supported on Windows. Implemented by GNU Make 4.4 and above
120 /// when `--jobserver-style=fifo` is used.
121 ///
122 /// kModeWin32Semaphore means that `--jobserver-auth=SEMAPHORE_NAME` is
123 /// used to pass the name of a Win32 semaphore to client processes.
124 /// This is not supported on Posix.
125 ///
126 /// kModeDefault is the default mode to enable on the current platform.
127 /// This is an alias for kModeWin32Semaphore on Windows ,and
128 /// kModePosixFifo on Posix.
129 enum Mode {
134#ifdef _WIN32
136#else // _WIN32
138#endif // _WIN32
139 };
140
141 /// Implementation mode for the pool.
143
144 /// For kModeFifo, this is the path to the Unix FIFO to use.
145 /// For kModeSemaphore, this is the name of the Win32 semaphore to use.
146 std::string path;
147
148 /// Return true if this instance matches an active implementation mode.
149 /// This does not try to validate configuration parameters though.
150 bool HasMode() { return mode != kModeNone; }
151 };
152
153 /// Parse the value of a MAKEFLAGS environment variable. On success return
154 /// true and set |*config|. On failure, return false and set |*error| to
155 /// explain what's wrong. If |makeflags_env| is nullptr or an empty string,
156 /// this returns success and sets |config->mode| to Config::kModeNone.
157 static bool ParseMakeFlagsValue(const char* makeflags_env, Config* config,
158 std::string* error);
159
160 /// A variant of ParseMakeFlagsValue() that will return an error if the parsed
161 /// result is not compatible with the native system. I.e.:
162 ///
163 /// --jobserver-auth=R,W is not supported on any system (but recognized to
164 /// provide a relevant error message to the user).
165 ///
166 /// --jobserver-auth=NAME onlw works on Windows.
167 ///
168 /// --jobserver-auth=fifo:PATH only works on Posix.
169 ///
170 static bool ParseNativeMakeFlagsValue(const char* makeflags_env,
171 Config* config, std::string* error);
172
173 /// A Jobserver::Client instance models a client of an external GNU jobserver
174 /// pool, which can be implemented as a Unix FIFO, or a Windows named
175 /// semaphore. Usage is the following:
176 ///
177 /// - Call Jobserver::Client::Create(), passing a Config value as argument,
178 /// (e.g. one initialized with ParseNativeMakeFlagsValue()) to create
179 /// a new instance.
180 ///
181 /// - Call TryAcquire() to try to acquire a job slot from the pool.
182 /// If the result is not an invalid slot, store it until the
183 /// corresponding command completes, then call Release() to send it
184 /// back to the pool.
185 ///
186 /// - It is important that all acquired slots are released to the pool,
187 /// even if Ninja terminates early (e.g. due to a build command failing).
188 ///
189 class Client {
190 public:
191 virtual ~Client() {}
192
193 /// Try to acquire a slot from the pool. On failure, i.e. if no slot
194 /// can be acquired, this returns an invalid Token instance.
195 ///
196 /// Note that this will always return the implicit slot value the first
197 /// time this is called, without reading anything from the pool, as
198 /// specified by the protocol. This implicit value *must* be released
199 /// just like any other one. In general, users of this class should not
200 /// care about this detail, except unit-tests.
201 virtual Slot TryAcquire() { return Slot(); }
202
203 /// Release a slot to the pool. Does nothing if slot is invalid,
204 /// or if writing to the pool fails (and if this is not the implicit slot).
205 /// If the pool is destroyed before Ninja, then only the implicit slot
206 /// can be acquired in the next calls (if it was released). This simply
207 /// enforces serialization of all commands, instead of blocking.
208 virtual void Release(Slot slot) {}
209
210 /// Create a new Client instance from a given configuration. On failure,
211 /// this returns null after setting |*error|. Note that it is an error to
212 /// call this function with |config.HasMode() == false|.
213 static std::unique_ptr<Client> Create(const Config&, std::string* error);
214
215 protected:
216 Client() = default;
217 };
218};
virtual Slot TryAcquire()
Try to acquire a slot from the pool.
Definition jobserver.h:201
virtual ~Client()
Definition jobserver.h:191
static std::unique_ptr< Client > Create(const Config &, std::string *error)
Create a new Client instance from a given configuration.
virtual void Release(Slot slot)
Release a slot to the pool.
Definition jobserver.h:208
A Jobserver::Config models how to access or implement a GNU jobserver implementation.
Definition jobserver.h:106
std::string path
For kModeFifo, this is the path to the Unix FIFO to use.
Definition jobserver.h:146
bool HasMode()
Return true if this instance matches an active implementation mode.
Definition jobserver.h:150
Mode
Different implementation modes for the slot pool.
Definition jobserver.h:129
Mode mode
Implementation mode for the pool.
Definition jobserver.h:142
A Jobserver::Slot models a single job slot that can be acquired from.
Definition jobserver.h:55
uint8_t GetExplicitValue() const
Return value of an explicit slot.
Definition jobserver.cc:64
bool IsExplicit() const
Return true if this instance represents an explicit job slot.
Definition jobserver.h:82
Slot & operator=(Slot &&o) noexcept
Definition jobserver.h:62
Slot()=default
Default constructor creates invalid instance.
static Slot CreateImplicit()
Create instance for the implicit value.
Definition jobserver.h:94
static Slot CreateExplicit(uint8_t value)
Create instance for explicit byte value.
Definition jobserver.h:89
Slot & operator=(const Slot &)=delete
Slot(Slot &&o) noexcept
Move operations are allowed.
Definition jobserver.h:60
bool IsImplicit() const
Return true if this instance represents an implicit job slot.
Definition jobserver.h:79
Slot(const Slot &)=delete
Copy operations are disallowed.
Slot(int16_t value)
Definition jobserver.h:97
static constexpr int16_t kImplicitValue
Definition jobserver.h:99
bool IsValid() const
Return true if this instance is valid, i.e.
Definition jobserver.h:76
Jobserver provides types related to managing a pool of "job slots" using the GNU Make jobserver ptoco...
Definition jobserver.h:28
static bool ParseNativeMakeFlagsValue(const char *makeflags_env, Config *config, std::string *error)
A variant of ParseMakeFlagsValue() that will return an error if the parsed result is not compatible w...
Definition jobserver.cc:186
static bool ParseMakeFlagsValue(const char *makeflags_env, Config *config, std::string *error)
Parse the value of a MAKEFLAGS environment variable.
Definition jobserver.cc:69
signed short int16_t
Definition win32port.h:25