summaryrefslogtreecommitdiffstats
path: root/xpcom/threads/EventQueue.h
blob: b7af71be82c0735f33d26737c2e6f20eba2dcfca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_EventQueue_h
#define mozilla_EventQueue_h

#include "mozilla/Mutex.h"
#include "mozilla/Queue.h"
#include "mozilla/TimeStamp.h"
#include "nsCOMPtr.h"
#include "nsIRunnable.h"

namespace mozilla {

#define EVENT_QUEUE_PRIORITY_LIST(EVENT_PRIORITY) \
  EVENT_PRIORITY(Idle, 0)                         \
  EVENT_PRIORITY(DeferredTimers, 1)               \
  EVENT_PRIORITY(Low, 2)                          \
  EVENT_PRIORITY(InputLow, 3)                     \
  EVENT_PRIORITY(Normal, 4)                       \
  EVENT_PRIORITY(MediumHigh, 5)                   \
  EVENT_PRIORITY(InputHigh, 6)                    \
  EVENT_PRIORITY(Vsync, 7)                        \
  EVENT_PRIORITY(InputHighest, 8)                 \
  EVENT_PRIORITY(RenderBlocking, 9)               \
  EVENT_PRIORITY(Control, 10)

enum class EventQueuePriority {
#define EVENT_PRIORITY(NAME, VALUE) NAME = VALUE,
  EVENT_QUEUE_PRIORITY_LIST(EVENT_PRIORITY)
#undef EVENT_PRIORITY
      Invalid
};

class IdlePeriodState;

namespace detail {

// EventQueue is our unsynchronized event queue implementation. It is a queue
// of runnables used for non-main thread, as well as optionally providing
// forwarding to TaskController.
//
// Since EventQueue is unsynchronized, it should be wrapped in an outer
// SynchronizedEventQueue implementation (like ThreadEventQueue).
template <size_t ItemsPerPage>
class EventQueueInternal {
 public:
  explicit EventQueueInternal(bool aForwardToTC) : mForwardToTC(aForwardToTC) {}

  // Add an event to the end of the queue. Implementors are free to use
  // aPriority however they wish.  If the runnable supports
  // nsIRunnablePriority and the implementing class supports
  // prioritization, aPriority represents the result of calling
  // nsIRunnablePriority::GetPriority().  *aDelay is time the event has
  // already been delayed (used when moving an event from one queue to
  // another)
  void PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
                EventQueuePriority aPriority, const MutexAutoLock& aProofOfLock,
                mozilla::TimeDuration* aDelay = nullptr);

  // Get an event from the front of the queue. This should return null if the
  // queue is non-empty but the event in front is not ready to run.
  // *aLastEventDelay is the time the event spent in queues before being
  // retrieved.
  already_AddRefed<nsIRunnable> GetEvent(
      const MutexAutoLock& aProofOfLock,
      mozilla::TimeDuration* aLastEventDelay = nullptr);

  // Returns true if the queue is empty. Implies !HasReadyEvent().
  bool IsEmpty(const MutexAutoLock& aProofOfLock);

  // Returns true if the queue is non-empty and if the event in front is ready
  // to run. Implies !IsEmpty(). This should return true iff GetEvent returns a
  // non-null value.
  bool HasReadyEvent(const MutexAutoLock& aProofOfLock);

  // Returns the number of events in the queue.
  size_t Count(const MutexAutoLock& aProofOfLock) const;
  // For some reason, if we put this in the .cpp file the linker can't find it
  already_AddRefed<nsIRunnable> PeekEvent(const MutexAutoLock& aProofOfLock) {
    if (mQueue.IsEmpty()) {
      return nullptr;
    }

    nsCOMPtr<nsIRunnable> result = mQueue.FirstElement();
    return result.forget();
  }

  void EnableInputEventPrioritization(const MutexAutoLock& aProofOfLock) {}
  void FlushInputEventPrioritization(const MutexAutoLock& aProofOfLock) {}
  void SuspendInputEventPrioritization(const MutexAutoLock& aProofOfLock) {}
  void ResumeInputEventPrioritization(const MutexAutoLock& aProofOfLock) {}

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
  }

  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
    size_t size = mQueue.ShallowSizeOfExcludingThis(aMallocSizeOf);
    size += mDispatchTimes.ShallowSizeOfExcludingThis(aMallocSizeOf);
    return size;
  }

 private:
  mozilla::Queue<nsCOMPtr<nsIRunnable>, ItemsPerPage> mQueue;
  // This queue is only populated when the profiler is turned on.
  mozilla::Queue<mozilla::TimeStamp, ItemsPerPage> mDispatchTimes;
  TimeDuration mLastEventDelay;
  // This indicates PutEvent forwards runnables to the TaskController. This
  // should be true for the top level event queue on the main thread.
  bool mForwardToTC;
};

}  // namespace detail

class EventQueue final : public mozilla::detail::EventQueueInternal<16> {
 public:
  explicit EventQueue(bool aForwardToTC = false)
      : mozilla::detail::EventQueueInternal<16>(aForwardToTC) {}
};

template <size_t ItemsPerPage = 16>
class EventQueueSized final
    : public mozilla::detail::EventQueueInternal<ItemsPerPage> {
 public:
  explicit EventQueueSized(bool aForwardToTC = false)
      : mozilla::detail::EventQueueInternal<ItemsPerPage>(aForwardToTC) {}
};

}  // namespace mozilla

#endif  // mozilla_EventQueue_h