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 ///
28 struct 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 };
A Jobserver::Client instance models a client of an external GNU jobserver pool, which can be implemen...
Definition: jobserver.h:189
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=(const Slot &)=delete
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(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 & operator=(Slot &&o) noexcept
Definition: jobserver.h:62
Slot(int16_t value)
Definition: jobserver.h:97
int16_t value_
Definition: jobserver.h:101
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