Ninja
jobserver-posix.cc
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#include <assert.h>
16#include <errno.h>
17#include <fcntl.h>
18#include <string.h>
19#include <sys/stat.h>
20#include <unistd.h>
21
22#include <string>
23
24#include "jobserver.h"
25#include "util.h"
26
27namespace {
28
29// Return true if |fd| is a fifo or pipe descriptor.
30bool IsFifoDescriptor(int fd) {
31 struct stat info;
32 int ret = ::fstat(fd, &info);
33 return (ret == 0) && ((info.st_mode & S_IFMT) == S_IFIFO);
34}
35
36// Implementation of Jobserver::Client for Posix systems
37class PosixJobserverClient : public Jobserver::Client {
38 public:
39 virtual ~PosixJobserverClient() {
40 if (write_fd_ >= 0)
41 ::close(write_fd_);
42 if (read_fd_ >= 0)
43 ::close(read_fd_);
44 }
45
46 Jobserver::Slot TryAcquire() override {
47 if (has_implicit_slot_) {
48 has_implicit_slot_ = false;
50 }
51 uint8_t slot_char = '\0';
52 ssize_t ret;
53 do {
54 ret = ::read(read_fd_, &slot_char, 1);
55 } while (ret < 0 && errno == EINTR);
56 if (ret == 1) {
57 return Jobserver::Slot::CreateExplicit(slot_char);
58 }
59 return Jobserver::Slot();
60 }
61
62 void Release(Jobserver::Slot slot) override {
63 if (!slot.IsValid())
64 return;
65
66 if (slot.IsImplicit()) {
67 assert(!has_implicit_slot_ && "Implicit slot cannot be released twice!");
68 has_implicit_slot_ = true;
69 return;
70 }
71
72 uint8_t slot_char = slot.GetExplicitValue();
73 ssize_t ret;
74 do {
75 ret = ::write(write_fd_, &slot_char, 1);
76 } while (ret < 0 && errno == EINTR);
77 (void)ret; // Nothing can be done in case of error here.
78 }
79
80 // Initialize with FIFO file path.
81 bool InitWithFifo(const std::string& fifo_path, std::string* error) {
82 if (fifo_path.empty()) {
83 *error = "Empty fifo path";
84 return false;
85 }
86 read_fd_ = ::open(fifo_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC);
87 if (read_fd_ < 0) {
88 *error =
89 std::string("Error opening fifo for reading: ") + strerror(errno);
90 return false;
91 }
92 if (!IsFifoDescriptor(read_fd_)) {
93 *error = "Not a fifo path: " + fifo_path;
94 // Let destructor close read_fd_.
95 return false;
96 }
97 write_fd_ = ::open(fifo_path.c_str(), O_WRONLY | O_NONBLOCK | O_CLOEXEC);
98 if (write_fd_ < 0) {
99 *error =
100 std::string("Error opening fifo for writing: ") + strerror(errno);
101 // Let destructor close read_fd_
102 return false;
103 }
104 return true;
105 }
106
107 private:
108 // Set to true if the implicit slot has not been acquired yet.
109 bool has_implicit_slot_ = true;
110
111 // read and write descriptors.
112 int read_fd_ = -1;
113 int write_fd_ = -1;
114};
115
116} // namespace
117
118// static
119std::unique_ptr<Jobserver::Client> Jobserver::Client::Create(
120 const Jobserver::Config& config, std::string* error) {
121 bool success = false;
122 auto client = std::unique_ptr<PosixJobserverClient>(new PosixJobserverClient);
124 success = client->InitWithFifo(config.path, error);
125 } else {
126 *error = "Unsupported jobserver mode";
127 }
128 if (!success)
129 client.reset();
130 return client;
131}
A Jobserver::Client instance models a client of an external GNU jobserver pool, which can be implemen...
Definition jobserver.h:189
static std::unique_ptr< Client > Create(const Config &, std::string *error)
Create a new Client instance from a given configuration.
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
Mode mode
Implementation mode for the pool.
Definition jobserver.h:142
uint8_t GetExplicitValue() const
Return value of an explicit slot.
Definition jobserver.cc:64
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
bool IsImplicit() const
Return true if this instance represents an implicit job slot.
Definition jobserver.h:79
bool IsValid() const
Return true if this instance is valid, i.e.
Definition jobserver.h:76