Coverage Report

Created: 2018-09-25 14:53

/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_