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 "PerformanceStorageWorker.h"
8 #include "Performance.h"
9 #include "PerformanceResourceTiming.h"
10 #include "PerformanceTiming.h"
11 #include "mozilla/dom/WorkerRef.h"
12 #include "mozilla/dom/WorkerRunnable.h"
13 #include "mozilla/dom/WorkerScope.h"
15 namespace mozilla::dom
{
17 class PerformanceProxyData
{
19 PerformanceProxyData(UniquePtr
<PerformanceTimingData
>&& aData
,
20 const nsAString
& aInitiatorType
,
21 const nsAString
& aEntryName
)
22 : mData(std::move(aData
)),
23 mInitiatorType(aInitiatorType
),
24 mEntryName(aEntryName
) {
25 MOZ_RELEASE_ASSERT(mData
);
28 UniquePtr
<PerformanceTimingData
> mData
; // always non-null
29 nsString mInitiatorType
;
35 // Here we use control runnable because this code must be executed also when in
37 class PerformanceEntryAdder final
: public WorkerControlRunnable
{
39 PerformanceEntryAdder(WorkerPrivate
* aWorkerPrivate
,
40 PerformanceStorageWorker
* aStorage
,
41 UniquePtr
<PerformanceProxyData
>&& aData
)
42 : WorkerControlRunnable(aWorkerPrivate
, WorkerThreadUnchangedBusyCount
),
44 mData(std::move(aData
)) {}
46 bool WorkerRun(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
) override
{
47 mStorage
->AddEntryOnWorker(std::move(mData
));
51 nsresult
Cancel() override
{
52 mStorage
->ShutdownOnWorker();
53 return WorkerRunnable::Cancel();
56 bool PreDispatch(WorkerPrivate
* aWorkerPrivate
) override
{ return true; }
58 void PostDispatch(WorkerPrivate
* aWorkerPrivate
,
59 bool aDispatchResult
) override
{}
62 RefPtr
<PerformanceStorageWorker
> mStorage
;
63 UniquePtr
<PerformanceProxyData
> mData
;
69 already_AddRefed
<PerformanceStorageWorker
> PerformanceStorageWorker::Create(
70 WorkerPrivate
* aWorkerPrivate
) {
71 MOZ_ASSERT(aWorkerPrivate
);
72 aWorkerPrivate
->AssertIsOnWorkerThread();
74 RefPtr
<PerformanceStorageWorker
> storage
= new PerformanceStorageWorker();
76 MutexAutoLock
lock(storage
->mMutex
); // for thread-safety analysis
77 storage
->mWorkerRef
= WeakWorkerRef::Create(
78 aWorkerPrivate
, [storage
]() { storage
->ShutdownOnWorker(); });
80 // PerformanceStorageWorker is created at the creation time of the worker.
81 MOZ_ASSERT(storage
->mWorkerRef
);
83 return storage
.forget();
86 PerformanceStorageWorker::PerformanceStorageWorker()
87 : mMutex("PerformanceStorageWorker::mMutex") {}
89 PerformanceStorageWorker::~PerformanceStorageWorker() = default;
91 void PerformanceStorageWorker::AddEntry(nsIHttpChannel
* aChannel
,
92 nsITimedChannel
* aTimedChannel
) {
93 MOZ_ASSERT(NS_IsMainThread());
95 MutexAutoLock
lock(mMutex
);
101 // If we have mWorkerRef, we haven't received the WorkerRef notification and
102 // we haven't yet call ShutdownOnWorker, which uses the mutex.
103 WorkerPrivate
* workerPrivate
= mWorkerRef
->GetUnsafePrivate();
104 MOZ_ASSERT(workerPrivate
);
106 nsAutoString initiatorType
;
107 nsAutoString entryName
;
109 UniquePtr
<PerformanceTimingData
> performanceTimingData(
110 PerformanceTimingData::Create(aTimedChannel
, aChannel
, 0, initiatorType
,
112 if (!performanceTimingData
) {
116 UniquePtr
<PerformanceProxyData
> data(new PerformanceProxyData(
117 std::move(performanceTimingData
), initiatorType
, entryName
));
119 RefPtr
<PerformanceEntryAdder
> r
=
120 new PerformanceEntryAdder(workerPrivate
, this, std::move(data
));
121 Unused
<< NS_WARN_IF(!r
->Dispatch());
124 void PerformanceStorageWorker::AddEntry(
125 const nsString
& aEntryName
, const nsString
& aInitiatorType
,
126 UniquePtr
<PerformanceTimingData
>&& aData
) {
127 MOZ_ASSERT(!NS_IsMainThread());
132 UniquePtr
<PerformanceProxyData
> data
= MakeUnique
<PerformanceProxyData
>(
133 std::move(aData
), aInitiatorType
, aEntryName
);
135 AddEntryOnWorker(std::move(data
));
138 void PerformanceStorageWorker::ShutdownOnWorker() {
139 MutexAutoLock
lock(mMutex
);
145 MOZ_ASSERT(!NS_IsMainThread());
147 mWorkerRef
= nullptr;
150 void PerformanceStorageWorker::AddEntryOnWorker(
151 UniquePtr
<PerformanceProxyData
>&& aData
) {
152 RefPtr
<Performance
> performance
;
153 UniquePtr
<PerformanceProxyData
> data
= std::move(aData
);
156 MutexAutoLock
lock(mMutex
);
162 // We must have the workerPrivate because it is available until a
163 // notification is received by WorkerRef and we use mutex to make the code
165 WorkerPrivate
* workerPrivate
= mWorkerRef
->GetPrivate();
166 MOZ_ASSERT(workerPrivate
);
168 WorkerGlobalScope
* scope
= workerPrivate
->GlobalScope();
169 performance
= scope
->GetPerformance();
172 if (NS_WARN_IF(!performance
)) {
176 RefPtr
<PerformanceResourceTiming
> performanceEntry
=
177 new PerformanceResourceTiming(std::move(data
->mData
), performance
,
179 performanceEntry
->SetInitiatorType(data
->mInitiatorType
);
181 performance
->InsertResourceEntry(performanceEntry
);
184 } // namespace mozilla::dom