Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/threads/PrioritizedEventQueue.h
Line
Count
Source (jump to first uncovered line)
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
#ifndef mozilla_PrioritizedEventQueue_h
8
#define mozilla_PrioritizedEventQueue_h
9
10
#include "mozilla/AbstractEventQueue.h"
11
#include "LabeledEventQueue.h"
12
#include "mozilla/TimeStamp.h"
13
#include "mozilla/TypeTraits.h"
14
#include "mozilla/UniquePtr.h"
15
#include "nsCOMPtr.h"
16
#include "nsIIdlePeriod.h"
17
18
class nsIRunnable;
19
20
namespace mozilla {
21
22
// This AbstractEventQueue implementation has one queue for each EventPriority.
23
// The type of queue used for each priority is determined by the template
24
// parameter.
25
//
26
// When an event is pushed, its priority is determined by QIing the runnable to
27
// nsIRunnablePriority, or by falling back to the aPriority parameter if the QI
28
// fails.
29
//
30
// When an event is popped, a queue is selected based on heuristics that
31
// optimize for performance. Roughly, events are selected from the highest
32
// priority queue that is non-empty. However, there are a few exceptions:
33
// - We try to avoid processing too many high-priority events in a row so
34
//   that the normal priority queue is not starved. When there are high-
35
//   and normal-priority events available, we interleave popping from the
36
//   normal and high queues.
37
// - We do not select events from the idle queue if the current idle period
38
//   is almost over.
39
template<class InnerQueueT>
40
class PrioritizedEventQueue final : public AbstractEventQueue
41
{
42
public:
43
  static const bool SupportsPrioritization = true;
44
45
  PrioritizedEventQueue(UniquePtr<InnerQueueT> aHighQueue,
46
                        UniquePtr<InnerQueueT> aInputQueue,
47
                        UniquePtr<InnerQueueT> aNormalQueue,
48
                        UniquePtr<InnerQueueT> aIdleQueue,
49
                        already_AddRefed<nsIIdlePeriod> aIdlePeriod);
50
51
  void PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
52
                EventPriority aPriority,
53
                const MutexAutoLock& aProofOfLock) final;
54
  already_AddRefed<nsIRunnable> GetEvent(EventPriority* aPriority,
55
                                         const MutexAutoLock& aProofOfLock) final;
56
57
  bool IsEmpty(const MutexAutoLock& aProofOfLock) final;
58
  size_t Count(const MutexAutoLock& aProofOfLock) const final;
59
  bool HasReadyEvent(const MutexAutoLock& aProofOfLock) final;
60
61
  // When checking the idle deadline, we need to drop whatever mutex protects
62
  // this queue. This method allows that mutex to be stored so that we can drop
63
  // it and reacquire it when checking the idle deadline. The mutex must live at
64
  // least as long as the queue.
65
3
  void SetMutexRef(Mutex& aMutex) { mMutex = &aMutex; }
mozilla::PrioritizedEventQueue<mozilla::EventQueue>::SetMutexRef(mozilla::Mutex&)
Line
Count
Source
65
3
  void SetMutexRef(Mutex& aMutex) { mMutex = &aMutex; }
Unexecuted instantiation: mozilla::PrioritizedEventQueue<mozilla::LabeledEventQueue>::SetMutexRef(mozilla::Mutex&)
66
67
#ifndef RELEASE_OR_BETA
68
  // nsThread.cpp sends telemetry containing the most recently computed idle
69
  // deadline. We store a reference to a field in nsThread where this deadline
70
  // will be stored so that it can be fetched quickly for telemetry.
71
3
  void SetNextIdleDeadlineRef(TimeStamp& aDeadline) { mNextIdleDeadline = &aDeadline; }
mozilla::PrioritizedEventQueue<mozilla::EventQueue>::SetNextIdleDeadlineRef(mozilla::TimeStamp&)
Line
Count
Source
71
3
  void SetNextIdleDeadlineRef(TimeStamp& aDeadline) { mNextIdleDeadline = &aDeadline; }
Unexecuted instantiation: mozilla::PrioritizedEventQueue<mozilla::LabeledEventQueue>::SetNextIdleDeadlineRef(mozilla::TimeStamp&)
72
#endif
73
74
  void EnableInputEventPrioritization(const MutexAutoLock& aProofOfLock) final;
75
  void FlushInputEventPrioritization(const MutexAutoLock& aProofOfLock) final;
76
  void SuspendInputEventPrioritization(const MutexAutoLock& aProofOfLock) final;
77
  void ResumeInputEventPrioritization(const MutexAutoLock& aProofOfLock) final;
78
79
  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override
80
0
  {
81
0
    size_t n = 0;
82
0
83
0
    n += mHighQueue->SizeOfIncludingThis(aMallocSizeOf);
84
0
    n += mInputQueue->SizeOfIncludingThis(aMallocSizeOf);
85
0
    n += mNormalQueue->SizeOfIncludingThis(aMallocSizeOf);
86
0
    n += mIdleQueue->SizeOfIncludingThis(aMallocSizeOf);
87
0
88
0
    if (mIdlePeriod) {
89
0
      n += aMallocSizeOf(mIdlePeriod);
90
0
    }
91
0
92
0
    return n;
93
0
  }
Unexecuted instantiation: mozilla::PrioritizedEventQueue<mozilla::EventQueue>::SizeOfExcludingThis(unsigned long (*)(void const*)) const
Unexecuted instantiation: mozilla::PrioritizedEventQueue<mozilla::LabeledEventQueue>::SizeOfExcludingThis(unsigned long (*)(void const*)) const
94
95
private:
96
  EventPriority SelectQueue(bool aUpdateState, const MutexAutoLock& aProofOfLock);
97
98
  // Returns a null TimeStamp if we're not in the idle period.
99
  mozilla::TimeStamp GetIdleDeadline();
100
101
  UniquePtr<InnerQueueT> mHighQueue;
102
  UniquePtr<InnerQueueT> mInputQueue;
103
  UniquePtr<InnerQueueT> mNormalQueue;
104
  UniquePtr<InnerQueueT> mIdleQueue;
105
106
  // We need to drop the queue mutex when checking the idle deadline, so we keep
107
  // a pointer to it here.
108
  Mutex* mMutex = nullptr;
109
110
#ifndef RELEASE_OR_BETA
111
  // Pointer to a place where the most recently computed idle deadline is
112
  // stored.
113
  TimeStamp* mNextIdleDeadline = nullptr;
114
#endif
115
116
  // Try to process one high priority runnable after each normal
117
  // priority runnable. This gives the processing model HTML spec has for
118
  // 'Update the rendering' in the case only vsync messages are in the
119
  // secondary queue and prevents starving the normal queue.
120
  bool mProcessHighPriorityQueue = false;
121
122
  // mIdlePeriod keeps track of the current idle period. If at any
123
  // time the main event queue is empty, calling
124
  // mIdlePeriod->GetIdlePeriodHint() will give an estimate of when
125
  // the current idle period will end.
126
  nsCOMPtr<nsIIdlePeriod> mIdlePeriod;
127
128
  // Set to true if HasPendingEvents() has been called and returned true because
129
  // of a pending idle event.  This is used to remember to return that idle
130
  // event from GetIdleEvent() to ensure that HasPendingEvents() never lies.
131
  bool mHasPendingEventsPromisedIdleEvent = false;
132
133
  TimeStamp mInputHandlingStartTime;
134
135
  enum InputEventQueueState
136
  {
137
    STATE_DISABLED,
138
    STATE_FLUSHING,
139
    STATE_SUSPEND,
140
    STATE_ENABLED
141
  };
142
  InputEventQueueState mInputQueueState = STATE_DISABLED;
143
};
144
145
class EventQueue;
146
extern template class PrioritizedEventQueue<EventQueue>;
147
extern template class PrioritizedEventQueue<LabeledEventQueue>;
148
149
} // namespace mozilla
150
151
#endif // mozilla_PrioritizedEventQueue_h