mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
style: Add support for read only SharedRwLocks, which don't need any locking.
Differential Revision: https://phabricator.services.mozilla.com/D17185
This commit is contained in:
parent
7e7a9e2ec5
commit
b71a601a36
1 changed files with 47 additions and 12 deletions
|
@ -28,6 +28,10 @@ use std::ptr;
|
||||||
/// Servo needs the blocking behavior for its unsynchronized animation setup,
|
/// 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
|
/// but that may not be web-compatible and may need to be changed (at which
|
||||||
/// point Servo could use AtomicRefCell too).
|
/// 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)]
|
#[derive(Clone)]
|
||||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
||||||
pub struct SharedRwLock {
|
pub struct SharedRwLock {
|
||||||
|
@ -36,7 +40,7 @@ pub struct SharedRwLock {
|
||||||
arc: Arc<RwLock<()>>,
|
arc: Arc<RwLock<()>>,
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
cell: Arc<AtomicRefCell<SomethingZeroSizedButTyped>>,
|
cell: Option<Arc<AtomicRefCell<SomethingZeroSizedButTyped>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
@ -61,10 +65,16 @@ impl SharedRwLock {
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SharedRwLock {
|
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.
|
/// Wrap the given data to make its access protected by this lock.
|
||||||
pub fn wrap<T>(&self, data: T) -> Locked<T> {
|
pub fn wrap<T>(&self, data: T) -> Locked<T> {
|
||||||
Locked {
|
Locked {
|
||||||
|
@ -83,7 +93,7 @@ impl SharedRwLock {
|
||||||
/// Obtain the lock for reading (gecko).
|
/// Obtain the lock for reading (gecko).
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub fn read(&self) -> SharedRwLockReadGuard {
|
pub fn read(&self) -> SharedRwLockReadGuard {
|
||||||
SharedRwLockReadGuard(self.cell.borrow())
|
SharedRwLockReadGuard(self.cell.as_ref().map(|cell| cell.borrow()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Obtain the lock for writing (servo).
|
/// Obtain the lock for writing (servo).
|
||||||
|
@ -96,22 +106,26 @@ impl SharedRwLock {
|
||||||
/// Obtain the lock for writing (gecko).
|
/// Obtain the lock for writing (gecko).
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub fn write(&self) -> SharedRwLockWriteGuard {
|
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).
|
/// Proof that a shared lock was obtained for reading (servo).
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
pub struct SharedRwLockReadGuard<'a>(&'a SharedRwLock);
|
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")]
|
#[cfg(feature = "gecko")]
|
||||||
pub struct SharedRwLockReadGuard<'a>(AtomicRef<'a, SomethingZeroSizedButTyped>);
|
pub struct SharedRwLockReadGuard<'a>(Option<AtomicRef<'a, SomethingZeroSizedButTyped>>);
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
impl<'a> Drop for SharedRwLockReadGuard<'a> {
|
impl<'a> Drop for SharedRwLockReadGuard<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Unsafe: self.lock is private to this module, only ever set after `read()`,
|
// Unsafe: self.lock is private to this module, only ever set after `read()`,
|
||||||
// and never copied or cloned (see `compile_time_assert` below).
|
// 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> {
|
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")]
|
#[cfg(feature = "servo")]
|
||||||
fn same_lock_as(&self, lock: &SharedRwLock) -> bool {
|
fn same_lock_as(&self, lock: &SharedRwLock) -> bool {
|
||||||
Arc::ptr_eq(&self.shared_lock.arc, &lock.arc)
|
Arc::ptr_eq(&self.shared_lock.arc, &lock.arc)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
fn same_lock_as(&self, derefed_guard: &SomethingZeroSizedButTyped) -> bool {
|
fn same_lock_as(&self, derefed_guard: Option<&SomethingZeroSizedButTyped>) -> bool {
|
||||||
ptr::eq(self.shared_lock.cell.as_ptr(), derefed_guard)
|
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.
|
/// Access the data for reading.
|
||||||
pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
|
pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
|
||||||
assert!(
|
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"
|
"Locked::read_with called with a guard from an unrelated SharedRwLock"
|
||||||
);
|
);
|
||||||
let ptr = self.data.get();
|
let ptr = self.data.get();
|
||||||
|
@ -186,8 +221,8 @@ impl<T> Locked<T> {
|
||||||
/// Access the data for writing.
|
/// Access the data for writing.
|
||||||
pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T {
|
pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T {
|
||||||
assert!(
|
assert!(
|
||||||
self.same_lock_as(&guard.0),
|
!self.is_read_only_lock() && self.same_lock_as(Some(&guard.0)),
|
||||||
"Locked::write_with called with a guard from an unrelated SharedRwLock"
|
"Locked::write_with called with a guard from a read only or unrelated SharedRwLock"
|
||||||
);
|
);
|
||||||
let ptr = self.data.get();
|
let ptr = self.data.get();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue