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 in about what sort of thread is running and 6 //! what state it's in. 7 8 #![deny(missing_docs)] 9 10 use std::cell::RefCell; 11 12 bitflags! { 13 /// A thread state flag, used for multiple assertions. 14 pub struct ThreadState: u32 { 15 /// Whether we're in a script thread. 16 const SCRIPT = 0x01; 17 /// Whether we're in a layout thread. 18 const LAYOUT = 0x02; 19 20 /// Whether we're in a script worker thread (actual web workers), or in 21 /// a layout worker thread. 22 const IN_WORKER = 0x0100; 23 24 /// Whether the current thread is going through a GC. 25 const IN_GC = 0x0200; 26 } 27 } 28 29 macro_rules! thread_types ( ( $( $fun:ident = $flag:path ; )* ) => ( 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 $( 37 #[allow(missing_docs)] 38 pub fn $fun(self) -> bool { 39 self.contains($flag) 40 } 41 )* 42 } 43 )); 44 45 thread_types! { 46 is_script = ThreadState::SCRIPT; 47 is_layout = ThreadState::LAYOUT; 48 } 49 50 thread_local!(static STATE: RefCell<Option<ThreadState>> = RefCell::new(None)); 51 52 /// Initializes the current thread state. initialize(x: ThreadState)53pub fn initialize(x: ThreadState) { 54 STATE.with(|ref k| { 55 if let Some(ref s) = *k.borrow() { 56 if x != *s { 57 panic!("Thread state already initialized as {:?}", s); 58 } 59 } 60 *k.borrow_mut() = Some(x); 61 }); 62 } 63 64 /// Initializes the current thread as a layout worker thread. initialize_layout_worker_thread()65pub fn initialize_layout_worker_thread() { 66 initialize(ThreadState::LAYOUT | ThreadState::IN_WORKER); 67 } 68 69 /// Gets the current thread state. get() -> ThreadState70pub fn get() -> ThreadState { 71 let state = STATE.with(|ref k| { 72 match *k.borrow() { 73 None => ThreadState::empty(), // Unknown thread. 74 Some(s) => s, 75 } 76 }); 77 78 state 79 } 80 81 /// Enters into a given temporary state. Panics if re-entring. enter(x: ThreadState)82pub fn enter(x: ThreadState) { 83 let state = get(); 84 debug_assert!(!state.intersects(x)); 85 STATE.with(|ref k| { 86 *k.borrow_mut() = Some(state | x); 87 }) 88 } 89 90 /// Exits a given temporary state. exit(x: ThreadState)91pub fn exit(x: ThreadState) { 92 let state = get(); 93 debug_assert!(state.contains(x)); 94 STATE.with(|ref k| { 95 *k.borrow_mut() = Some(state & !x); 96 }) 97 } 98