servo: Merge #18566 - Thread state fixes (from bholley:thread_state_fixes); r=Manishearth
authorBobby Holley <bobbyholley@gmail.com>
Tue, 19 Sep 2017 15:05:54 -0500
changeset 381712 7e1111a6f0521a51e6ca0fe553a40348e5de2ed4
parent 381711 6e57f448953dbd8b5df11682ccc13b022269512d
child 381713 f659596d56f2074544fa82d019d97074ff0402fc
push id51596
push userservo-vcs-sync@mozilla.com
push dateTue, 19 Sep 2017 21:10:32 +0000
treeherderautoland@7e1111a6f052 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersManishearth
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #18566 - Thread state fixes (from bholley:thread_state_fixes); r=Manishearth https://bugzilla.mozilla.org/show_bug.cgi?id=1400435 Source-Repo: https://github.com/servo/servo Source-Revision: c6381c66a0bc2b7cad14a808b000d0e38860c7f6
servo/components/layout_thread/lib.rs
servo/components/style/gecko/global_style_data.rs
servo/components/style/thread_state.rs
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -456,17 +456,18 @@ impl LayoutThread {
         // The device pixel ratio is incorrect (it does not have the hidpi value),
         // but it will be set correctly when the initial reflow takes place.
         let device = Device::new(
             MediaType::screen(),
             opts::get().initial_window_size.to_f32() * ScaleFactor::new(1.0),
             ScaleFactor::new(opts::get().device_pixels_per_px.unwrap_or(1.0)));
 
         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 {
             Some(rayon::ThreadPool::new(configuration).expect("ThreadPool creation failed"))
         } else {
             None
         };
         debug!("Possible layout Threads: {}", layout_threads);
 
         // Create the channel on which new animations can be sent.
--- a/servo/components/style/gecko/global_style_data.rs
+++ b/servo/components/style/gecko/global_style_data.rs
@@ -10,16 +10,17 @@ use gecko_bindings::bindings::{Gecko_Reg
 use gecko_bindings::bindings::Gecko_SetJemallocThreadLocalArena;
 use num_cpus;
 use parallel::STYLE_THREAD_STACK_SIZE_KB;
 use rayon;
 use shared_lock::SharedRwLock;
 use std::cmp;
 use std::env;
 use std::ffi::CString;
+use thread_state;
 
 /// Global style data
 pub struct GlobalStyleData {
     /// Shared RWLock for CSSOM objects
     pub shared_lock: SharedRwLock,
 
     /// Global style system options determined by env vars.
     pub options: StyleSystemOptions,
@@ -34,16 +35,17 @@ pub struct StyleThreadPool {
     pub style_thread_pool: Option<rayon::ThreadPool>,
 }
 
 fn thread_name(index: usize) -> String {
     format!("StyleThread#{}", index)
 }
 
 fn thread_startup(index: usize) {
+    thread_state::initialize_layout_worker_thread();
     unsafe {
         Gecko_SetJemallocThreadLocalArena(true);
     }
     let name = thread_name(index);
     let name = CString::new(name).unwrap();
     unsafe {
         // Gecko_RegisterProfilerThread copies the passed name here.
         Gecko_RegisterProfilerThread(name.as_ptr());
--- a/servo/components/style/thread_state.rs
+++ b/servo/components/style/thread_state.rs
@@ -1,21 +1,18 @@
 /* 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/. */
 
-//! Supports dynamic assertions in debug builds about what sort of thread is
-//! running and what state it's in.
-//!
-//! In release builds, `get` returns 0.  All of the other functions inline
-//! away to nothing.
+//! Supports dynamic assertions in about what sort of thread is running and
+//! what state it's in.
 
 #![deny(missing_docs)]
 
-pub use self::imp::{enter, exit, get, initialize};
+use std::cell::RefCell;
 
 bitflags! {
     /// A thread state flag, used for multiple assertions.
     pub flags ThreadState: u32 {
         /// Whether we're in a script thread.
         const SCRIPT          = 0x01,
         /// Whether we're in a layout thread.
         const LAYOUT          = 0x02,
@@ -32,92 +29,67 @@ bitflags! {
 macro_rules! thread_types ( ( $( $fun:ident = $flag:ident ; )* ) => (
     impl ThreadState {
         /// Whether the current thread is a worker thread.
         pub fn is_worker(self) -> bool {
             self.contains(IN_WORKER)
         }
 
         $(
-            #[cfg(debug_assertions)]
             #[allow(missing_docs)]
             pub fn $fun(self) -> bool {
                 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! {
     is_script = SCRIPT;
     is_layout = LAYOUT;
 }
 
-#[cfg(debug_assertions)]
-mod imp {
-    use std::cell::RefCell;
-    use super::{TYPES, ThreadState};
-
-    thread_local!(static STATE: RefCell<Option<ThreadState>> = RefCell::new(None));
-
-    /// Initialize the current thread state.
-    pub fn initialize(x: ThreadState) {
-        STATE.with(|ref k| {
-            if let Some(ref s) = *k.borrow() {
-                panic!("Thread state already initialized as {:?}", s);
-            }
-            *k.borrow_mut() = Some(x);
-        });
-        get(); // check the assertion below
-    }
+thread_local!(static STATE: RefCell<Option<ThreadState>> = RefCell::new(None));
 
-    /// 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
-    }
+/// Initializes the current thread state.
+pub fn initialize(x: ThreadState) {
+    STATE.with(|ref k| {
+        if let Some(ref s) = *k.borrow() {
+            panic!("Thread state already initialized as {:?}", s);
+        }
+        *k.borrow_mut() = Some(x);
+    });
+}
 
-    /// 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);
-        })
-    }
+/// Initializes the current thread as a layout worker thread.
+pub fn initialize_layout_worker_thread() {
+    initialize(LAYOUT | IN_WORKER);
 }
 
-#[cfg(not(debug_assertions))]
-#[allow(missing_docs)]
-mod imp {
-    use super::ThreadState;
-    #[inline(always)] pub fn initialize(_: ThreadState) { }
-    #[inline(always)] pub fn get() -> ThreadState { ThreadState::empty() }
-    #[inline(always)] pub fn enter(_: ThreadState) { }
-    #[inline(always)] pub fn exit(_: ThreadState) { }
+/// Gets the current thread state.
+pub fn get() -> 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);
+    })
+}