Use raw pointers

This commit is contained in:
John Kåre Alsaker 2018-05-27 09:01:57 +02:00
parent 090b8341bc
commit 302aae5864

View File

@ -62,7 +62,7 @@ pub struct QueryJob<'tcx> {
pub diagnostics: Lock<Vec<Diagnostic>>, pub diagnostics: Lock<Vec<Diagnostic>>,
#[cfg(parallel_queries)] #[cfg(parallel_queries)]
latch: QueryLatch, latch: QueryLatch<'tcx>,
} }
impl<'tcx> QueryJob<'tcx> { impl<'tcx> QueryJob<'tcx> {
@ -146,41 +146,45 @@ impl<'tcx> QueryJob<'tcx> {
/// ///
/// This does nothing for single threaded rustc, /// This does nothing for single threaded rustc,
/// as there are no concurrent jobs which could be waiting on us /// as there are no concurrent jobs which could be waiting on us
pub fn signal_complete(&self, tcx: TyCtxt<'_, 'tcx, '_>) { pub fn signal_complete(&self) {
#[cfg(parallel_queries)] #[cfg(parallel_queries)]
self.latch.set(tcx); self.latch.set();
} }
} }
#[cfg(parallel_queries)] #[cfg(parallel_queries)]
struct QueryWaiter<'a, 'tcx: 'a> { struct QueryWaiter<'tcx> {
query: &'a Option<Lrc<QueryJob<'tcx>>>, query: *const Option<Lrc<QueryJob<'tcx>>>,
condvar: Condvar, condvar: Condvar,
span: Span, span: Span,
cycle: Option<CycleError<'tcx>>, cycle: Option<CycleError<'tcx>>,
} }
#[cfg(parallel_queries)] #[cfg(parallel_queries)]
impl<'a, 'tcx> QueryWaiter<'a, 'tcx> { impl<'tcx> QueryWaiter<'tcx> {
fn notify(&self, tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) { fn notify(&self, registry: &rayon_core::Registry) {
rayon_core::mark_unblocked(registry); rayon_core::mark_unblocked(registry);
self.condvar.notify_one(); self.condvar.notify_one();
} }
} }
#[cfg(parallel_queries)] #[cfg(parallel_queries)]
struct QueryLatchInfo { struct QueryLatchInfo<'tcx> {
complete: bool, complete: bool,
waiters: Vec<&'static mut QueryWaiter<'static, 'static>>, waiters: Vec<*mut QueryWaiter<'tcx>>,
}
// Required because of raw pointers
#[cfg(parallel_queries)]
unsafe impl<'tcx> Send for QueryLatchInfo<'tcx> {}
#[cfg(parallel_queries)]
struct QueryLatch<'tcx> {
info: Mutex<QueryLatchInfo<'tcx>>,
} }
#[cfg(parallel_queries)] #[cfg(parallel_queries)]
struct QueryLatch { impl<'tcx> QueryLatch<'tcx> {
info: Mutex<QueryLatchInfo>,
}
#[cfg(parallel_queries)]
impl QueryLatch {
fn new() -> Self { fn new() -> Self {
QueryLatch { QueryLatch {
info: Mutex::new(QueryLatchInfo { info: Mutex::new(QueryLatchInfo {
@ -190,44 +194,45 @@ impl QueryLatch {
} }
} }
fn await(&self, waiter: &mut QueryWaiter<'_, '_>) { fn await(&self, waiter: &mut QueryWaiter<'tcx>) {
let mut info = self.info.lock(); let mut info = self.info.lock();
if !info.complete { if !info.complete {
let waiter = &*waiter; info.waiters.push(waiter);
unsafe { let condvar = &waiter.condvar;
#[allow(mutable_transmutes)]
info.waiters.push(mem::transmute(waiter));
}
// If this detects a deadlock and the deadlock handler want to resume this thread // If this detects a deadlock and the deadlock handler want to resume this thread
// we have to be in the `wait` call. This is ensured by the deadlock handler // we have to be in the `wait` call. This is ensured by the deadlock handler
// getting the self.info lock. // getting the self.info lock.
rayon_core::mark_blocked(); rayon_core::mark_blocked();
waiter.condvar.wait(&mut info); condvar.wait(&mut info);
} }
} }
fn set(&self, tcx: TyCtxt<'_, '_, '_>) { fn set(&self) {
let mut info = self.info.lock(); let mut info = self.info.lock();
debug_assert!(!info.complete); debug_assert!(!info.complete);
info.complete = true; info.complete = true;
let registry = rayon_core::Registry::current(); let registry = rayon_core::Registry::current();
for waiter in info.waiters.drain(..) { for waiter in info.waiters.drain(..) {
waiter.notify(tcx, &registry); unsafe {
(*waiter).notify(&registry);
}
} }
} }
fn resume_waiter( fn resume_waiter(
&self, &self,
waiter: usize, waiter: usize,
error: CycleError error: CycleError<'tcx>
) -> &'static mut QueryWaiter<'static, 'static> { ) -> *mut QueryWaiter<'tcx> {
let mut info = self.info.lock(); let mut info = self.info.lock();
debug_assert!(!info.complete); debug_assert!(!info.complete);
// Remove the waiter from the list of waiters // Remove the waiter from the list of waiters
let waiter = info.waiters.remove(waiter); let waiter = info.waiters.remove(waiter);
// Set the cycle error it will be picked it up when resumed // Set the cycle error it will be picked it up when resumed
waiter.cycle = unsafe { Some(mem::transmute(error)) }; unsafe {
(*waiter).cycle = Some(error);
}
waiter waiter
} }
@ -250,10 +255,12 @@ where
return Some(cycle); return Some(cycle);
} }
} }
for (i, waiter) in query.latch.info.lock().waiters.iter().enumerate() { for (i, &waiter) in query.latch.info.lock().waiters.iter().enumerate() {
if let Some(ref waiter_query) = waiter.query { unsafe {
if visit(waiter.span, &**waiter_query as Ref).is_some() { if let Some(ref waiter_query) = *(*waiter).query {
return Some(Some((query_ref, i))); if visit((*waiter).span, &**waiter_query as Ref).is_some() {
return Some(Some((query_ref, i)));
}
} }
} }
} }
@ -322,7 +329,7 @@ fn query_entry<'tcx>(r: Ref<'tcx>) -> QueryInfo<'tcx> {
#[cfg(parallel_queries)] #[cfg(parallel_queries)]
fn remove_cycle<'tcx>( fn remove_cycle<'tcx>(
jobs: &mut Vec<Ref<'tcx>>, jobs: &mut Vec<Ref<'tcx>>,
wakelist: &mut Vec<&'static mut QueryWaiter<'static, 'static>>, wakelist: &mut Vec<*mut QueryWaiter<'tcx>>,
tcx: TyCtxt<'_, 'tcx, '_> tcx: TyCtxt<'_, 'tcx, '_>
) { ) {
let mut visited = HashSet::new(); let mut visited = HashSet::new();
@ -453,7 +460,9 @@ fn deadlock(tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) {
// FIXME: Ensure this won't cause a deadlock before we return // FIXME: Ensure this won't cause a deadlock before we return
for waiter in wakelist.into_iter() { for waiter in wakelist.into_iter() {
waiter.notify(tcx, registry); unsafe {
(*waiter).notify(registry);
}
} }
on_panic.disable(); on_panic.disable();