tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }