/src/mozilla-central/dom/media/doctor/DDMediaLogs.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
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 | | #ifndef DDMediaLogs_h_ |
8 | | #define DDMediaLogs_h_ |
9 | | |
10 | | #include "DDLifetimes.h" |
11 | | #include "DDMediaLog.h" |
12 | | #include "mozilla/MozPromise.h" |
13 | | #include "MultiWriterQueue.h" |
14 | | |
15 | | namespace mozilla { |
16 | | |
17 | | // Main object managing all processed logs, and yet-unprocessed messages. |
18 | | struct DDMediaLogs |
19 | | { |
20 | | public: |
21 | | // Construct a DDMediaLogs object if possible. |
22 | | struct ConstructionResult |
23 | | { |
24 | | nsresult mRv; |
25 | | DDMediaLogs* mMediaLogs; |
26 | | }; |
27 | | static ConstructionResult New(); |
28 | | |
29 | | // If not already shutdown, performs normal end-of-life processing, and shuts |
30 | | // down the processing thread (blocking). |
31 | | ~DDMediaLogs(); |
32 | | |
33 | | // Shutdown the processing thread (blocking), and free as much memory as |
34 | | // possible. |
35 | | void Panic(); |
36 | | |
37 | | inline void Log(const char* aSubjectTypeName, |
38 | | const void* aSubjectPointer, |
39 | | DDLogCategory aCategory, |
40 | | const char* aLabel, |
41 | | DDLogValue&& aValue) |
42 | 0 | { |
43 | 0 | if (mMessagesQueue.PushF( |
44 | 0 | [&](DDLogMessage& aMessage, MessagesQueue::Index i) { |
45 | 0 | aMessage.mIndex = i; |
46 | 0 | aMessage.mTimeStamp = DDNow(); |
47 | 0 | aMessage.mObject.Set(aSubjectTypeName, aSubjectPointer); |
48 | 0 | aMessage.mCategory = aCategory; |
49 | 0 | aMessage.mLabel = aLabel; |
50 | 0 | aMessage.mValue = std::move(aValue); |
51 | 0 | })) { |
52 | 0 | // Filled a buffer-full of messages, process it in another thread. |
53 | 0 | DispatchProcessLog(); |
54 | 0 | } |
55 | 0 | } |
56 | | |
57 | | // Process the log right now; should only be used on the processing thread, |
58 | | // or after shutdown for end-of-life log retrieval. Work includes: |
59 | | // - Processing incoming buffers, to update object lifetimes and links; |
60 | | // - Resolve pending promises that requested logs; |
61 | | // - Clean-up old logs from memory. |
62 | | void ProcessLog(); |
63 | | |
64 | | using LogMessagesPromise = |
65 | | MozPromise<nsCString, nsresult, /* IsExclusive = */ true>; |
66 | | |
67 | | // Retrieve all messages associated with an HTMLMediaElement. |
68 | | // This will trigger an async processing run (to ensure most recent messages |
69 | | // get retrieved too), and the returned promise will be resolved with all |
70 | | // found log messages. |
71 | | RefPtr<LogMessagesPromise> RetrieveMessages( |
72 | | const dom::HTMLMediaElement* aMediaElement); |
73 | | |
74 | | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; |
75 | | |
76 | | private: |
77 | | // Constructor, takes the given thread to use for log processing. |
78 | | explicit DDMediaLogs(nsCOMPtr<nsIThread>&& aThread); |
79 | | |
80 | | // Shutdown the processing thread, blocks until that thread exits. |
81 | | // If aPanic is true, just free as much memory as possible. |
82 | | // Otherwise, perform a final processing run, output end-logs (if enabled). |
83 | | void Shutdown(bool aPanic); |
84 | | |
85 | | // Get the log of yet-unassociated messages. |
86 | | DDMediaLog& LogForUnassociatedMessages(); |
87 | | const DDMediaLog& LogForUnassociatedMessages() const; |
88 | | |
89 | | // Get the log for the given HTMLMediaElement. Returns nullptr if there is no |
90 | | // such log yet. |
91 | | DDMediaLog* GetLogFor(const dom::HTMLMediaElement* aMediaElement); |
92 | | |
93 | | // Get the log for the given HTMLMediaElement. |
94 | | // A new log is created if that element didn't already have one. |
95 | | DDMediaLog& LogFor(const dom::HTMLMediaElement* aMediaElement); |
96 | | |
97 | | // Associate a lifetime, and all its already-linked lifetimes, with an |
98 | | // HTMLMediaElement. |
99 | | // All messages involving the modified lifetime(s) are moved to the |
100 | | // corresponding log. |
101 | | void SetMediaElement(DDLifetime& aLifetime, |
102 | | const dom::HTMLMediaElement* aMediaElement); |
103 | | |
104 | | // Find the lifetime corresponding to an object (known type and pointer) that |
105 | | // was known to be alive at aIndex. |
106 | | // If there is no such lifetime yet, create it with aTimeStamp as implicit |
107 | | // construction timestamp. |
108 | | // If the object is of type HTMLMediaElement, run SetMediaElement() on it. |
109 | | DDLifetime& FindOrCreateLifetime(const DDLogObject& aObject, |
110 | | DDMessageIndex aIndex, |
111 | | const DDTimeStamp& aTimeStamp); |
112 | | |
113 | | // Link two lifetimes together (at a given time corresponding to aIndex). |
114 | | // If only one is associated with an HTMLMediaElement, run SetMediaElement on |
115 | | // the other one. |
116 | | void LinkLifetimes(DDLifetime& aParentLifetime, |
117 | | const char* aLinkName, |
118 | | DDLifetime& aChildLifetime, |
119 | | DDMessageIndex aIndex); |
120 | | |
121 | | // Unlink all lifetimes linked to aLifetime; only used to know when links |
122 | | // expire, so that they won't be used after this time. |
123 | | void UnlinkLifetime(DDLifetime& aLifetime, DDMessageIndex aIndex); |
124 | | |
125 | | // Unlink two lifetimes; only used to know when a link expires, so that it |
126 | | // won't be used after this time. |
127 | | void UnlinkLifetimes(DDLifetime& aParentLifetime, |
128 | | DDLifetime& aChildLifetime, |
129 | | DDMessageIndex aIndex); |
130 | | |
131 | | // Remove all links involving aLifetime from the database. |
132 | | void DestroyLifetimeLinks(const DDLifetime& aLifetime); |
133 | | |
134 | | // Process all incoming log messages. |
135 | | // This will create the appropriate DDLifetime and links objects, and then |
136 | | // move processed messages to logs associated with different |
137 | | // HTMLMediaElements. |
138 | | void ProcessBuffer(); |
139 | | |
140 | | // Pending promises (added by RetrieveMessages) are resolved with all new |
141 | | // log messages corresponding to requested HTMLMediaElements -- These |
142 | | // messages are removed from our logs. |
143 | | void FulfillPromises(); |
144 | | |
145 | | // Remove processed messages that have a low chance of being requested, |
146 | | // based on the assumption that users/scripts will regularly call |
147 | | // RetrieveMessages for HTMLMediaElements they are interested in. |
148 | | void CleanUpLogs(); |
149 | | |
150 | | // Request log-processing on the processing thread. Thread-safe. |
151 | | nsresult DispatchProcessLog(); |
152 | | |
153 | | // Request log-processing on the processing thread. |
154 | | nsresult DispatchProcessLog(const MutexAutoLock& aProofOfLock); |
155 | | |
156 | | using MessagesQueue = MultiWriterQueue<DDLogMessage, |
157 | | MultiWriterQueueDefaultBufferSize, |
158 | | MultiWriterQueueReaderLocking_None>; |
159 | | MessagesQueue mMessagesQueue; |
160 | | |
161 | | DDLifetimes mLifetimes; |
162 | | |
163 | | // mMediaLogs[0] contains unsorted message (with mMediaElement=nullptr). |
164 | | // mMediaLogs[1+] contains sorted messages for each media element. |
165 | | nsTArray<DDMediaLog> mMediaLogs; |
166 | | |
167 | | struct DDObjectLink |
168 | | { |
169 | | const DDLogObject mParent; |
170 | | const DDLogObject mChild; |
171 | | const char* const mLinkName; |
172 | | const DDMessageIndex mLinkingIndex; |
173 | | Maybe<DDMessageIndex> mUnlinkingIndex; |
174 | | |
175 | | DDObjectLink(DDLogObject aParent, |
176 | | DDLogObject aChild, |
177 | | const char* aLinkName, |
178 | | DDMessageIndex aLinkingIndex) |
179 | | : mParent(aParent) |
180 | | , mChild(aChild) |
181 | | , mLinkName(aLinkName) |
182 | | , mLinkingIndex(aLinkingIndex) |
183 | | , mUnlinkingIndex(Nothing{}) |
184 | 0 | { |
185 | 0 | } |
186 | | }; |
187 | | // Links between live objects, updated while messages are processed. |
188 | | nsTArray<DDObjectLink> mObjectLinks; |
189 | | |
190 | | // Protects members below. |
191 | | Mutex mMutex; |
192 | | |
193 | | // Processing thread. |
194 | | nsCOMPtr<nsIThread> mThread; |
195 | | |
196 | | struct PendingPromise |
197 | | { |
198 | | MozPromiseHolder<LogMessagesPromise> mPromiseHolder; |
199 | | const dom::HTMLMediaElement* mMediaElement; |
200 | | }; |
201 | | // Most cases should have 1 media panel requesting 1 promise at a time. |
202 | | AutoTArray<PendingPromise, 2> mPendingPromises; |
203 | | }; |
204 | | |
205 | | } // namespace mozilla |
206 | | |
207 | | #endif // DDMediaLogs_h_ |