forked from mirrors/gecko-dev
		
	 aaa37485cc
			
		
	
	
		aaa37485cc
		
	
	
	
	
		
			
			This improves the setup so that whenever there are only idle/deferred tasks, we can run low priority tasks immediately. Manual testing shows that this way we get couple of more ticks every now and then. Without this patch we'd rely on normal priority tasks, but since there might be multiple of those pending, ShouldGiveNonVsyncTasksMoreTime() would return true. So, low priority tasks are effectively "run when the queue is otherwise empty (but idle-type of tasks are still special)". Differential Revision: https://phabricator.services.mozilla.com/D159583
		
			
				
	
	
		
			136 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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"
 | |
| 
 | |
| class nsIRunnable;
 | |
| 
 | |
| 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
 |