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