blob: e07a567fe726e2505eee4abedb108bf82e8a9526 (
plain)
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);
})
}
|