Bug 1755481: correct documentation of `nsIClipboard::getData`. r=mccr8
[gecko.git] / xpcom / threads / SchedulerGroup.cpp
blob376bd22627ad889443aa72f265869109ebe512c5
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/SchedulerGroup.h"
9 #include <utility>
11 #include "jsfriendapi.h"
12 #include "mozilla/Atomics.h"
13 #include "mozilla/Telemetry.h"
14 #include "mozilla/Unused.h"
15 #include "mozilla/dom/DocGroup.h"
16 #include "mozilla/dom/ScriptSettings.h"
17 #include "nsINamed.h"
18 #include "nsQueryObject.h"
19 #include "nsThreadUtils.h"
21 using namespace mozilla;
23 namespace {
25 static Atomic<uint64_t> gEarliestUnprocessedVsync(0);
27 } // namespace
29 /* static */
30 nsresult SchedulerGroup::UnlabeledDispatch(
31 TaskCategory aCategory, already_AddRefed<nsIRunnable>&& aRunnable) {
32 if (NS_IsMainThread()) {
33 return NS_DispatchToCurrentThread(std::move(aRunnable));
34 } else {
35 return NS_DispatchToMainThread(std::move(aRunnable));
39 /* static */
40 void SchedulerGroup::MarkVsyncReceived() {
41 // May be called on any thread when a vsync is received and scheduled to be
42 // processed. This may occur on the main thread due to queued messages when
43 // the channel is connected.
44 TimeStamp creation = TimeStamp::ProcessCreation();
46 // Attempt to set gEarliestUnprocessedVsync to our new value. If we've seen a
47 // vsync already, but haven't handled it, the `compareExchange` will fail and
48 // the static won't be updated.
49 uint64_t unprocessedVsync =
50 uint64_t((TimeStamp::Now() - creation).ToMicroseconds());
51 gEarliestUnprocessedVsync.compareExchange(0, unprocessedVsync);
54 /* static */
55 void SchedulerGroup::MarkVsyncRan() { gEarliestUnprocessedVsync = 0; }
57 SchedulerGroup::SchedulerGroup() : mIsRunning(false) {}
59 /* static */
60 nsresult SchedulerGroup::Dispatch(TaskCategory aCategory,
61 already_AddRefed<nsIRunnable>&& aRunnable) {
62 return LabeledDispatch(aCategory, std::move(aRunnable), nullptr);
65 /* static */
66 nsresult SchedulerGroup::LabeledDispatch(
67 TaskCategory aCategory, already_AddRefed<nsIRunnable>&& aRunnable,
68 mozilla::PerformanceCounter* aPerformanceCounter) {
69 nsCOMPtr<nsIRunnable> runnable(aRunnable);
70 if (XRE_IsContentProcess()) {
71 RefPtr<Runnable> internalRunnable =
72 new Runnable(runnable.forget(), aPerformanceCounter);
73 return InternalUnlabeledDispatch(aCategory, internalRunnable.forget());
75 return UnlabeledDispatch(aCategory, runnable.forget());
78 /*static*/
79 nsresult SchedulerGroup::InternalUnlabeledDispatch(
80 TaskCategory aCategory, already_AddRefed<Runnable>&& aRunnable) {
81 if (NS_IsMainThread()) {
82 // NS_DispatchToCurrentThread will not leak the passed in runnable
83 // when it fails, so we don't need to do anything special.
84 return NS_DispatchToCurrentThread(std::move(aRunnable));
87 RefPtr<Runnable> runnable(aRunnable);
88 nsresult rv = NS_DispatchToMainThread(do_AddRef(runnable));
89 if (NS_FAILED(rv)) {
90 // Dispatch failed. This is a situation where we would have used
91 // NS_DispatchToMainThread rather than calling into the SchedulerGroup
92 // machinery, and the caller would be expecting to leak the nsIRunnable
93 // originally passed in. But because we've had to wrap things up
94 // internally, we were going to leak the nsIRunnable *and* our Runnable
95 // wrapper. But there's no reason that we have to leak our Runnable
96 // wrapper; we can just leak the wrapped nsIRunnable, and let the caller
97 // take care of unleaking it if they need to.
98 Unused << runnable->mRunnable.forget().take();
99 nsrefcnt refcnt = runnable.get()->Release();
100 MOZ_RELEASE_ASSERT(refcnt == 1, "still holding an unexpected reference!");
103 return rv;
106 SchedulerGroup::Runnable::Runnable(
107 already_AddRefed<nsIRunnable>&& aRunnable,
108 mozilla::PerformanceCounter* aPerformanceCounter)
109 : mozilla::Runnable("SchedulerGroup::Runnable"),
110 mRunnable(std::move(aRunnable)),
111 mPerformanceCounter(aPerformanceCounter) {}
113 mozilla::PerformanceCounter* SchedulerGroup::Runnable::GetPerformanceCounter()
114 const {
115 return mPerformanceCounter;
118 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
119 NS_IMETHODIMP
120 SchedulerGroup::Runnable::GetName(nsACString& aName) {
121 // Try to get a name from the underlying runnable.
122 nsCOMPtr<nsINamed> named = do_QueryInterface(mRunnable);
123 if (named) {
124 named->GetName(aName);
126 if (aName.IsEmpty()) {
127 aName.AssignLiteral("anonymous");
130 return NS_OK;
132 #endif
134 NS_IMETHODIMP
135 SchedulerGroup::Runnable::Run() {
136 MOZ_RELEASE_ASSERT(NS_IsMainThread());
137 // The runnable's destructor can have side effects, so try to execute it in
138 // the scope of the SchedulerGroup.
139 nsCOMPtr<nsIRunnable> runnable(std::move(mRunnable));
140 return runnable->Run();
143 NS_IMETHODIMP
144 SchedulerGroup::Runnable::GetPriority(uint32_t* aPriority) {
145 *aPriority = nsIRunnablePriority::PRIORITY_NORMAL;
146 nsCOMPtr<nsIRunnablePriority> runnablePrio = do_QueryInterface(mRunnable);
147 return runnablePrio ? runnablePrio->GetPriority(aPriority) : NS_OK;
150 NS_IMPL_ISUPPORTS_INHERITED(SchedulerGroup::Runnable, mozilla::Runnable,
151 nsIRunnablePriority, SchedulerGroup::Runnable)