PerformanceStorageWorker.cpp (5537B)
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/. */ 6 7 #include "PerformanceStorageWorker.h" 8 9 #include "Performance.h" 10 #include "PerformanceResourceTiming.h" 11 #include "PerformanceTiming.h" 12 #include "mozilla/dom/WorkerRef.h" 13 #include "mozilla/dom/WorkerRunnable.h" 14 #include "mozilla/dom/WorkerScope.h" 15 16 namespace mozilla::dom { 17 18 class PerformanceProxyData { 19 public: 20 PerformanceProxyData(UniquePtr<PerformanceTimingData>&& aData, 21 const nsAString& aInitiatorType, 22 const nsAString& aEntryName) 23 : mData(std::move(aData)), 24 mInitiatorType(aInitiatorType), 25 mEntryName(aEntryName) { 26 MOZ_RELEASE_ASSERT(mData); 27 } 28 29 UniquePtr<PerformanceTimingData> mData; // always non-null 30 nsString mInitiatorType; 31 nsString mEntryName; 32 }; 33 34 namespace { 35 36 // Here we use control runnable because this code must be executed also when in 37 // a sync event loop 38 class PerformanceEntryAdder final : public WorkerControlRunnable { 39 public: 40 PerformanceEntryAdder(WorkerPrivate* aWorkerPrivate, 41 PerformanceStorageWorker* aStorage, 42 UniquePtr<PerformanceProxyData>&& aData) 43 : WorkerControlRunnable("PerformanceEntryAdder"), 44 mStorage(aStorage), 45 mData(std::move(aData)) {} 46 47 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { 48 mStorage->AddEntryOnWorker(std::move(mData)); 49 return true; 50 } 51 52 nsresult Cancel() override { 53 mStorage->ShutdownOnWorker(); 54 return NS_OK; 55 } 56 57 bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { return true; } 58 59 void PostDispatch(WorkerPrivate* aWorkerPrivate, 60 bool aDispatchResult) override {} 61 62 private: 63 RefPtr<PerformanceStorageWorker> mStorage; 64 UniquePtr<PerformanceProxyData> mData; 65 }; 66 67 } // namespace 68 69 /* static */ 70 already_AddRefed<PerformanceStorageWorker> PerformanceStorageWorker::Create( 71 WorkerPrivate* aWorkerPrivate) { 72 MOZ_ASSERT(aWorkerPrivate); 73 aWorkerPrivate->AssertIsOnWorkerThread(); 74 75 RefPtr<PerformanceStorageWorker> storage = new PerformanceStorageWorker(); 76 77 MutexAutoLock lock(storage->mMutex); // for thread-safety analysis 78 storage->mWorkerRef = WeakWorkerRef::Create( 79 aWorkerPrivate, [storage]() { storage->ShutdownOnWorker(); }); 80 81 // PerformanceStorageWorker is created at the creation time of the worker. 82 MOZ_ASSERT(storage->mWorkerRef); 83 84 return storage.forget(); 85 } 86 87 PerformanceStorageWorker::PerformanceStorageWorker() 88 : mMutex("PerformanceStorageWorker::mMutex") {} 89 90 PerformanceStorageWorker::~PerformanceStorageWorker() = default; 91 92 void PerformanceStorageWorker::AddEntry(nsIHttpChannel* aChannel, 93 nsITimedChannel* aTimedChannel) { 94 MOZ_ASSERT(NS_IsMainThread()); 95 96 MutexAutoLock lock(mMutex); 97 98 if (!mWorkerRef) { 99 return; 100 } 101 102 // If we have mWorkerRef, we haven't received the WorkerRef notification and 103 // we haven't yet call ShutdownOnWorker, which uses the mutex. 104 WorkerPrivate* workerPrivate = mWorkerRef->GetUnsafePrivate(); 105 MOZ_ASSERT(workerPrivate); 106 107 nsAutoString initiatorType; 108 nsAutoString entryName; 109 110 UniquePtr<PerformanceTimingData> performanceTimingData( 111 PerformanceTimingData::Create(aTimedChannel, aChannel, 0, initiatorType, 112 entryName)); 113 if (!performanceTimingData) { 114 return; 115 } 116 117 UniquePtr<PerformanceProxyData> data(new PerformanceProxyData( 118 std::move(performanceTimingData), initiatorType, entryName)); 119 120 RefPtr<PerformanceEntryAdder> r = 121 new PerformanceEntryAdder(workerPrivate, this, std::move(data)); 122 (void)NS_WARN_IF(!r->Dispatch(workerPrivate)); 123 } 124 125 void PerformanceStorageWorker::AddEntry( 126 const nsString& aEntryName, const nsString& aInitiatorType, 127 UniquePtr<PerformanceTimingData>&& aData) { 128 MOZ_ASSERT(!NS_IsMainThread()); 129 if (!aData) { 130 return; 131 } 132 133 UniquePtr<PerformanceProxyData> data = MakeUnique<PerformanceProxyData>( 134 std::move(aData), aInitiatorType, aEntryName); 135 136 AddEntryOnWorker(std::move(data)); 137 } 138 139 void PerformanceStorageWorker::ShutdownOnWorker() { 140 MutexAutoLock lock(mMutex); 141 142 if (!mWorkerRef) { 143 return; 144 } 145 146 MOZ_ASSERT(!NS_IsMainThread()); 147 148 mWorkerRef = nullptr; 149 } 150 151 void PerformanceStorageWorker::AddEntryOnWorker( 152 UniquePtr<PerformanceProxyData>&& aData) { 153 RefPtr<Performance> performance; 154 UniquePtr<PerformanceProxyData> data = std::move(aData); 155 156 { 157 MutexAutoLock lock(mMutex); 158 159 if (!mWorkerRef) { 160 return; 161 } 162 163 // We must have the workerPrivate because it is available until a 164 // notification is received by WorkerRef and we use mutex to make the code 165 // protected. 166 WorkerPrivate* workerPrivate = mWorkerRef->GetPrivate(); 167 MOZ_ASSERT(workerPrivate); 168 169 WorkerGlobalScope* scope = workerPrivate->GlobalScope(); 170 performance = scope->GetPerformance(); 171 } 172 173 if (NS_WARN_IF(!performance)) { 174 return; 175 } 176 177 RefPtr<PerformanceResourceTiming> performanceEntry = 178 new PerformanceResourceTiming(std::move(data->mData), performance, 179 data->mEntryName); 180 performanceEntry->SetInitiatorType(data->mInitiatorType); 181 182 performance->InsertResourceEntry(performanceEntry); 183 } 184 185 } // namespace mozilla::dom