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}