From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- xpcom/rust/moz_task/src/event_loop.rs | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 xpcom/rust/moz_task/src/event_loop.rs (limited to 'xpcom/rust/moz_task/src/event_loop.rs') diff --git a/xpcom/rust/moz_task/src/event_loop.rs b/xpcom/rust/moz_task/src/event_loop.rs new file mode 100644 index 0000000000..f8d113ed57 --- /dev/null +++ b/xpcom/rust/moz_task/src/event_loop.rs @@ -0,0 +1,66 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +extern crate nsstring; + +use cstr::cstr; +use nserror::{nsresult, NS_ERROR_SERVICE_NOT_AVAILABLE, NS_ERROR_UNEXPECTED, NS_OK}; +use nsstring::*; +use std::cell::RefCell; +use std::future::Future; +use xpcom::{interfaces::nsIThreadManager, xpcom, xpcom_method}; + +#[xpcom(implement(nsINestedEventLoopCondition), nonatomic)] +struct FutureCompleteCondition { + value: RefCell>, +} + +impl FutureCompleteCondition { + xpcom_method!(is_done => IsDone() -> bool); + fn is_done(&self) -> Result { + Ok(self.value.borrow().is_some()) + } +} + +/// Spin the event loop on the current thread until `future` is resolved. +/// +/// # Safety +/// +/// Spinning a nested event loop should always be avoided when possible, as it +/// can cause hangs, break JS run-to-completion guarantees, and break other C++ +/// code currently on the stack relying on heap invariants. While in a pure-rust +/// codebase this method would only be ill-advised and not technically "unsafe", +/// it is marked as unsafe due to the potential for triggering unsafety in +/// unrelated C++ code. +pub unsafe fn spin_event_loop_until( + reason: &'static str, + future: F, +) -> Result +where + F: Future + 'static, + F::Output: 'static, +{ + let thread_manager = + xpcom::get_service::(cstr!("@mozilla.org/thread-manager;1")) + .ok_or(NS_ERROR_SERVICE_NOT_AVAILABLE)?; + + let cond = FutureCompleteCondition::::allocate(InitFutureCompleteCondition { + value: RefCell::new(None), + }); + + // Spawn our future onto the current thread event loop, and record the + // completed value as it completes. + let cond2 = cond.clone(); + crate::spawn_local(reason, async move { + let rv = future.await; + *cond2.value.borrow_mut() = Some(rv); + }) + .detach(); + + thread_manager + .SpinEventLoopUntil(&*nsCStr::from(reason), cond.coerce()) + .to_result()?; + let rv = cond.value.borrow_mut().take(); + rv.ok_or(NS_ERROR_UNEXPECTED) +} -- cgit v1.2.3