Skip to content
Permalink
Browse files

style: Add support for read only SharedRwLocks, which don't need any …

…locking.

Differential Revision: https://phabricator.services.mozilla.com/D17185
  • Loading branch information...
heycam authored and emilio committed Mar 30, 2019
1 parent 7e7a9e2 commit b71a601a36c3f52a8618027b9f817ff5524af38a
Showing with 47 additions and 12 deletions.
  1. +47 −12 components/style/shared_lock.rs
@@ -28,6 +28,10 @@ use std::ptr;
/// Servo needs the blocking behavior for its unsynchronized animation setup,
/// but that may not be web-compatible and may need to be changed (at which
/// point Servo could use AtomicRefCell too).
///
/// Gecko also needs the ability to have "read only" SharedRwLocks, which are
/// used for objects stored in (read only) shared memory. Attempting to acquire
/// write access to objects protected by a read only SharedRwLock will panic.
#[derive(Clone)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub struct SharedRwLock {
@@ -36,7 +40,7 @@ pub struct SharedRwLock {
arc: Arc<RwLock<()>>,

#[cfg(feature = "gecko")]
cell: Arc<AtomicRefCell<SomethingZeroSizedButTyped>>,
cell: Option<Arc<AtomicRefCell<SomethingZeroSizedButTyped>>>,
}

#[cfg(feature = "gecko")]
@@ -61,10 +65,16 @@ impl SharedRwLock {
#[cfg(feature = "gecko")]
pub fn new() -> Self {
SharedRwLock {
cell: Arc::new(AtomicRefCell::new(SomethingZeroSizedButTyped)),
cell: Some(Arc::new(AtomicRefCell::new(SomethingZeroSizedButTyped))),
}
}

/// Create a new read-only shared lock (gecko).
#[cfg(feature = "gecko")]
pub fn read_only() -> Self {
SharedRwLock { cell: None }
}

/// Wrap the given data to make its access protected by this lock.
pub fn wrap<T>(&self, data: T) -> Locked<T> {
Locked {
@@ -83,7 +93,7 @@ impl SharedRwLock {
/// Obtain the lock for reading (gecko).
#[cfg(feature = "gecko")]
pub fn read(&self) -> SharedRwLockReadGuard {
SharedRwLockReadGuard(self.cell.borrow())
SharedRwLockReadGuard(self.cell.as_ref().map(|cell| cell.borrow()))
}

/// Obtain the lock for writing (servo).
@@ -96,22 +106,26 @@ impl SharedRwLock {
/// Obtain the lock for writing (gecko).
#[cfg(feature = "gecko")]
pub fn write(&self) -> SharedRwLockWriteGuard {
SharedRwLockWriteGuard(self.cell.borrow_mut())
SharedRwLockWriteGuard(self.cell.as_ref().unwrap().borrow_mut())
}
}

/// Proof that a shared lock was obtained for reading (servo).
#[cfg(feature = "servo")]
pub struct SharedRwLockReadGuard<'a>(&'a SharedRwLock);
/// Proof that a shared lock was obtained for writing (gecko).
/// Proof that a shared lock was obtained for reading (gecko).
#[cfg(feature = "gecko")]
pub struct SharedRwLockReadGuard<'a>(AtomicRef<'a, SomethingZeroSizedButTyped>);
pub struct SharedRwLockReadGuard<'a>(Option<AtomicRef<'a, SomethingZeroSizedButTyped>>);
#[cfg(feature = "servo")]
impl<'a> Drop for SharedRwLockReadGuard<'a> {
fn drop(&mut self) {
// Unsafe: self.lock is private to this module, only ever set after `read()`,
// and never copied or cloned (see `compile_time_assert` below).
unsafe { self.0.arc.force_unlock_read() }
if let Some(arc) = self.0.arc {
unsafe {
arc.force_unlock_read();
}
}
}
}

@@ -149,20 +163,41 @@ impl<T: fmt::Debug> fmt::Debug for Locked<T> {
}

impl<T> Locked<T> {
#[cfg(feature = "servo")]
#[inline]
fn is_read_only_lock(&self) -> bool {
false
}

#[cfg(feature = "gecko")]
#[inline]
fn is_read_only_lock(&self) -> bool {
self.shared_lock.cell.is_none()
}

#[cfg(feature = "servo")]
fn same_lock_as(&self, lock: &SharedRwLock) -> bool {
Arc::ptr_eq(&self.shared_lock.arc, &lock.arc)
}

#[cfg(feature = "gecko")]
fn same_lock_as(&self, derefed_guard: &SomethingZeroSizedButTyped) -> bool {
ptr::eq(self.shared_lock.cell.as_ptr(), derefed_guard)
fn same_lock_as(&self, derefed_guard: Option<&SomethingZeroSizedButTyped>) -> bool {
ptr::eq(
self.shared_lock
.cell
.as_ref()
.map(|cell| cell.as_ptr())
.unwrap_or(ptr::null_mut()),
derefed_guard
.map(|guard| guard as *const _ as *mut _)
.unwrap_or(ptr::null_mut()),
)
}

/// Access the data for reading.
pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
assert!(
self.same_lock_as(&guard.0),
self.is_read_only_lock() || self.same_lock_as(guard.0.as_ref().map(|r| &**r)),
"Locked::read_with called with a guard from an unrelated SharedRwLock"
);
let ptr = self.data.get();
@@ -186,8 +221,8 @@ impl<T> Locked<T> {
/// Access the data for writing.
pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T {
assert!(
self.same_lock_as(&guard.0),
"Locked::write_with called with a guard from an unrelated SharedRwLock"
!self.is_read_only_lock() && self.same_lock_as(Some(&guard.0)),
"Locked::write_with called with a guard from a read only or unrelated SharedRwLock"
);
let ptr = self.data.get();

0 comments on commit b71a601

Please sign in to comment.
You can’t perform that action at this time.