forked from ninja-build/ninja
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add GNU make jobserver client support
- add new TokenPool interface - GNU make implementation for TokenPool parses and verifies the magic information from the MAKEFLAGS environment variable - RealCommandRunner tries to acquire TokenPool * if no token pool is available then there is no change in behaviour - When a token pool is available then RealCommandRunner behaviour changes as follows * CanRunMore() only returns true if TokenPool::Acquire() returns true * StartCommand() calls TokenPool::Reserve() * WaitForCommand() calls TokenPool::Release() Documentation for GNU make jobserver http://make.mad-scientist.net/papers/jobserver-implementation/ Fixes ninja-build#1139
- Loading branch information
Stefan Becker
committed
Apr 27, 2016
1 parent
aa79fbe
commit e6d3d5b
Showing
5 changed files
with
226 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// Copyright 2016 Google Inc. All Rights Reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include "tokenpool.h" | ||
|
||
#include <fcntl.h> | ||
#include <poll.h> | ||
#include <unistd.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
|
||
// TokenPool implementation for GNU make jobserver | ||
// (http://make.mad-scientist.net/papers/jobserver-implementation/) | ||
struct GNUmakeTokenPool : public TokenPool { | ||
GNUmakeTokenPool(); | ||
virtual ~GNUmakeTokenPool(); | ||
|
||
virtual bool Acquire(); | ||
virtual void Reserve(); | ||
virtual void Release(); | ||
virtual void Clear(); | ||
|
||
bool Setup(); | ||
|
||
private: | ||
int available_; | ||
int used_; | ||
|
||
#ifdef _WIN32 | ||
// @TODO | ||
#else | ||
int rfd_; | ||
int wfd_; | ||
|
||
bool CheckFd(int fd); | ||
#endif | ||
|
||
void Return(); | ||
}; | ||
|
||
// every instance owns an implicit token -> available_ == 1 | ||
GNUmakeTokenPool::GNUmakeTokenPool() : available_(1), used_(0), | ||
rfd_(-1), wfd_(-1) { | ||
} | ||
|
||
GNUmakeTokenPool::~GNUmakeTokenPool() { | ||
Clear(); | ||
} | ||
|
||
bool GNUmakeTokenPool::CheckFd(int fd) { | ||
if (fd < 0) | ||
return false; | ||
int ret = fcntl(fd, F_GETFD); | ||
if (ret < 0) | ||
return false; | ||
return true; | ||
} | ||
|
||
bool GNUmakeTokenPool::Setup() { | ||
const char *value = getenv("MAKEFLAGS"); | ||
if (value) { | ||
const char *jobserver = strstr(value, "--jobserver-fds="); | ||
if (jobserver) { | ||
int rfd = -1; | ||
int wfd = -1; | ||
if ((sscanf(jobserver, "--jobserver-fds=%d,%d", &rfd, &wfd) == 2) && | ||
CheckFd(rfd) && | ||
CheckFd(wfd)) { | ||
rfd_ = rfd; | ||
wfd_ = wfd; | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
bool GNUmakeTokenPool::Acquire() { | ||
if (available_ > 0) | ||
return true; | ||
|
||
#ifdef USE_PPOLL | ||
pollfd pollfds[] = {{rfd_, POLLIN, 0}}; | ||
int ret = poll(pollfds, 1, 0); | ||
#else | ||
fd_set set; | ||
struct timeval timeout = { 0, 0 }; | ||
FD_ZERO(&set); | ||
FD_SET(rfd_, &set); | ||
int ret = select(rfd_ + 1, &set, NULL, NULL, &timeout); | ||
#endif | ||
if (ret > 0) { | ||
char buf; | ||
int ret = read(rfd_, &buf, 1); | ||
if (ret > 0) { | ||
available_++; | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
void GNUmakeTokenPool::Reserve() { | ||
available_--; | ||
used_++; | ||
} | ||
|
||
void GNUmakeTokenPool::Return() { | ||
const char buf = '+'; | ||
if (write(wfd_, &buf, 1) > 0) | ||
available_--; | ||
} | ||
|
||
void GNUmakeTokenPool::Release() { | ||
available_++; | ||
used_--; | ||
if (available_ > 1) | ||
Return(); | ||
} | ||
|
||
void GNUmakeTokenPool::Clear() { | ||
while (used_ > 0) | ||
Release(); | ||
while (available_ > 1) | ||
Return(); | ||
} | ||
|
||
struct TokenPool *TokenPool::Get(void) { | ||
GNUmakeTokenPool *tokenpool = new GNUmakeTokenPool; | ||
if (tokenpool->Setup()) | ||
return tokenpool; | ||
else | ||
delete tokenpool; | ||
return NULL; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright 2016 Google Inc. All Rights Reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include "tokenpool.h" | ||
|
||
#include <fcntl.h> | ||
#include <poll.h> | ||
#include <unistd.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
|
||
// No-op TokenPool implementation | ||
struct TokenPool *TokenPool::Get(void) { | ||
return NULL; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Copyright 2016 Google Inc. All Rights Reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// interface to token pool | ||
struct TokenPool { | ||
virtual ~TokenPool() {} | ||
|
||
virtual bool Acquire() = 0; | ||
virtual void Reserve() = 0; | ||
virtual void Release() = 0; | ||
virtual void Clear() = 0; | ||
|
||
// returns NULL if token pool is not available | ||
static struct TokenPool *Get(void); | ||
}; |
It's been a while since I spent time with this code, but my recollection is that
DoWork()
above is the main blocking call that waits for a subprocess to complete.It seems with your change,
DoWork()
ought to also wait for a job token to become available. Otherwise it seems you could get in the situation where more job tokens are becoming available but Ninja is blocked waiting for some long-running subprocess and won't notice that it can now spawn more subprocesses.