Source code

Revision control

Copy as Markdown

Other Tools

/* 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);
})
}