diff options
Diffstat (limited to 'src/libstore')
-rw-r--r-- | src/libstore/build.cc | 34 | ||||
-rw-r--r-- | src/libstore/globals.cc | 1 | ||||
-rw-r--r-- | src/libstore/globals.hh | 4 |
3 files changed, 35 insertions, 4 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 83bd6754a61a..4df62acea761 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -209,7 +209,10 @@ private: /* Last time the goals in `waitingForAWhile' where woken up. */ time_t lastWokenUp; - + + /* Last time `waitForInput' was last called. */ + time_t lastWait; + public: bool cacheFailure; @@ -681,7 +684,8 @@ HookInstance::HookInstance() builderOut.readSide.close(); if (dup2(builderOut.writeSide, 4) == -1) throw SysError("dupping builder's stdout/stderr"); - + + /* XXX: Pass `buildTimeout' to the hook? */ execl(buildHook.c_str(), buildHook.c_str(), thisSystem.c_str(), (format("%1%") % maxSilentTime).str().c_str(), (format("%1%") % printBuildTrace).str().c_str(), @@ -2666,7 +2670,14 @@ void Worker::waitForInput() struct timeval timeout; timeout.tv_usec = 0; time_t before = time(0); - + + /* If a global timeout has been set, sleep until it's done. */ + if (buildTimeout != 0) { + useTimeout = true; + if (lastWait == 0 || lastWait > before) lastWait = before; + timeout.tv_sec = std::max((time_t) 0, lastWait + buildTimeout - before); + } + /* If we're monitoring for silence on stdout/stderr, sleep until the first deadline for any child. */ if (maxSilentTime != 0) { @@ -2678,8 +2689,11 @@ void Worker::waitForInput() } } if (oldest) { + time_t silenceTimeout = std::max((time_t) 0, oldest + maxSilentTime - before); + timeout.tv_sec = useTimeout + ? std::min(silenceTimeout, timeout.tv_sec) + : silenceTimeout; useTimeout = true; - timeout.tv_sec = std::max((time_t) 0, oldest + maxSilentTime - before); printMsg(lvlVomit, format("sleeping %1% seconds") % timeout.tv_sec); } } @@ -2717,6 +2731,9 @@ void Worker::waitForInput() time_t after = time(0); + /* Keep track of when we were last called. */ + lastWait = after; + /* Process all available file descriptors. */ /* Since goals may be canceled from inside the loop below (causing @@ -2765,6 +2782,15 @@ void Worker::waitForInput() % goal->getName() % maxSilentTime); goal->cancel(); } + + if (buildTimeout != 0 && + after - before >= (time_t) buildTimeout) + { + printMsg(lvlError, + format("%1% timed out after %2% seconds of activity") + % goal->getName() % buildTimeout); + goal->cancel(); + } } if (!waitingForAWhile.empty() && lastWokenUp + wakeUpInterval <= after) { diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 7069d104aae4..2e9dc88237d1 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -26,6 +26,7 @@ unsigned int buildCores = 1; bool readOnlyMode = false; string thisSystem = "unset"; time_t maxSilentTime = 0; +time_t buildTimeout = 0; Paths substituters; bool useBuildHook = true; bool printBuildTrace = false; diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index a74a741d677e..231c1f8508ac 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -72,6 +72,10 @@ extern string thisSystem; infinity. */ extern time_t maxSilentTime; +/* The maximum duration in seconds that a builder can run. 0 means + infinity. */ +extern time_t buildTimeout; + /* The substituters. There are programs that can somehow realise a store path without building, e.g., by downloading it or copying it from a CD. */ |