Use Event API and add docs

This commit is contained in:
Kevin Leimkuhler 2018-10-31 12:01:30 -07:00
parent 5bface5bb9
commit 83482293c6
3 changed files with 28 additions and 27 deletions

View file

@ -628,38 +628,32 @@ where
// panicked before it could be removed. At this point, we // panicked before it could be removed. At this point, we
// therefore "own" unique access to our slot, so we can just // therefore "own" unique access to our slot, so we can just
// remove the `InProgress` marker. // remove the `InProgress` marker.
let waiting = { let mut map = self.map.write();
let mut map = self.map.write(); match map.remove(self.key) {
match map.remove(self.key) { Some(QueryState::InProgress { id, waiting }) => {
Some(QueryState::InProgress { id, waiting }) => { assert_eq!(id, self.my_id);
assert_eq!(id, self.my_id);
let waiting = waiting.into_inner(); let waiting = waiting.into_inner();
if waiting.is_empty() { if !waiting.is_empty() {
// if nobody is waiting, we are done here // We want to propagate our panic to those waiting on
return; // us. By dropping `waiting`, others will panic in
} else { // `.recv`.
waiting std::mem::drop(waiting)
}
} }
}
// If we don't see an `InProgress` marker, something // If we don't see an `InProgress` marker, something
// has gone horribly wrong. This panic will // has gone horribly wrong. This panic will
// (unfortunately) abort the process, but recovery is // (unfortunately) abort the process, but recovery is
// not possible. // not possible.
_ => panic!( _ => panic!(
"\ "\
Unexpected panic during query evaluation, aborting the process. Unexpected panic during query evaluation, aborting the process.
Please report this bug to https://github.com/salsa-rs/salsa/issues." Please report this bug to https://github.com/salsa-rs/salsa/issues."
), ),
} }
};
// We want to propagate our panic to those waiting on us. By dropping
// `waiting`, others will panic in `.recv`.
std::mem::drop(waiting)
} else { } else {
// If no panic occurred, then panic guard ought to be // If no panic occurred, then panic guard ought to be
// "forgotten" and so this Drop code should never run. // "forgotten" and so this Drop code should never run.

View file

@ -112,7 +112,7 @@ where
/// Check if `key` is (currently) believed to be a constant. /// Check if `key` is (currently) believed to be a constant.
fn is_constant(&self, db: &DB, key: &Q::Key) -> bool; fn is_constant(&self, db: &DB, key: &Q::Key) -> bool;
/// Check if `key` is (currently) believed to be a constant. /// Get the (current) set of the keys in the query storage
fn keys<C>(&self, db: &DB) -> C fn keys<C>(&self, db: &DB) -> C
where where
C: std::iter::FromIterator<Q::Key>; C: std::iter::FromIterator<Q::Key>;

View file

@ -84,12 +84,17 @@ fn true_parallel_same_keys() {
assert_eq!(thread2.join().unwrap(), 111); assert_eq!(thread2.join().unwrap(), 111);
} }
/// Add a test that tries to trigger a conflict, where we fetch `sum("a")`
/// from two threads simultaneously. After `thread2` begins blocking,
/// we force `thread1` to panic and should see that propagate to `thread2`.
#[test] #[test]
fn true_parallel_propagate_panic() { fn true_parallel_propagate_panic() {
let db = ParDatabaseImpl::default(); let db = ParDatabaseImpl::default();
db.query(Input).set('a', 1); db.query(Input).set('a', 1);
// `thread1` will wait_for a barrier in the start of `sum`. Once it can
// continue, it will panic.
let thread1 = std::thread::spawn({ let thread1 = std::thread::spawn({
let db = db.fork(); let db = db.fork();
move || { move || {
@ -102,11 +107,13 @@ fn true_parallel_propagate_panic() {
} }
}); });
// `thread2` will wait until `thread1` has entered sum and then -- once it
// has set itself to block -- signal `thread1` to continue.
let thread2 = std::thread::spawn({ let thread2 = std::thread::spawn({
let db = db.fork(); let db = db.fork();
move || { move || {
db.knobs().signal.wait_for(1); db.knobs().signal.wait_for(1);
db.knobs().signal.signal(2); db.knobs().signal_on_will_block.set(2);
db.sum("a") db.sum("a")
} }
}); });