Skip to content

Commit

Permalink
Auto merge of #59211 - nox:refcell-borrow-state, r=KodrAus
Browse files Browse the repository at this point in the history
Introduce RefCell::try_borrow_unguarded

*Come sit next to the fireplace with me, this is going to be a long story.*

So, you may already be aware that Servo has weird design constraints that forces us developers working on it to do weird things. The thing that interests us today is that we do layout on a separate thread with its own thread pool to do some things in parallel, whereas the data it uses comes from the script thread, which implements the entire DOM and related pieces, with `!Sync` data types such as `RefCell<T>`.

The invariant we maintain is that script does not do anything ever with the DOM data as long as layout is doing its job. That's all nice and all, but one thing we don't ensure is that we don't actually know if script was currently mutably borrowing some `RefCell<T>` prior to starting layout, which may lead to aliasing mutable memory and obviously undefined behaviour.

This PR reinstates `RefCell::borrow_state` so that [this method](https://github.com/servo/servo/blob/master/components/script/dom/bindings/cell.rs#L23-L30) can make use of it and return `None` if the cell was mutably borrowed.

Cc @SimonSapin
  • Loading branch information
bors committed Apr 11, 2019
2 parents ee1474a + 38811a1 commit 8509127
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/doc/unstable-book/src/library-features/borrow-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# `borrow_state`

The tracking issue for this feature is: [#27733]

[#27733]: https://github.com/rust-lang/rust/issues/27733

------------------------
38 changes: 38 additions & 0 deletions src/libcore/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,44 @@ impl<T: ?Sized> RefCell<T> {
&mut *self.value.get()
}
}

/// Immutably borrows the wrapped value, returning an error if the value is
/// currently mutably borrowed.
///
/// # Safety
///
/// Unlike `RefCell::borrow`, this method is unsafe because it does not
/// return a `Ref`, thus leaving the borrow flag untouched. Mutably
/// borrowing the `RefCell` while the reference returned by this method
/// is alive is undefined behaviour.
///
/// # Examples
///
/// ```
/// #![feature(borrow_state)]
/// use std::cell::RefCell;
///
/// let c = RefCell::new(5);
///
/// {
/// let m = c.borrow_mut();
/// assert!(unsafe { c.try_borrow_unguarded() }.is_err());
/// }
///
/// {
/// let m = c.borrow();
/// assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
/// }
/// ```
#[unstable(feature = "borrow_state", issue = "27733")]
#[inline]
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
if !is_writing(self.borrow.get()) {
Ok(&*self.value.get())
} else {
Err(BorrowError { _private: () })
}
}
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down

0 comments on commit 8509127

Please sign in to comment.