Step cancellation: Don't use pthread_cancel()

This was a bad idea because pthread_cancel() is unsalvageable broken
in C++. Destructors are not allowed to throw exceptions (especially in
C++11), but pthread_cancel() can cause a __cxxabiv1::__forced_unwind
exception inside any destructor that invokes a cancellation
point. (This exception can be caught but *must* be rethrown.) So let's
just kill the builder process instead.
This commit is contained in:
Eelco Dolstra
2016-11-07 19:34:35 +01:00
parent 95aa1f0590
commit 7863d2e1da
4 changed files with 57 additions and 33 deletions

View File

@ -117,7 +117,7 @@ static void copyClosureTo(ref<Store> destStore,
void State::buildRemote(ref<Store> destStore,
Machine::ptr machine, Step::ptr step,
unsigned int maxSilentTime, unsigned int buildTimeout,
RemoteResult & result)
RemoteResult & result, std::shared_ptr<ActiveStep> activeStep)
{
assert(BuildResult::TimedOut == 8);
@ -138,6 +138,24 @@ void State::buildRemote(ref<Store> destStore,
Child child;
openConnection(machine, tmpDir, logFD.get(), child);
{
auto activeStepState(activeStep->state_.lock());
if (activeStepState->cancelled) throw Error("step cancelled");
activeStepState->pid = child.pid;
}
Finally clearPid([&]() {
auto activeStepState(activeStep->state_.lock());
activeStepState->pid = -1;
/* FIXME: there is a slight race here with step
cancellation in State::processQueueChange(), which
could call kill() on this pid after we've done waitpid()
on it. With pid wrap-around, there is a tiny
possibility that we end up killing another
process. Meh. */
});
FdSource from(child.from.get());
FdSink to(child.to.get());