]> git.lizzy.rs Git - rust.git/blobdiff - src/locks.rs
rustup for big refactor; kill most of validation
[rust.git] / src / locks.rs
index 9f4126ad82b60002e105863b78712e8f10ae5278..a87ff6367e3ad89c398360e87013b3d994586d22 100644 (file)
@@ -1,3 +1,5 @@
+#![allow(unused)]
+
 use super::*;
 use rustc::middle::region;
 use rustc::ty::layout::Size;
@@ -6,6 +8,9 @@
 // Locks
 ////////////////////////////////////////////////////////////////////////////////
 
+// Just some dummy to keep this compiling; I think some of this will be useful later
+type AbsPlace<'tcx> = ::rustc::ty::Ty<'tcx>;
+
 /// Information about a lock that is currently held.
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct LockInfo<'tcx> {
@@ -67,321 +72,6 @@ fn access_permitted(&self, frame: Option<usize>, access: AccessKind) -> bool {
     }
 }
 
-pub trait MemoryExt<'tcx> {
-    fn check_locks(
-        &self,
-        ptr: Pointer,
-        len: u64,
-        access: AccessKind,
-    ) -> EvalResult<'tcx>;
-    fn acquire_lock(
-        &mut self,
-        ptr: Pointer,
-        len: u64,
-        region: Option<region::Scope>,
-        kind: AccessKind,
-    ) -> EvalResult<'tcx>;
-    fn suspend_write_lock(
-        &mut self,
-        ptr: Pointer,
-        len: u64,
-        lock_path: &AbsPlace<'tcx>,
-        suspend: Option<region::Scope>,
-    ) -> EvalResult<'tcx>;
-    fn recover_write_lock(
-        &mut self,
-        ptr: Pointer,
-        len: u64,
-        lock_path: &AbsPlace<'tcx>,
-        lock_region: Option<region::Scope>,
-        suspended_region: region::Scope,
-    ) -> EvalResult<'tcx>;
-    fn locks_lifetime_ended(&mut self, ending_region: Option<region::Scope>);
-}
-
-
-impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> {
-    fn check_locks(
-        &self,
-        ptr: Pointer,
-        len: u64,
-        access: AccessKind,
-    ) -> EvalResult<'tcx> {
-        if len == 0 {
-            return Ok(());
-        }
-        let locks = match self.data.locks.get(&ptr.alloc_id) {
-            Some(locks) => locks,
-            // immutable static or other constant memory
-            None => return Ok(()),
-        };
-        let frame = self.cur_frame;
-        locks
-            .check(Some(frame), ptr.offset.bytes(), len, access)
-            .map_err(|lock| {
-                EvalErrorKind::MemoryLockViolation {
-                    ptr,
-                    len,
-                    frame,
-                    access,
-                    lock: lock.active,
-                }.into()
-            })
-    }
-
-    /// Acquire the lock for the given lifetime
-    fn acquire_lock(
-        &mut self,
-        ptr: Pointer,
-        len: u64,
-        region: Option<region::Scope>,
-        kind: AccessKind,
-    ) -> EvalResult<'tcx> {
-        let frame = self.cur_frame;
-        assert!(len > 0);
-        trace!(
-            "Frame {} acquiring {:?} lock at {:?}, size {} for region {:?}",
-            frame,
-            kind,
-            ptr,
-            len,
-            region
-        );
-        self.check_bounds(ptr.offset(Size::from_bytes(len), &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
-
-        let locks = match self.data.locks.get_mut(&ptr.alloc_id) {
-            Some(locks) => locks,
-            // immutable static or other constant memory
-            None => return Ok(()),
-        };
-
-        // Iterate over our range and acquire the lock.  If the range is already split into pieces,
-        // we have to manipulate all of them.
-        let lifetime = DynamicLifetime { frame, region };
-        for lock in locks.iter_mut(ptr.offset.bytes(), len) {
-            if !lock.access_permitted(None, kind) {
-                return err!(MemoryAcquireConflict {
-                    ptr,
-                    len,
-                    kind,
-                    lock: lock.active.clone(),
-                });
-            }
-            // See what we have to do
-            match (&mut lock.active, kind) {
-                (active @ &mut NoLock, AccessKind::Write) => {
-                    *active = WriteLock(lifetime);
-                }
-                (active @ &mut NoLock, AccessKind::Read) => {
-                    *active = ReadLock(vec![lifetime]);
-                }
-                (&mut ReadLock(ref mut lifetimes), AccessKind::Read) => {
-                    lifetimes.push(lifetime);
-                }
-                _ => bug!("We already checked that there is no conflicting lock"),
-            }
-        }
-        Ok(())
-    }
-
-    /// Release or suspend a write lock of the given lifetime prematurely.
-    /// When releasing, if there is a read lock or someone else's write lock, that's an error.
-    /// If no lock is held, that's fine.  This can happen when e.g. a local is initialized
-    /// from a constant, and then suspended.
-    /// When suspending, the same cases are fine; we just register an additional suspension.
-    fn suspend_write_lock(
-        &mut self,
-        ptr: Pointer,
-        len: u64,
-        lock_path: &AbsPlace<'tcx>,
-        suspend: Option<region::Scope>,
-    ) -> EvalResult<'tcx> {
-        assert!(len > 0);
-        let cur_frame = self.cur_frame;
-        let locks = match self.data.locks.get_mut(&ptr.alloc_id) {
-            Some(locks) => locks,
-            // immutable static or other constant memory
-            None => return Ok(()),
-        };
-
-        'locks: for lock in locks.iter_mut(ptr.offset.bytes(), len) {
-            let is_our_lock = match lock.active {
-                WriteLock(lft) =>
-                    // Double-check that we are holding the lock.
-                    // (Due to subtyping, checking the region would not make any sense.)
-                    lft.frame == cur_frame,
-                ReadLock(_) | NoLock => false,
-            };
-            if is_our_lock {
-                trace!("Releasing {:?}", lock.active);
-                // Disable the lock
-                lock.active = NoLock;
-            } else {
-                trace!(
-                    "Not touching {:?} as it is not our lock",
-                    lock.active,
-                );
-            }
-            // Check if we want to register a suspension
-            if let Some(suspend_region) = suspend {
-                let lock_id = WriteLockId {
-                    frame: cur_frame,
-                    path: lock_path.clone(),
-                };
-                trace!("Adding suspension to {:?}", lock_id);
-                let mut new_suspension = false;
-                lock.suspended
-                    .entry(lock_id)
-                    // Remember whether we added a new suspension or not
-                    .or_insert_with(|| { new_suspension = true; Vec::new() })
-                    .push(suspend_region);
-                // If the suspension is new, we should have owned this.
-                // If there already was a suspension, we should NOT have owned this.
-                if new_suspension == is_our_lock {
-                    // All is well
-                    continue 'locks;
-                }
-            } else if !is_our_lock {
-                // All is well.
-                continue 'locks;
-            }
-            // If we get here, releasing this is an error except for NoLock.
-            if lock.active != NoLock {
-                return err!(InvalidMemoryLockRelease {
-                    ptr,
-                    len,
-                    frame: cur_frame,
-                    lock: lock.active.clone(),
-                });
-            }
-        }
-
-        Ok(())
-    }
-
-    /// Release a suspension from the write lock.  If this is the last suspension or if there is no suspension, acquire the lock.
-    fn recover_write_lock(
-        &mut self,
-        ptr: Pointer,
-        len: u64,
-        lock_path: &AbsPlace<'tcx>,
-        lock_region: Option<region::Scope>,
-        suspended_region: region::Scope,
-    ) -> EvalResult<'tcx> {
-        assert!(len > 0);
-        let cur_frame = self.cur_frame;
-        let lock_id = WriteLockId {
-            frame: cur_frame,
-            path: lock_path.clone(),
-        };
-        let locks = match self.data.locks.get_mut(&ptr.alloc_id) {
-            Some(locks) => locks,
-            // immutable static or other constant memory
-            None => return Ok(()),
-        };
-
-        for lock in locks.iter_mut(ptr.offset.bytes(), len) {
-            // Check if we have a suspension here
-            let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) {
-                None => {
-                    trace!("No suspension around, we can just acquire");
-                    (true, false)
-                }
-                Some(suspensions) => {
-                    trace!("Found suspension of {:?}, removing it", lock_id);
-                    // That's us!  Remove suspension (it should be in there).  The same suspension can
-                    // occur multiple times (when there are multiple shared borrows of this that have the same
-                    // lifetime); only remove one of them.
-                    let idx = match suspensions.iter().enumerate().find(|&(_, re)| re == &suspended_region) {
-                        None => // TODO: Can the user trigger this?
-                            bug!("We have this lock suspended, but not for the given region."),
-                        Some((idx, _)) => idx
-                    };
-                    suspensions.remove(idx);
-                    let got_lock = suspensions.is_empty();
-                    if got_lock {
-                        trace!("All suspensions are gone, we can have the lock again");
-                    }
-                    (got_lock, got_lock)
-                }
-            };
-            if remove_suspension {
-                // with NLL, we could do that up in the match above...
-                assert!(got_the_lock);
-                lock.suspended.remove(&lock_id);
-            }
-            if got_the_lock {
-                match lock.active {
-                    ref mut active @ NoLock => {
-                        *active = WriteLock(
-                            DynamicLifetime {
-                                frame: cur_frame,
-                                region: lock_region,
-                            }
-                        );
-                    }
-                    _ => {
-                        return err!(MemoryAcquireConflict {
-                            ptr,
-                            len,
-                            kind: AccessKind::Write,
-                            lock: lock.active.clone(),
-                        })
-                    }
-                }
-            }
-        }
-
-        Ok(())
-    }
-
-    fn locks_lifetime_ended(&mut self, ending_region: Option<region::Scope>) {
-        let cur_frame = self.cur_frame;
-        trace!(
-            "Releasing frame {} locks that expire at {:?}",
-            cur_frame,
-            ending_region
-        );
-        let has_ended = |lifetime: &DynamicLifetime| -> bool {
-            if lifetime.frame != cur_frame {
-                return false;
-            }
-            match ending_region {
-                None => true, // When a function ends, we end *all* its locks. It's okay for a function to still have lifetime-related locks
-                // when it returns, that can happen e.g. with NLL when a lifetime can, but does not have to, extend beyond the
-                // end of a function.  Same for a function still having recoveries.
-                Some(ending_region) => lifetime.region == Some(ending_region),
-            }
-        };
-
-        for alloc_locks in self.data.locks.values_mut() {
-            for lock in alloc_locks.iter_mut_all() {
-                // Delete everything that ends now -- i.e., keep only all the other lifetimes.
-                let lock_ended = match lock.active {
-                    WriteLock(ref lft) => has_ended(lft),
-                    ReadLock(ref mut lfts) => {
-                        lfts.retain(|lft| !has_ended(lft));
-                        lfts.is_empty()
-                    }
-                    NoLock => false,
-                };
-                if lock_ended {
-                    lock.active = NoLock;
-                }
-                // Also clean up suspended write locks when the function returns
-                if ending_region.is_none() {
-                    lock.suspended.retain(|id, _suspensions| id.frame != cur_frame);
-                }
-            }
-            // Clean up the map
-            alloc_locks.retain(|lock| match lock.active {
-                NoLock => !lock.suspended.is_empty(),
-                _ => true,
-            });
-        }
-    }
-}
-
 impl<'tcx> RangeMap<LockInfo<'tcx>> {
     pub fn check(
         &self,