Skip to content

Commit 8509127

Browse files
committed
Auto merge of #59211 - nox:refcell-borrow-state, r=KodrAus
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
2 parents ee1474a + 38811a1 commit 8509127

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# `borrow_state`
2+
3+
The tracking issue for this feature is: [#27733]
4+
5+
[#27733]: https://github.com/rust-lang/rust/issues/27733
6+
7+
------------------------

src/libcore/cell.rs

+38
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,44 @@ impl<T: ?Sized> RefCell<T> {
955955
&mut *self.value.get()
956956
}
957957
}
958+
959+
/// Immutably borrows the wrapped value, returning an error if the value is
960+
/// currently mutably borrowed.
961+
///
962+
/// # Safety
963+
///
964+
/// Unlike `RefCell::borrow`, this method is unsafe because it does not
965+
/// return a `Ref`, thus leaving the borrow flag untouched. Mutably
966+
/// borrowing the `RefCell` while the reference returned by this method
967+
/// is alive is undefined behaviour.
968+
///
969+
/// # Examples
970+
///
971+
/// ```
972+
/// #![feature(borrow_state)]
973+
/// use std::cell::RefCell;
974+
///
975+
/// let c = RefCell::new(5);
976+
///
977+
/// {
978+
/// let m = c.borrow_mut();
979+
/// assert!(unsafe { c.try_borrow_unguarded() }.is_err());
980+
/// }
981+
///
982+
/// {
983+
/// let m = c.borrow();
984+
/// assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
985+
/// }
986+
/// ```
987+
#[unstable(feature = "borrow_state", issue = "27733")]
988+
#[inline]
989+
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
990+
if !is_writing(self.borrow.get()) {
991+
Ok(&*self.value.get())
992+
} else {
993+
Err(BorrowError { _private: () })
994+
}
995+
}
958996
}
959997

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

0 commit comments

Comments
 (0)