Skip to main content

script/dom/globalscope/
auto_close_worker.rs

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
5use std::sync::Arc;
6use std::sync::atomic::{AtomicBool, Ordering};
7use std::thread::JoinHandle;
8
9use crossbeam_channel::Sender;
10
11use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerControlMsg;
12use crate::runtime::script_runtime::ThreadSafeJSContext;
13
14#[derive(JSTraceable, MallocSizeOf)]
15pub(crate) struct AutoCloseWorker {
16    /// <https://html.spec.whatwg.org/multipage/#dom-workerglobalscope-closing>
17    #[conditional_malloc_size_of]
18    pub(super) closing: Arc<AtomicBool>,
19    #[conditional_malloc_size_of]
20    pub(super) animation_frame_provider_supported: Arc<AtomicBool>,
21    /// A handle to join on the worker thread.
22    #[ignore_malloc_size_of = "JoinHandle"]
23    pub(super) join_handle: Option<JoinHandle<()>>,
24    /// A sender of control messages.
25    #[no_trace]
26    pub(super) control_sender: Sender<DedicatedWorkerControlMsg>,
27    /// The context to request an interrupt on the worker thread.
28    #[ignore_malloc_size_of = "mozjs"]
29    #[no_trace]
30    pub(super) context: ThreadSafeJSContext,
31}
32
33impl Drop for AutoCloseWorker {
34    /// <https://html.spec.whatwg.org/multipage/#terminate-a-worker>
35    fn drop(&mut self) {
36        // Step 1. Set the worker's `WorkerGlobalScope` object's closing flag to true.
37        self.closing.store(true, Ordering::SeqCst);
38
39        if self
40            .control_sender
41            .send(DedicatedWorkerControlMsg::Exit)
42            .is_err()
43        {
44            warn!("Couldn't send an exit message to a dedicated worker.");
45        }
46
47        self.context.request_interrupt_callback();
48
49        // Step 2. If there are any tasks queued in the `WorkerGlobalScope` object's relevant agent's event loop's task queues, discard them without processing them.
50        // Step 3. Abort the script currently running in the worker.
51        // Step 4. If the worker's WorkerGlobalScope object is actually a DedicatedWorkerGlobalScope object (i.e. the worker is a dedicated worker), then empty the port message queue of the port that the worker's implicit port is entangled with.
52        // TODO Steps 2-4.
53        if self
54            .join_handle
55            .take()
56            .expect("No handle to join on worker.")
57            .join()
58            .is_err()
59        {
60            warn!("Failed to join on dedicated worker thread.");
61        }
62    }
63}