Bug 1858509 add thread-safety annotations around MediaSourceDemuxer::mMonitor r=alwu
[gecko.git] / widget / PrintBackgroundTask.h
blob8b18c8a879f8c1f279bc0eb970e8cc524e3166ad
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_PrintBackgroundTask_h_
7 #define mozilla_PrintBackgroundTask_h_
9 #include "mozilla/dom/Promise.h"
10 #include "mozilla/ErrorResult.h"
11 #include "mozilla/Telemetry.h"
13 #include <tuple>
14 #include <utility>
16 // A helper to resolve a DOM Promise with the result of a const method, executed
17 // in another thread.
19 // Once in the main thread, the caller can turn the result of the method into a
20 // JSValue by specializing ResolveOrReject.
21 namespace mozilla {
23 template <typename T, typename Result>
24 void ResolveOrReject(dom::Promise& aPromise, T&, Result& aResult) {
25 aPromise.MaybeResolve(std::forward<Result>(aResult));
28 template <typename T, typename Result, typename... Args>
29 using PrintBackgroundTask = Result (T::*)(Args...) const;
31 template <typename T, typename Result, typename... Args>
32 void SpawnPrintBackgroundTask(
33 T& aReceiver, dom::Promise& aPromise, const nsCString& aTelemetryKey,
34 PrintBackgroundTask<T, Result, Args...> aBackgroundTask, Args... aArgs) {
35 auto promiseHolder = MakeRefPtr<nsMainThreadPtrHolder<dom::Promise>>(
36 "nsPrinterBase::SpawnBackgroundTaskPromise", &aPromise);
37 // We actually want to allow to access the printer data from the callback, so
38 // disable strict checking. They should of course only access immutable
39 // members.
40 auto holder = MakeRefPtr<nsMainThreadPtrHolder<T>>(
41 "nsPrinterBase::SpawnBackgroundTaskPrinter", &aReceiver,
42 /* strict = */ false);
43 // See
44 // https://stackoverflow.com/questions/47496358/c-lambdas-how-to-capture-variadic-parameter-pack-from-the-upper-scope
45 // about the tuple shenanigans. It could be improved with C++20
46 NS_DispatchBackgroundTask(
47 NS_NewRunnableFunction(
48 "SpawnPrintBackgroundTask",
49 [holder = std::move(holder), promiseHolder = std::move(promiseHolder),
50 aTelemetryKey, startRoundTrip = TimeStamp::Now(),
51 backgroundTask = aBackgroundTask,
52 aArgs = std::make_tuple(std::forward<Args>(aArgs)...)] {
53 auto start = TimeStamp::Now();
54 Result result = std::apply(
55 [&](auto&&... args) {
56 return (holder->get()->*backgroundTask)(args...);
58 std::move(aArgs));
59 Telemetry::AccumulateTimeDelta(
60 Telemetry::PRINT_BACKGROUND_TASK_TIME_MS, aTelemetryKey, start);
61 NS_DispatchToMainThread(NS_NewRunnableFunction(
62 "SpawnPrintBackgroundTaskResolution",
63 [holder = std::move(holder),
64 promiseHolder = std::move(promiseHolder),
65 telemetryKey = std::move(aTelemetryKey), startRoundTrip,
66 result = std::move(result)] {
67 Telemetry::AccumulateTimeDelta(
68 Telemetry::PRINT_BACKGROUND_TASK_ROUND_TRIP_TIME_MS,
69 telemetryKey, startRoundTrip);
70 ResolveOrReject(*promiseHolder->get(), *holder->get(),
71 result);
72 }));
73 }),
74 NS_DISPATCH_EVENT_MAY_BLOCK);
77 // Gets a fresh promise into aResultPromise, that resolves whenever the print
78 // background task finishes.
79 template <typename T, typename Result, typename... Args>
80 nsresult PrintBackgroundTaskPromise(
81 T& aReceiver, JSContext* aCx, dom::Promise** aResultPromise,
82 const nsCString& aTelemetryKey,
83 PrintBackgroundTask<T, Result, Args...> aTask, Args... aArgs) {
84 ErrorResult rv;
85 RefPtr<dom::Promise> promise =
86 dom::Promise::Create(xpc::CurrentNativeGlobal(aCx), rv);
87 if (MOZ_UNLIKELY(rv.Failed())) {
88 return rv.StealNSResult();
91 SpawnPrintBackgroundTask(aReceiver, *promise, aTelemetryKey, aTask,
92 std::forward<Args>(aArgs)...);
94 promise.forget(aResultPromise);
95 return NS_OK;
98 // Resolves an async attribute via a background task, creating and storing a
99 // promise as needed in aPromiseSlot.
100 template <typename T, typename Result, typename... Args>
101 nsresult AsyncPromiseAttributeGetter(
102 T& aReceiver, RefPtr<dom::Promise>& aPromiseSlot, JSContext* aCx,
103 dom::Promise** aResultPromise, const nsCString& aTelemetryKey,
104 PrintBackgroundTask<T, Result, Args...> aTask, Args... aArgs) {
105 if (RefPtr<dom::Promise> existing = aPromiseSlot) {
106 existing.forget(aResultPromise);
107 return NS_OK;
110 nsresult rv =
111 PrintBackgroundTaskPromise(aReceiver, aCx, aResultPromise, aTelemetryKey,
112 aTask, std::forward<Args>(aArgs)...);
113 NS_ENSURE_SUCCESS(rv, rv);
115 aPromiseSlot = *aResultPromise;
116 return NS_OK;
119 } // namespace mozilla
121 #endif