Fix --fallback

This fixes an assertion failure in "assert(goal);" in
Worker::waitForInput() after a substitution goal is cancelled by the
termination of another goal. The problem was the line

  //worker.childTerminated(shared_from_this()); // FIXME

in the SubstitutionGoal destructor. This was disabled because
shared_from_this() obviously doesn't work from a destructor. So we now
use a real pointer for object identity.
This commit is contained in:
Eelco Dolstra 2016-08-30 15:45:39 +02:00
parent dd85fc1c5a
commit 97b1af1cbe

View file

@ -193,6 +193,7 @@ bool CompareGoalPtrs::operator() (const GoalPtr & a, const GoalPtr & b) {
struct Child struct Child
{ {
WeakGoalPtr goal; WeakGoalPtr goal;
Goal * goal2; // ugly hackery
set<int> fds; set<int> fds;
bool respectTimeouts; bool respectTimeouts;
bool inBuildSlot; bool inBuildSlot;
@ -284,7 +285,7 @@ public:
false if there is no sense in waking up goals that are sleeping false if there is no sense in waking up goals that are sleeping
because they can't run yet (e.g., there is no free build slot, because they can't run yet (e.g., there is no free build slot,
or the hook would still say `postpone'). */ or the hook would still say `postpone'). */
void childTerminated(GoalPtr goal, bool wakeSleepers = true); void childTerminated(Goal * goal, bool wakeSleepers = true);
/* Put `goal' to sleep until a build slot becomes available (which /* Put `goal' to sleep until a build slot becomes available (which
might be right away). */ might be right away). */
@ -935,7 +936,7 @@ DerivationGoal::~DerivationGoal()
void DerivationGoal::killChild() void DerivationGoal::killChild()
{ {
if (pid != -1) { if (pid != -1) {
worker.childTerminated(shared_from_this()); worker.childTerminated(this);
if (buildUser.enabled()) { if (buildUser.enabled()) {
/* If we're using a build user, then there is a tricky /* If we're using a build user, then there is a tricky
@ -1409,7 +1410,7 @@ void DerivationGoal::buildDone()
debug(format("builder process for %1% finished") % drvPath); debug(format("builder process for %1% finished") % drvPath);
/* So the child is gone now. */ /* So the child is gone now. */
worker.childTerminated(shared_from_this()); worker.childTerminated(this);
/* Close the read side of the logger pipe. */ /* Close the read side of the logger pipe. */
if (hook) { if (hook) {
@ -3141,8 +3142,9 @@ SubstitutionGoal::~SubstitutionGoal()
{ {
try { try {
if (thr.joinable()) { if (thr.joinable()) {
// FIXME: signal worker thread to quit.
thr.join(); thr.join();
//worker.childTerminated(shared_from_this()); // FIXME worker.childTerminated(this);
} }
} catch (...) { } catch (...) {
ignoreException(); ignoreException();
@ -3297,7 +3299,7 @@ void SubstitutionGoal::finished()
trace("substitute finished"); trace("substitute finished");
thr.join(); thr.join();
worker.childTerminated(shared_from_this()); worker.childTerminated(this);
try { try {
promise.get_future().get(); promise.get_future().get();
@ -3450,6 +3452,7 @@ void Worker::childStarted(GoalPtr goal, const set<int> & fds,
{ {
Child child; Child child;
child.goal = goal; child.goal = goal;
child.goal2 = goal.get();
child.fds = fds; child.fds = fds;
child.timeStarted = child.lastOutput = time(0); child.timeStarted = child.lastOutput = time(0);
child.inBuildSlot = inBuildSlot; child.inBuildSlot = inBuildSlot;
@ -3459,10 +3462,10 @@ void Worker::childStarted(GoalPtr goal, const set<int> & fds,
} }
void Worker::childTerminated(GoalPtr goal, bool wakeSleepers) void Worker::childTerminated(Goal * goal, bool wakeSleepers)
{ {
auto i = std::find_if(children.begin(), children.end(), auto i = std::find_if(children.begin(), children.end(),
[&](const Child & child) { return child.goal.lock() == goal; }); [&](const Child & child) { return child.goal2 == goal; });
assert(i != children.end()); assert(i != children.end());
if (i->inBuildSlot) { if (i->inBuildSlot) {