message: 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
diff: @@ -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};
  @@ -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:
  @@ -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 {
  