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 "mozilla/EventQueue.h"
8 
9 #include "GeckoProfiler.h"
10 #include "nsIRunnable.h"
11 
12 using namespace mozilla;
13 using namespace mozilla::detail;
14 
15 template <size_t ItemsPerPage>
EventQueueInternal(EventQueuePriority aPriority)16 EventQueueInternal<ItemsPerPage>::EventQueueInternal(
17     EventQueuePriority aPriority) {}
18 
19 template <size_t ItemsPerPage>
PutEvent(already_AddRefed<nsIRunnable> && aEvent,EventQueuePriority aPriority,const MutexAutoLock & aProofOfLock,mozilla::TimeDuration * aDelay)20 void EventQueueInternal<ItemsPerPage>::PutEvent(
21     already_AddRefed<nsIRunnable>&& aEvent, EventQueuePriority aPriority,
22     const MutexAutoLock& aProofOfLock, mozilla::TimeDuration* aDelay) {
23 #ifdef MOZ_GECKO_PROFILER
24   // Sigh, this doesn't check if this thread is being profiled
25   if (profiler_is_active()) {
26     // check to see if the profiler has been enabled since the last PutEvent
27     while (mDispatchTimes.Count() < mQueue.Count()) {
28       mDispatchTimes.Push(TimeStamp());
29     }
30     mDispatchTimes.Push(aDelay ? TimeStamp::Now() - *aDelay : TimeStamp::Now());
31   }
32 #endif
33 
34   nsCOMPtr<nsIRunnable> event(aEvent);
35   mQueue.Push(std::move(event));
36 }
37 
38 template <size_t ItemsPerPage>
GetEvent(EventQueuePriority * aPriority,const MutexAutoLock & aProofOfLock,mozilla::TimeDuration * aLastEventDelay)39 already_AddRefed<nsIRunnable> EventQueueInternal<ItemsPerPage>::GetEvent(
40     EventQueuePriority* aPriority, const MutexAutoLock& aProofOfLock,
41     mozilla::TimeDuration* aLastEventDelay) {
42   if (mQueue.IsEmpty()) {
43     if (aLastEventDelay) {
44       *aLastEventDelay = TimeDuration();
45     }
46     return nullptr;
47   }
48 
49   if (aPriority) {
50     *aPriority = EventQueuePriority::Normal;
51   }
52 
53 #ifdef MOZ_GECKO_PROFILER
54   // We always want to clear the dispatch times, even if the profiler is turned
55   // off, because we want to empty the (previously-collected) dispatch times, if
56   // any, from when the profiler was turned on.  We only want to do something
57   // interesting with the dispatch times if the profiler is turned on, though.
58   if (!mDispatchTimes.IsEmpty()) {
59     TimeStamp dispatch_time = mDispatchTimes.Pop();
60     if (profiler_is_active()) {
61       if (!dispatch_time.IsNull()) {
62         if (aLastEventDelay) {
63           *aLastEventDelay = TimeStamp::Now() - dispatch_time;
64         }
65       }
66     }
67   } else if (profiler_is_active()) {
68     if (aLastEventDelay) {
69       // if we just turned on the profiler, we don't have dispatch
70       // times for events already in the queue.
71       *aLastEventDelay = TimeDuration();
72     }
73   }
74 #endif
75 
76   nsCOMPtr<nsIRunnable> result = mQueue.Pop();
77   return result.forget();
78 }
79 
80 template <size_t ItemsPerPage>
IsEmpty(const MutexAutoLock & aProofOfLock)81 bool EventQueueInternal<ItemsPerPage>::IsEmpty(
82     const MutexAutoLock& aProofOfLock) {
83   return mQueue.IsEmpty();
84 }
85 
86 template <size_t ItemsPerPage>
HasReadyEvent(const MutexAutoLock & aProofOfLock)87 bool EventQueueInternal<ItemsPerPage>::HasReadyEvent(
88     const MutexAutoLock& aProofOfLock) {
89   return !IsEmpty(aProofOfLock);
90 }
91 
92 template <size_t ItemsPerPage>
Count(const MutexAutoLock & aProofOfLock) const93 size_t EventQueueInternal<ItemsPerPage>::Count(
94     const MutexAutoLock& aProofOfLock) const {
95   return mQueue.Count();
96 }
97