Bug 1638929 - Expose `NS_DispatchBackgroundTask` to `moz_task`. r=KrisWright
authorLina Cambridge <lina@yakshaving.ninja>
Wed, 20 May 2020 20:54:11 +0000
changeset 531332 87b6bc1c13222b570d79a4228f334d8e20d794fe
parent 531331 e4cd52e972162f3ae572553bf8e640d9af25e185
child 531333 767dac9c6d2b6fdcc8ca4a8cdbf31a9b31d03d53
push id37438
push userabutkovits@mozilla.com
push dateThu, 21 May 2020 09:36:57 +0000
treeherdermozilla-central@2d00a1a6495c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersKrisWright
bugs1638929
milestone78.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1638929 - Expose `NS_DispatchBackgroundTask` to `moz_task`. r=KrisWright Differential Revision: https://phabricator.services.mozilla.com/D75838
xpcom/rust/moz_task/src/lib.rs
xpcom/threads/nsThreadUtils.cpp
xpcom/threads/nsThreadUtils.h
--- a/xpcom/rust/moz_task/src/lib.rs
+++ b/xpcom/rust/moz_task/src/lib.rs
@@ -41,16 +41,17 @@ extern "C" {
         target: *const nsIEventTarget,
         doomed: *const nsISupports,
         always_proxy: bool,
     );
     fn NS_CreateBackgroundTaskQueue(
         name: *const libc::c_char,
         target: *mut *const nsISerialEventTarget,
     ) -> nsresult;
+    fn NS_DispatchBackgroundTask(event: *const nsIRunnable, flags: u32) -> nsresult;
 }
 
 pub fn get_current_thread() -> Result<RefPtr<nsIThread>, nsresult> {
     getter_addrefs(|p| unsafe { NS_GetCurrentThreadEventTarget(p) })
 }
 
 pub fn get_main_thread() -> Result<RefPtr<nsIThread>, nsresult> {
     getter_addrefs(|p| unsafe { NS_GetMainThreadEventTarget(p) })
@@ -65,22 +66,52 @@ pub fn create_thread(name: &str) -> Resu
         NS_NewNamedThreadWithDefaultStackSize(&*nsCString::from(name), p, ptr::null())
     })
 }
 
 pub fn is_current_thread(thread: &nsIThread) -> bool {
     unsafe { NS_IsCurrentThread(thread.coerce()) }
 }
 
+/// Creates a queue that runs tasks on the background thread pool. The tasks
+/// will run in the order they're dispatched, one after the other.
 pub fn create_background_task_queue(
     name: &'static CStr,
 ) -> Result<RefPtr<nsISerialEventTarget>, nsresult> {
     getter_addrefs(|p| unsafe { NS_CreateBackgroundTaskQueue(name.as_ptr(), p) })
 }
 
+/// Dispatches a one-shot task runnable to the background thread pool with the
+/// default options.
+#[inline]
+pub fn dispatch_background_task(runnable: RefPtr<nsIRunnable>) -> Result<(), nsresult> {
+    dispatch_background_task_with_options(runnable, DispatchOptions::default())
+}
+
+/// Dispatches a one-shot task runnable to the background thread pool with the
+/// given options. The task may run concurrently with other background tasks.
+/// If you need tasks to run in a specific order, please create a background
+/// task queue using `create_background_task_queue`, and dispatch tasks to it
+/// instead.
+///
+/// ### Safety
+///
+/// This function leaks the runnable if dispatch fails. This avoids a race where
+/// a runnable can be destroyed on either the original or target thread, which
+/// is important if the runnable holds thread-unsafe members.
+pub fn dispatch_background_task_with_options(
+    runnable: RefPtr<nsIRunnable>,
+    options: DispatchOptions,
+) -> Result<(), nsresult> {
+    // This eventually calls the non-`already_AddRefed<nsIRunnable>` overload of
+    // `nsIEventTarget::Dispatch` (see xpcom/threads/nsIEventTarget.idl#20-25),
+    // which adds an owning reference and leaks if dispatch fails.
+    unsafe { NS_DispatchBackgroundTask(runnable.coerce(), options.flags()) }.to_result()
+}
+
 /// Options to control how task runnables are dispatched.
 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
 pub struct DispatchOptions(u32);
 
 impl Default for DispatchOptions {
     #[inline]
     fn default() -> Self {
         DispatchOptions(nsIEventTarget::DISPATCH_NORMAL as u32)
--- a/xpcom/threads/nsThreadUtils.cpp
+++ b/xpcom/threads/nsThreadUtils.cpp
@@ -535,22 +535,16 @@ nsCString nsThreadPoolNaming::GetNextThr
 
 nsresult NS_DispatchBackgroundTask(already_AddRefed<nsIRunnable> aEvent,
                                    uint32_t aDispatchFlags) {
   nsCOMPtr<nsIRunnable> event(aEvent);
   return nsThreadManager::get().DispatchToBackgroundThread(event,
                                                            aDispatchFlags);
 }
 
-nsresult NS_DispatchBackgroundTask(nsIRunnable* aEvent,
-                                   uint32_t aDispatchFlags) {
-  return nsThreadManager::get().DispatchToBackgroundThread(aEvent,
-                                                           aDispatchFlags);
-}
-
 // nsAutoLowPriorityIO
 nsAutoLowPriorityIO::nsAutoLowPriorityIO() {
 #if defined(XP_WIN)
   lowIOPrioritySet =
       SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
 #elif defined(XP_MACOSX)
   oldPriority = getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD);
   lowIOPrioritySet =
@@ -675,16 +669,22 @@ nsresult NS_NewNamedThreadWithDefaultSta
                                                nsIRunnable* aEvent) {
   return NS_NewNamedThread(aName, aResult, aEvent);
 }
 
 bool NS_IsCurrentThread(nsIEventTarget* aThread) {
   return aThread->IsOnCurrentThread();
 }
 
+nsresult NS_DispatchBackgroundTask(nsIRunnable* aEvent,
+                                   uint32_t aDispatchFlags) {
+  return nsThreadManager::get().DispatchToBackgroundThread(aEvent,
+                                                           aDispatchFlags);
+}
+
 nsresult NS_CreateBackgroundTaskQueue(const char* aName,
                                       nsISerialEventTarget** aTarget) {
   nsCOMPtr<nsISerialEventTarget> target =
       nsThreadManager::get().CreateBackgroundTaskQueue(aName);
   if (!target) {
     return NS_ERROR_FAILURE;
   }
 
--- a/xpcom/threads/nsThreadUtils.h
+++ b/xpcom/threads/nsThreadUtils.h
@@ -1762,17 +1762,17 @@ extern mozilla::TimeStamp NS_GetTimerDea
  * serially, in dispatch order; several dispatched events may run in parallel.
  * If you depend on serial execution of dispatched events, you should use
  * NS_CreateBackgroundTaskQueue instead, and dispatch events to the returned
  * event target.
  */
 extern nsresult NS_DispatchBackgroundTask(
     already_AddRefed<nsIRunnable> aEvent,
     uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
-extern nsresult NS_DispatchBackgroundTask(
+extern "C" nsresult NS_DispatchBackgroundTask(
     nsIRunnable* aEvent, uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
 
 /**
  * Obtain a new serial event target that dispatches runnables to a background
  * thread.  In many cases, this is a straight replacement for creating your
  * own, private thread, and is generally preferred to creating your own,
  * private thread.
  */