Skip to content

Commit

Permalink
Auto merge of #7366 - alexcrichton:fix-hang, r=Eh2406
Browse files Browse the repository at this point in the history
Don't hang when Cargo's worker threads panic

This shouldn't ever happen during normal development, but happens from
time to time while developing Cargo itself.

Closes #6433
  • Loading branch information
bors committed Sep 16, 2019
2 parents b2d4f20 + 8a3c0fe commit bcb89d1
Showing 1 changed file with 26 additions and 3 deletions.
29 changes: 26 additions & 3 deletions src/cargo/core/compiler/job_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ use std::cell::Cell;
use std::collections::{HashMap, HashSet};
use std::io;
use std::marker;
use std::mem;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Arc;

use crossbeam_utils::thread::Scope;
use failure::format_err;
use jobserver::{Acquired, HelperThread};
use log::{debug, info, trace};

Expand Down Expand Up @@ -490,7 +492,13 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
rmeta_required: Cell::new(rmeta_required),
_marker: marker::PhantomData,
};
let res = job.run(&state);

let mut sender = FinishOnDrop {
tx: &my_tx,
id,
result: Err(format_err!("worker panicked")),
};
sender.result = job.run(&state);

// If the `rmeta_required` wasn't consumed but it was set
// previously, then we either have:
Expand All @@ -504,13 +512,28 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> {
// we'll just naturally abort the compilation operation but for 1
// we need to make sure that the metadata is flagged as produced so
// send a synthetic message here.
if state.rmeta_required.get() && res.is_ok() {
if state.rmeta_required.get() && sender.result.is_ok() {
my_tx
.send(Message::Finish(id, Artifact::Metadata, Ok(())))
.unwrap();
}

my_tx.send(Message::Finish(id, Artifact::All, res)).unwrap();
// Use a helper struct with a `Drop` implementation to guarantee
// that a `Finish` message is sent even if our job panics. We
// shouldn't panic unless there's a bug in Cargo, so we just need
// to make sure nothing hangs by accident.
struct FinishOnDrop<'a> {
tx: &'a Sender<Message>,
id: u32,
result: CargoResult<()>,
}

impl Drop for FinishOnDrop<'_> {
fn drop(&mut self) {
let msg = mem::replace(&mut self.result, Ok(()));
drop(self.tx.send(Message::Finish(self.id, Artifact::All, msg)));
}
}
};

if !cx.bcx.build_config.build_plan {
Expand Down

0 comments on commit bcb89d1

Please sign in to comment.