/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Different objects protected by the same lock
usecrate::str::{CssString, CssStringWriter}; usecrate::stylesheets::Origin; #[cfg(feature = "gecko")] use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; #[cfg(feature = "servo")] use parking_lot::RwLock; use servo_arc::Arc; use std::cell::UnsafeCell; use std::fmt; #[cfg(feature = "servo")] use std::mem; #[cfg(feature = "gecko")] use std::ptr; use to_shmem::{SharedMemoryBuilder, ToShmem};
/// A shared read/write lock that can protect multiple objects. /// /// In Gecko builds, we don't need the blocking behavior, just the safety. As /// such we implement this with an AtomicRefCell instead in Gecko builds, /// which is ~2x as fast, and panics (rather than deadlocking) when things go /// wrong (which is much easier to debug on CI). /// /// 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))] pubstruct SharedRwLock { #[cfg(feature = "servo")] #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
arc: Arc<RwLock<()>>,
/// Wrap the given data to make its access protected by this lock. pubfn wrap<T>(&self, data: T) -> Locked<T> {
Locked {
shared_lock: self.clone(),
data: UnsafeCell::new(data),
}
}
/// Obtain the lock for reading (servo). #[cfg(feature = "servo")] pubfn read(&self) -> SharedRwLockReadGuard {
mem::forget(self.arc.read());
SharedRwLockReadGuard(self)
}
/// Obtain the lock for reading (gecko). #[cfg(feature = "gecko")] pubfn read(&self) -> SharedRwLockReadGuard {
SharedRwLockReadGuard(self.cell.as_ref().map(|cell| cell.borrow()))
}
/// Obtain the lock for writing (servo). #[cfg(feature = "servo")] pubfn write(&self) -> SharedRwLockWriteGuard {
mem::forget(self.arc.write());
SharedRwLockWriteGuard(self)
}
/// Obtain the lock for writing (gecko). #[cfg(feature = "gecko")] pubfn write(&self) -> SharedRwLockWriteGuard {
SharedRwLockWriteGuard(self.cell.as_ref().unwrap().borrow_mut())
}
}
/// Proof that a shared lock was obtained for reading (servo). #[cfg(feature = "servo")] pubstruct SharedRwLockReadGuard<'a>(&'a SharedRwLock); /// Proof that a shared lock was obtained for reading (gecko). #[cfg(feature = "gecko")] pubstruct SharedRwLockReadGuard<'a>(Option<AtomicRef<'a, SomethingZeroSizedButTyped>>); #[cfg(feature = "servo")] impl<'a> Drop for SharedRwLockReadGuard<'a> { fn drop(&mutself) { // 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() }
}
}
/// Proof that a shared lock was obtained for writing (servo). #[cfg(feature = "servo")] pubstruct SharedRwLockWriteGuard<'a>(&'a SharedRwLock); /// Proof that a shared lock was obtained for writing (gecko). #[cfg(feature = "gecko")] pubstruct SharedRwLockWriteGuard<'a>(AtomicRefMut<'a, SomethingZeroSizedButTyped>); #[cfg(feature = "servo")] impl<'a> Drop for SharedRwLockWriteGuard<'a> { fn drop(&mutself) { // Unsafe: self.lock is private to this module, only ever set after `write()`, // and never copied or cloned (see `compile_time_assert` below). unsafe { self.0.arc.force_unlock_write() }
}
}
/// Data protect by a shared lock. pubstruct Locked<T> {
shared_lock: SharedRwLock,
data: UnsafeCell<T>,
}
// Unsafe: the data inside `UnsafeCell` is only accessed in `read_with` and `write_with`, // where guards ensure synchronization. unsafeimpl<T: Send> Send for Locked<T> {} unsafeimpl<T: Send + Sync> Sync for Locked<T> {}
/// Access the data for reading. pubfn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T { #[cfg(feature = "gecko")]
assert!( self.is_read_only_lock() || self.same_lock_as(guard.ptr()), "Locked::read_with called with a guard from an unrelated SharedRwLock: {:?} vs. {:?}", self.shared_lock.ptr(),
guard.ptr(),
); #[cfg(not(feature = "gecko"))]
assert!(self.same_lock_as(&guard.0));
let ptr = self.data.get();
// Unsafe: // // * The guard guarantees that the lock is taken for reading, // and we’ve checked that it’s the correct lock. // * The returned reference borrows *both* the data and the guard, // so that it can outlive neither. unsafe { &*ptr }
}
/// Access the data for reading without verifying the lock. Use with caution. #[cfg(feature = "gecko")] pubunsafefn read_unchecked<'a>(&'a self) -> &'a T { let ptr = self.data.get();
&*ptr
}
/// Access the data for writing. pubfn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T { #[cfg(feature = "gecko")]
assert!(
!self.is_read_only_lock() && self.same_lock_as(&*guard.0), "Locked::write_with called with a guard from a read only or unrelated SharedRwLock"
); #[cfg(not(feature = "gecko"))]
assert!(self.same_lock_as(&guard.0));
let ptr = self.data.get();
// Unsafe: // // * The guard guarantees that the lock is taken for writing, // and we’ve checked that it’s the correct lock. // * The returned reference borrows *both* the data and the guard, // so that it can outlive neither. // * We require a mutable borrow of the guard, // so that one write guard can only be used once at a time. unsafe { &mut *ptr }
}
}
#[cfg(feature = "gecko")] impl<T: ToShmem> ToShmem for Locked<T> { fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> { use std::mem::ManuallyDrop;
#[cfg(feature = "servo")] impl<T: ToShmem> ToShmem for Locked<T> { fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
panic!("ToShmem not supported in Servo currently")
}
}
#[allow(dead_code)] mod compile_time_assert { usesuper::{SharedRwLockReadGuard, SharedRwLockWriteGuard};
trait Marker1 {} impl<T: Clone> Marker1 for T {} impl<'a> Marker1 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Clone impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Clone
trait Marker2 {} impl<T: Copy> Marker2 for T {} impl<'a> Marker2 for SharedRwLockReadGuard<'a> {} // Assert SharedRwLockReadGuard: !Copy impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} // Assert SharedRwLockWriteGuard: !Copy
}
/// Like ToCss, but with a lock guard given by the caller, and with the writer specified /// concretely rather than with a parameter. pubtrait ToCssWithGuard { /// Serialize `self` in CSS syntax, writing to `dest`, using the given lock guard. fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result;
/// Serialize `self` in CSS syntax using the given lock guard and return a string. /// /// (This is a convenience wrapper for `to_css` and probably should not be overridden.) #[inline] fn to_css_string(&self, guard: &SharedRwLockReadGuard) -> CssString { letmut s = CssString::new(); self.to_css(guard, &mut s).unwrap();
s
}
}
/// A trait to do a deep clone of a given CSS type. Gets a lock and a read /// guard, in order to be able to read and clone nested structures. pubtrait DeepCloneWithLock: Sized { /// Deep clones this object. fn deep_clone_with_lock(
&self,
lock: &SharedRwLock,
guard: &SharedRwLockReadGuard,
) -> Self;
}
/// Guards for a document #[derive(Clone)] pubstruct StylesheetGuards<'a> { /// For author-origin stylesheets. pub author: &'a SharedRwLockReadGuard<'a>,
/// For user-agent-origin and user-origin stylesheets pub ua_or_user: &'a SharedRwLockReadGuard<'a>,
}
impl<'a> StylesheetGuards<'a> { /// Get the guard for a given stylesheet origin. pubfn for_origin(&self, origin: Origin) -> &SharedRwLockReadGuard<'a> { match origin {
Origin::Author => &self.author,
_ => &self.ua_or_user,
}
}
/// Same guard for all origins pubfn same(guard: &'a SharedRwLockReadGuard<'a>) -> Self {
StylesheetGuards {
author: guard,
ua_or_user: guard,
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.