From 2aa4a82499d4becd2284cdb482213d541b8804dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 16:29:10 +0200 Subject: Adding upstream version 86.0.1. Signed-off-by: Daniel Baumann --- servo/components/style/scoped_tls.rs | 78 ++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 servo/components/style/scoped_tls.rs (limited to 'servo/components/style/scoped_tls.rs') diff --git a/servo/components/style/scoped_tls.rs b/servo/components/style/scoped_tls.rs new file mode 100644 index 0000000000..7491456669 --- /dev/null +++ b/servo/components/style/scoped_tls.rs @@ -0,0 +1,78 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +//! Stack-scoped thread-local storage for rayon thread pools. + +#![allow(unsafe_code)] +#![deny(missing_docs)] + +use rayon; +use std::cell::{Ref, RefCell, RefMut}; +use std::ops::DerefMut; + +/// A scoped TLS set, that is alive during the `'scope` lifetime. +/// +/// We use this on Servo to construct thread-local contexts, but clear them once +/// we're done with restyling. +/// +/// Note that the cleanup is done on the thread that owns the scoped TLS, thus +/// the Send bound. +pub struct ScopedTLS<'scope, T: Send> { + pool: &'scope rayon::ThreadPool, + slots: Box<[RefCell>]>, +} + +/// The scoped TLS is `Sync` because no more than one worker thread can access a +/// given slot. +unsafe impl<'scope, T: Send> Sync for ScopedTLS<'scope, T> {} + +impl<'scope, T: Send> ScopedTLS<'scope, T> { + /// Create a new scoped TLS that will last as long as this rayon threadpool + /// reference. + pub fn new(p: &'scope rayon::ThreadPool) -> Self { + let count = p.current_num_threads(); + let mut v = Vec::with_capacity(count); + for _ in 0..count { + v.push(RefCell::new(None)); + } + + ScopedTLS { + pool: p, + slots: v.into_boxed_slice(), + } + } + + /// Return an immutable reference to the `Option` that this thread owns. + pub fn borrow(&self) -> Ref> { + let idx = self.pool.current_thread_index().unwrap(); + self.slots[idx].borrow() + } + + /// Return a mutable reference to the `Option` that this thread owns. + pub fn borrow_mut(&self) -> RefMut> { + let idx = self.pool.current_thread_index().unwrap(); + self.slots[idx].borrow_mut() + } + + /// Ensure that the current data this thread owns is initialized, or + /// initialize it using `f`. We want ensure() to be fast and inline, and we + /// want to inline the memmove that initializes the Option. But we don't + /// want to inline space for the entire large T struct in our stack frame. + /// That's why we hand `f` a mutable borrow to write to instead of just + /// having it return a T. + #[inline(always)] + pub fn ensure)>(&self, f: F) -> RefMut { + let mut opt = self.borrow_mut(); + if opt.is_none() { + f(opt.deref_mut()); + } + + RefMut::map(opt, |x| x.as_mut().unwrap()) + } + + /// Returns the slots, consuming the scope. + pub fn into_slots(self) -> Box<[RefCell>]> { + self.slots + } +} -- cgit v1.2.3