Auto merge of #18566 - bholley:thread_state_fixes, r=Manishearth

Thread state fixes

https://bugzilla.mozilla.org/show_bug.cgi?id=1400435
This commit is contained in:
bors-servo 2017-09-19 15:05:54 -05:00 committed by GitHub
commit c6381c66a0
3 changed files with 49 additions and 74 deletions

View file

@ -461,7 +461,8 @@ impl LayoutThread {
ScaleFactor::new(opts::get().device_pixels_per_px.unwrap_or(1.0))); ScaleFactor::new(opts::get().device_pixels_per_px.unwrap_or(1.0)));
let configuration = let configuration =
rayon::Configuration::new().num_threads(layout_threads); rayon::Configuration::new().num_threads(layout_threads)
.start_handler(|_| thread_state::initialize_layout_worker_thread());
let parallel_traversal = if layout_threads > 1 { let parallel_traversal = if layout_threads > 1 {
Some(rayon::ThreadPool::new(configuration).expect("ThreadPool creation failed")) Some(rayon::ThreadPool::new(configuration).expect("ThreadPool creation failed"))
} else { } else {

View file

@ -15,6 +15,7 @@ use shared_lock::SharedRwLock;
use std::cmp; use std::cmp;
use std::env; use std::env;
use std::ffi::CString; use std::ffi::CString;
use thread_state;
/// Global style data /// Global style data
pub struct GlobalStyleData { pub struct GlobalStyleData {
@ -39,6 +40,7 @@ fn thread_name(index: usize) -> String {
} }
fn thread_startup(index: usize) { fn thread_startup(index: usize) {
thread_state::initialize_layout_worker_thread();
unsafe { unsafe {
Gecko_SetJemallocThreadLocalArena(true); Gecko_SetJemallocThreadLocalArena(true);
} }

View file

@ -2,15 +2,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Supports dynamic assertions in debug builds about what sort of thread is //! Supports dynamic assertions in about what sort of thread is running and
//! running and what state it's in. //! what state it's in.
//!
//! In release builds, `get` returns 0. All of the other functions inline
//! away to nothing.
#![deny(missing_docs)] #![deny(missing_docs)]
pub use self::imp::{enter, exit, get, initialize}; use std::cell::RefCell;
bitflags! { bitflags! {
/// A thread state flag, used for multiple assertions. /// A thread state flag, used for multiple assertions.
@ -37,22 +34,12 @@ macro_rules! thread_types ( ( $( $fun:ident = $flag:ident ; )* ) => (
} }
$( $(
#[cfg(debug_assertions)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn $fun(self) -> bool { pub fn $fun(self) -> bool {
self.contains($flag) self.contains($flag)
} }
#[cfg(not(debug_assertions))]
#[allow(missing_docs)]
pub fn $fun(self) -> bool {
true
}
)* )*
} }
#[cfg(debug_assertions)]
static TYPES: &'static [ThreadState] =
&[ $( $flag ),* ];
)); ));
thread_types! { thread_types! {
@ -60,64 +47,49 @@ thread_types! {
is_layout = LAYOUT; is_layout = LAYOUT;
} }
#[cfg(debug_assertions)] thread_local!(static STATE: RefCell<Option<ThreadState>> = RefCell::new(None));
mod imp {
use std::cell::RefCell;
use super::{TYPES, ThreadState};
thread_local!(static STATE: RefCell<Option<ThreadState>> = RefCell::new(None)); /// Initializes the current thread state.
pub fn initialize(x: ThreadState) {
/// Initialize the current thread state. STATE.with(|ref k| {
pub fn initialize(x: ThreadState) { if let Some(ref s) = *k.borrow() {
STATE.with(|ref k| { panic!("Thread state already initialized as {:?}", s);
if let Some(ref s) = *k.borrow() { }
panic!("Thread state already initialized as {:?}", s); *k.borrow_mut() = Some(x);
} });
*k.borrow_mut() = Some(x);
});
get(); // check the assertion below
}
/// Get the current thread state.
pub fn get() -> ThreadState {
let state = STATE.with(|ref k| {
match *k.borrow() {
// This is one of the layout threads, that use rayon.
None => super::LAYOUT | super::IN_WORKER,
Some(s) => s,
}
});
// Exactly one of the thread type flags should be set.
assert_eq!(1, TYPES.iter().filter(|&&ty| state.contains(ty)).count());
state
}
/// Enter into a given temporary state. Panics if re-entring.
pub fn enter(x: ThreadState) {
let state = get();
assert!(!state.intersects(x));
STATE.with(|ref k| {
*k.borrow_mut() = Some(state | x);
})
}
/// Exit a given temporary state.
pub fn exit(x: ThreadState) {
let state = get();
assert!(state.contains(x));
STATE.with(|ref k| {
*k.borrow_mut() = Some(state & !x);
})
}
} }
#[cfg(not(debug_assertions))] /// Initializes the current thread as a layout worker thread.
#[allow(missing_docs)] pub fn initialize_layout_worker_thread() {
mod imp { initialize(LAYOUT | IN_WORKER);
use super::ThreadState; }
#[inline(always)] pub fn initialize(_: ThreadState) { }
#[inline(always)] pub fn get() -> ThreadState { ThreadState::empty() } /// Gets the current thread state.
#[inline(always)] pub fn enter(_: ThreadState) { } pub fn get() -> ThreadState {
#[inline(always)] pub fn exit(_: ThreadState) { } let state = STATE.with(|ref k| {
match *k.borrow() {
None => ThreadState::empty(), // Unknown thread.
Some(s) => s,
}
});
state
}
/// Enters into a given temporary state. Panics if re-entring.
pub fn enter(x: ThreadState) {
let state = get();
debug_assert!(!state.intersects(x));
STATE.with(|ref k| {
*k.borrow_mut() = Some(state | x);
})
}
/// Exits a given temporary state.
pub fn exit(x: ThreadState) {
let state = get();
debug_assert!(state.contains(x));
STATE.with(|ref k| {
*k.borrow_mut() = Some(state & !x);
})
} }