thread_state.rs (2782B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! Supports dynamic assertions about what sort of thread is running and 6 //! what state it's in. 7 8 #![deny(missing_docs)] 9 10 use std::cell::Cell; 11 12 bitflags! { 13 /// A thread state flag, used for multiple assertions. 14 #[derive(Clone, Copy, Default, Debug, Eq, PartialEq)] 15 pub struct ThreadState: u32 { 16 /// Whether we're in a script thread. 17 const SCRIPT = 0x01; 18 /// Whether we're in a layout thread. 19 const LAYOUT = 0x02; 20 21 /// Whether we're in a script worker thread (actual web workers), or in 22 /// a layout worker thread. 23 const IN_WORKER = 0x0100; 24 25 /// Whether the current thread is going through a GC. 26 const IN_GC = 0x0200; 27 } 28 } 29 30 impl ThreadState { 31 /// Whether the current thread is a worker thread. 32 pub fn is_worker(self) -> bool { 33 self.contains(ThreadState::IN_WORKER) 34 } 35 36 /// Whether the current thread is a script thread. 37 pub fn is_script(self) -> bool { 38 self.contains(ThreadState::SCRIPT) 39 } 40 41 /// Whether the current thread is a layout thread. 42 pub fn is_layout(self) -> bool { 43 self.contains(ThreadState::LAYOUT) 44 } 45 } 46 47 thread_local!(static STATE: Cell<Option<ThreadState>> = const { Cell::new(None) }); 48 49 /// Initializes the current thread state. 50 pub fn initialize(initialize_to: ThreadState) { 51 STATE.with(|state| { 52 if let Some(current_state) = state.get() { 53 if initialize_to != current_state { 54 panic!("Thread state already initialized as {:?}", current_state); 55 } 56 } 57 state.set(Some(initialize_to)); 58 }); 59 } 60 61 /// Initializes the current thread as a layout worker thread. 62 pub fn initialize_layout_worker_thread() { 63 initialize(ThreadState::LAYOUT | ThreadState::IN_WORKER); 64 } 65 66 /// Gets the current thread state. 67 pub fn get() -> ThreadState { 68 STATE.with(|state| state.get().unwrap_or_default()) 69 } 70 71 /// Enters into a given temporary state. Panics if re-entering. 72 pub fn enter(additional_flags: ThreadState) { 73 STATE.with(|state| { 74 let current_state = state.get().unwrap_or_default(); 75 debug_assert!(!current_state.intersects(additional_flags)); 76 state.set(Some(current_state | additional_flags)); 77 }) 78 } 79 80 /// Exits a given temporary state. 81 pub fn exit(flags_to_remove: ThreadState) { 82 STATE.with(|state| { 83 let current_state = state.get().unwrap_or_default(); 84 debug_assert!(current_state.contains(flags_to_remove)); 85 state.set(Some(current_state & !flags_to_remove)); 86 }) 87 }