1
Fork 0

Add a local counter that tracks how many tasks are pushed or not pushed,

so that we can still get assertion failures even when dep-graph
construction is disabled.
This commit is contained in:
Niko Matsakis 2016-01-29 15:00:46 -05:00
parent 98422e8c15
commit 37fbfaf183

View file

@ -19,6 +19,7 @@
//! allocated (and both have a fairly large capacity). //! allocated (and both have a fairly large capacity).
use rustc_data_structures::veccell::VecCell; use rustc_data_structures::veccell::VecCell;
use std::cell::Cell;
use std::sync::mpsc::{self, Sender, Receiver}; use std::sync::mpsc::{self, Sender, Receiver};
use std::thread; use std::thread;
@ -39,6 +40,13 @@ pub enum DepMessage {
pub struct DepGraphThreadData { pub struct DepGraphThreadData {
enabled: bool, enabled: bool,
// Local counter that just tracks how many tasks are pushed onto the
// stack, so that we still get an error in the case where one is
// missing. If dep-graph construction is enabled, we'd get the same
// error when processing tasks later on, but that's annoying because
// it lacks precision about the source of the error.
tasks_pushed: Cell<usize>,
// current buffer, where we accumulate messages // current buffer, where we accumulate messages
messages: VecCell<DepMessage>, messages: VecCell<DepMessage>,
@ -59,11 +67,14 @@ impl DepGraphThreadData {
let (tx1, rx1) = mpsc::channel(); let (tx1, rx1) = mpsc::channel();
let (tx2, rx2) = mpsc::channel(); let (tx2, rx2) = mpsc::channel();
let (txq, rxq) = mpsc::channel(); let (txq, rxq) = mpsc::channel();
if enabled { if enabled {
thread::spawn(move || main(rx1, tx2, txq)); thread::spawn(move || main(rx1, tx2, txq));
} }
DepGraphThreadData { DepGraphThreadData {
enabled: enabled, enabled: enabled,
tasks_pushed: Cell::new(0),
messages: VecCell::with_capacity(INITIAL_CAPACITY), messages: VecCell::with_capacity(INITIAL_CAPACITY),
swap_in: rx2, swap_in: rx2,
swap_out: tx1, swap_out: tx1,
@ -71,6 +82,11 @@ impl DepGraphThreadData {
} }
} }
#[inline]
pub fn enabled(&self) -> bool {
self.enabled
}
/// Sends the current batch of messages to the thread. Installs a /// Sends the current batch of messages to the thread. Installs a
/// new vector of messages. /// new vector of messages.
fn swap(&self) { fn swap(&self) {
@ -100,12 +116,39 @@ impl DepGraphThreadData {
/// the buffer is full, this may swap.) /// the buffer is full, this may swap.)
#[inline] #[inline]
pub fn enqueue(&self, message: DepMessage) { pub fn enqueue(&self, message: DepMessage) {
if self.enabled { // Regardless of whether dep graph construction is enabled, we
let len = self.messages.push(message); // still want to check that we always have a valid task on the
if len == INITIAL_CAPACITY { // stack when a read/write/etc event occurs.
self.swap(); match message {
} DepMessage::Read(_) | DepMessage::Write(_) =>
if self.tasks_pushed.get() == 0 {
self.invalid_message("read/write but no current task")
},
DepMessage::PushTask(_) | DepMessage::PushIgnore =>
self.tasks_pushed.set(self.tasks_pushed.get() + 1),
DepMessage::PopTask(_) | DepMessage::PopIgnore =>
self.tasks_pushed.set(self.tasks_pushed.get() - 1),
DepMessage::Query =>
(),
} }
if self.enabled {
self.enqueue_enabled(message);
}
}
// Outline this fn since I expect it may want to be inlined
// separately.
fn enqueue_enabled(&self, message: DepMessage) {
let len = self.messages.push(message);
if len == INITIAL_CAPACITY {
self.swap();
}
}
// Outline this too.
fn invalid_message(&self, string: &str) {
panic!("{}; see src/librustc/dep_graph/README.md for more information", string)
} }
} }