parent
7a3e7d0e61
commit
ceeedb58d2
2 changed files with 29 additions and 22 deletions
|
@ -17,9 +17,9 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -187,6 +187,9 @@ bool CompareGoalPtrs::operator() (const GoalPtr & a, const GoalPtr & b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::chrono::time_point<std::chrono::steady_clock> steady_time_point;
|
||||||
|
|
||||||
|
|
||||||
/* A mapping used to remember for each child process to what goal it
|
/* A mapping used to remember for each child process to what goal it
|
||||||
belongs, and file descriptors for receiving log data and output
|
belongs, and file descriptors for receiving log data and output
|
||||||
path creation commands. */
|
path creation commands. */
|
||||||
|
@ -197,8 +200,8 @@ struct Child
|
||||||
set<int> fds;
|
set<int> fds;
|
||||||
bool respectTimeouts;
|
bool respectTimeouts;
|
||||||
bool inBuildSlot;
|
bool inBuildSlot;
|
||||||
time_t lastOutput; /* time we last got output on stdout/stderr */
|
steady_time_point lastOutput; /* time we last got output on stdout/stderr */
|
||||||
time_t timeStarted;
|
steady_time_point timeStarted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -238,7 +241,7 @@ private:
|
||||||
WeakGoals waitingForAWhile;
|
WeakGoals waitingForAWhile;
|
||||||
|
|
||||||
/* Last time the goals in `waitingForAWhile' where woken up. */
|
/* Last time the goals in `waitingForAWhile' where woken up. */
|
||||||
time_t lastWokenUp;
|
steady_time_point lastWokenUp;
|
||||||
|
|
||||||
/* Cache for pathContentsGood(). */
|
/* Cache for pathContentsGood(). */
|
||||||
std::map<Path, bool> pathContentsGoodCache;
|
std::map<Path, bool> pathContentsGoodCache;
|
||||||
|
@ -3390,7 +3393,7 @@ Worker::Worker(LocalStore & store)
|
||||||
if (working) abort();
|
if (working) abort();
|
||||||
working = true;
|
working = true;
|
||||||
nrLocalBuilds = 0;
|
nrLocalBuilds = 0;
|
||||||
lastWokenUp = 0;
|
lastWokenUp = steady_time_point::min();
|
||||||
permanentFailure = false;
|
permanentFailure = false;
|
||||||
timedOut = false;
|
timedOut = false;
|
||||||
}
|
}
|
||||||
|
@ -3499,7 +3502,7 @@ void Worker::childStarted(GoalPtr goal, const set<int> & fds,
|
||||||
child.goal = goal;
|
child.goal = goal;
|
||||||
child.goal2 = goal.get();
|
child.goal2 = goal.get();
|
||||||
child.fds = fds;
|
child.fds = fds;
|
||||||
child.timeStarted = child.lastOutput = time(0);
|
child.timeStarted = child.lastOutput = steady_time_point::clock::now();
|
||||||
child.inBuildSlot = inBuildSlot;
|
child.inBuildSlot = inBuildSlot;
|
||||||
child.respectTimeouts = respectTimeouts;
|
child.respectTimeouts = respectTimeouts;
|
||||||
children.emplace_back(child);
|
children.emplace_back(child);
|
||||||
|
@ -3618,35 +3621,38 @@ void Worker::waitForInput()
|
||||||
bool useTimeout = false;
|
bool useTimeout = false;
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
timeout.tv_usec = 0;
|
timeout.tv_usec = 0;
|
||||||
time_t before = time(0);
|
auto before = steady_time_point::clock::now();
|
||||||
|
|
||||||
/* If we're monitoring for silence on stdout/stderr, or if there
|
/* If we're monitoring for silence on stdout/stderr, or if there
|
||||||
is a build timeout, then wait for input until the first
|
is a build timeout, then wait for input until the first
|
||||||
deadline for any child. */
|
deadline for any child. */
|
||||||
assert(sizeof(time_t) >= sizeof(long));
|
auto nearest = steady_time_point::max(); // nearest deadline
|
||||||
time_t nearest = LONG_MAX; // nearest deadline
|
|
||||||
for (auto & i : children) {
|
for (auto & i : children) {
|
||||||
if (!i.respectTimeouts) continue;
|
if (!i.respectTimeouts) continue;
|
||||||
if (settings.maxSilentTime != 0)
|
if (settings.maxSilentTime != 0)
|
||||||
nearest = std::min(nearest, i.lastOutput + settings.maxSilentTime);
|
nearest = std::min(nearest, i.lastOutput + std::chrono::seconds(settings.maxSilentTime));
|
||||||
if (settings.buildTimeout != 0)
|
if (settings.buildTimeout != 0)
|
||||||
nearest = std::min(nearest, i.timeStarted + settings.buildTimeout);
|
nearest = std::min(nearest, i.timeStarted + std::chrono::seconds(settings.buildTimeout));
|
||||||
}
|
}
|
||||||
if (nearest != LONG_MAX) {
|
if (nearest != steady_time_point::max()) {
|
||||||
timeout.tv_sec = std::max((time_t) 1, nearest - before);
|
timeout.tv_sec = std::max(1L, std::chrono::duration_cast<std::chrono::seconds>(nearest - before).count());
|
||||||
useTimeout = true;
|
useTimeout = true;
|
||||||
printMsg(lvlVomit, format("sleeping %1% seconds") % timeout.tv_sec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we are polling goals that are waiting for a lock, then wake
|
/* If we are polling goals that are waiting for a lock, then wake
|
||||||
up after a few seconds at most. */
|
up after a few seconds at most. */
|
||||||
if (!waitingForAWhile.empty()) {
|
if (!waitingForAWhile.empty()) {
|
||||||
useTimeout = true;
|
useTimeout = true;
|
||||||
if (lastWokenUp == 0)
|
if (lastWokenUp == steady_time_point::min())
|
||||||
printError("waiting for locks or build slots...");
|
printError("waiting for locks or build slots...");
|
||||||
if (lastWokenUp == 0 || lastWokenUp > before) lastWokenUp = before;
|
if (lastWokenUp == steady_time_point::min() || lastWokenUp > before) lastWokenUp = before;
|
||||||
timeout.tv_sec = std::max((time_t) 1, (time_t) (lastWokenUp + settings.pollInterval - before));
|
timeout.tv_sec = std::max(1L,
|
||||||
} else lastWokenUp = 0;
|
std::chrono::duration_cast<std::chrono::seconds>(
|
||||||
|
lastWokenUp + std::chrono::seconds(settings.pollInterval) - before).count());
|
||||||
|
} else lastWokenUp = steady_time_point::min();
|
||||||
|
|
||||||
|
if (useTimeout)
|
||||||
|
vomit("sleeping %d seconds", timeout.tv_sec);
|
||||||
|
|
||||||
/* Use select() to wait for the input side of any logger pipe to
|
/* Use select() to wait for the input side of any logger pipe to
|
||||||
become `available'. Note that `available' (i.e., non-blocking)
|
become `available'. Note that `available' (i.e., non-blocking)
|
||||||
|
@ -3666,7 +3672,7 @@ void Worker::waitForInput()
|
||||||
throw SysError("waiting for input");
|
throw SysError("waiting for input");
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t after = time(0);
|
auto after = steady_time_point::clock::now();
|
||||||
|
|
||||||
/* Process all available file descriptors. */
|
/* Process all available file descriptors. */
|
||||||
decltype(children)::iterator i;
|
decltype(children)::iterator i;
|
||||||
|
@ -3704,7 +3710,7 @@ void Worker::waitForInput()
|
||||||
if (goal->getExitCode() == Goal::ecBusy &&
|
if (goal->getExitCode() == Goal::ecBusy &&
|
||||||
settings.maxSilentTime != 0 &&
|
settings.maxSilentTime != 0 &&
|
||||||
j->respectTimeouts &&
|
j->respectTimeouts &&
|
||||||
after - j->lastOutput >= (time_t) settings.maxSilentTime)
|
after - j->lastOutput >= std::chrono::seconds(settings.maxSilentTime))
|
||||||
{
|
{
|
||||||
printError(
|
printError(
|
||||||
format("%1% timed out after %2% seconds of silence")
|
format("%1% timed out after %2% seconds of silence")
|
||||||
|
@ -3715,7 +3721,7 @@ void Worker::waitForInput()
|
||||||
else if (goal->getExitCode() == Goal::ecBusy &&
|
else if (goal->getExitCode() == Goal::ecBusy &&
|
||||||
settings.buildTimeout != 0 &&
|
settings.buildTimeout != 0 &&
|
||||||
j->respectTimeouts &&
|
j->respectTimeouts &&
|
||||||
after - j->timeStarted >= (time_t) settings.buildTimeout)
|
after - j->timeStarted >= std::chrono::seconds(settings.buildTimeout))
|
||||||
{
|
{
|
||||||
printError(
|
printError(
|
||||||
format("%1% timed out after %2% seconds")
|
format("%1% timed out after %2% seconds")
|
||||||
|
@ -3724,7 +3730,7 @@ void Worker::waitForInput()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!waitingForAWhile.empty() && lastWokenUp + (time_t) settings.pollInterval <= after) {
|
if (!waitingForAWhile.empty() && lastWokenUp + std::chrono::seconds(settings.pollInterval) <= after) {
|
||||||
lastWokenUp = after;
|
lastWokenUp = after;
|
||||||
for (auto & i : waitingForAWhile) {
|
for (auto & i : waitingForAWhile) {
|
||||||
GoalPtr goal = i.lock();
|
GoalPtr goal = i.lock();
|
||||||
|
|
|
@ -79,6 +79,7 @@ extern Verbosity verbosity; /* suppress msgs > this */
|
||||||
#define printError(args...) printMsg(lvlError, args)
|
#define printError(args...) printMsg(lvlError, args)
|
||||||
#define printInfo(args...) printMsg(lvlInfo, args)
|
#define printInfo(args...) printMsg(lvlInfo, args)
|
||||||
#define debug(args...) printMsg(lvlDebug, args)
|
#define debug(args...) printMsg(lvlDebug, args)
|
||||||
|
#define vomit(args...) printMsg(lvlVomit, args)
|
||||||
|
|
||||||
void warnOnce(bool & haveWarned, const FormatOrString & fs);
|
void warnOnce(bool & haveWarned, const FormatOrString & fs);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue