servo/components/style/scoped_tls.rs
Bobby Holley c5f01fe3b8 Introduce and use Scoped TLS.
It turns out that it's problematic to embed ThreadLocalStyleContext within
LayoutContext, because parameterizing the former on TElement (which we do
in the next patch) infects all the traversal stuff with the trait parameters,
which we don't really want.

In general, it probably makes sense to use separate scoped TLS types for
the separate DOM and Flow tree passes, so we can add a different ScopedTLS
type for the Flow pass if we ever need it.

We also reorder the |scope| and |shared| parameters in parallel.rs, because
it aligns more with the order in style/parallel.rs. I did this when I was
adding a TLS parameter to all these functions, which I realized we don't need
for now.
2016-12-21 11:10:39 -08:00

51 lines
1.4 KiB
Rust

/* 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 http://mozilla.org/MPL/2.0/. */
#![allow(unsafe_code)]
use rayon;
use std::cell::{Ref, RefCell, RefMut};
/// Stack-scoped thread-local storage for rayon thread pools.
pub struct ScopedTLS<'a, T: Send> {
pool: &'a rayon::ThreadPool,
slots: Box<[RefCell<Option<T>>]>,
}
unsafe impl<'a, T: Send> Sync for ScopedTLS<'a, T> {}
impl<'a, T: Send> ScopedTLS<'a, T> {
pub fn new(p: &'a rayon::ThreadPool) -> Self {
let count = p.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(),
}
}
pub fn borrow(&self) -> Ref<Option<T>> {
let idx = self.pool.current_thread_index().unwrap();
self.slots[idx].borrow()
}
pub fn borrow_mut(&self) -> RefMut<Option<T>> {
let idx = self.pool.current_thread_index().unwrap();
self.slots[idx].borrow_mut()
}
pub fn ensure<F: FnOnce() -> T>(&self, f: F) -> RefMut<T> {
let mut opt = self.borrow_mut();
if opt.is_none() {
*opt = Some(f());
}
RefMut::map(opt, |x| x.as_mut().unwrap())
}
}