diff options
Diffstat (limited to 'xpcom/threads/EventQueue.cpp')
-rw-r--r-- | xpcom/threads/EventQueue.cpp | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/xpcom/threads/EventQueue.cpp b/xpcom/threads/EventQueue.cpp new file mode 100644 index 0000000000..0decc3ce4c --- /dev/null +++ b/xpcom/threads/EventQueue.cpp @@ -0,0 +1,131 @@ +/* -*- 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/. */ + +#include "mozilla/EventQueue.h" + +#include "GeckoProfiler.h" +#include "InputTaskManager.h" +#include "VsyncTaskManager.h" +#include "nsIRunnable.h" +#include "TaskController.h" + +using namespace mozilla; +using namespace mozilla::detail; + +template <size_t ItemsPerPage> +void EventQueueInternal<ItemsPerPage>::PutEvent( + already_AddRefed<nsIRunnable>&& aEvent, EventQueuePriority aPriority, + const MutexAutoLock& aProofOfLock, mozilla::TimeDuration* aDelay) { + nsCOMPtr<nsIRunnable> event(aEvent); + + static_assert(static_cast<uint32_t>(nsIRunnablePriority::PRIORITY_IDLE) == + static_cast<uint32_t>(EventQueuePriority::Idle)); + static_assert(static_cast<uint32_t>(nsIRunnablePriority::PRIORITY_NORMAL) == + static_cast<uint32_t>(EventQueuePriority::Normal)); + static_assert( + static_cast<uint32_t>(nsIRunnablePriority::PRIORITY_MEDIUMHIGH) == + static_cast<uint32_t>(EventQueuePriority::MediumHigh)); + static_assert( + static_cast<uint32_t>(nsIRunnablePriority::PRIORITY_INPUT_HIGH) == + static_cast<uint32_t>(EventQueuePriority::InputHigh)); + static_assert(static_cast<uint32_t>(nsIRunnablePriority::PRIORITY_VSYNC) == + static_cast<uint32_t>(EventQueuePriority::Vsync)); + static_assert( + static_cast<uint32_t>(nsIRunnablePriority::PRIORITY_RENDER_BLOCKING) == + static_cast<uint32_t>(EventQueuePriority::RenderBlocking)); + static_assert(static_cast<uint32_t>(nsIRunnablePriority::PRIORITY_CONTROL) == + static_cast<uint32_t>(EventQueuePriority::Control)); + + if (mForwardToTC) { + TaskController* tc = TaskController::Get(); + + TaskManager* manager = nullptr; + if (aPriority == EventQueuePriority::InputHigh) { + manager = InputTaskManager::Get(); + } else if (aPriority == EventQueuePriority::DeferredTimers || + aPriority == EventQueuePriority::Idle) { + manager = TaskController::Get()->GetIdleTaskManager(); + } else if (aPriority == EventQueuePriority::Vsync) { + manager = VsyncTaskManager::Get(); + } + + tc->DispatchRunnable(event.forget(), static_cast<uint32_t>(aPriority), + manager); + return; + } + + if (profiler_thread_is_being_profiled(ThreadProfilingFeatures::Sampling)) { + // check to see if the profiler has been enabled since the last PutEvent + while (mDispatchTimes.Count() < mQueue.Count()) { + mDispatchTimes.Push(TimeStamp()); + } + mDispatchTimes.Push(aDelay ? TimeStamp::Now() - *aDelay : TimeStamp::Now()); + } + + mQueue.Push(std::move(event)); +} + +template <size_t ItemsPerPage> +already_AddRefed<nsIRunnable> EventQueueInternal<ItemsPerPage>::GetEvent( + const MutexAutoLock& aProofOfLock, mozilla::TimeDuration* aLastEventDelay) { + if (mQueue.IsEmpty()) { + if (aLastEventDelay) { + *aLastEventDelay = TimeDuration(); + } + return nullptr; + } + + // We always want to clear the dispatch times, even if the profiler is turned + // off, because we want to empty the (previously-collected) dispatch times, if + // any, from when the profiler was turned on. We only want to do something + // interesting with the dispatch times if the profiler is turned on, though. + if (!mDispatchTimes.IsEmpty()) { + TimeStamp dispatch_time = mDispatchTimes.Pop(); + if (profiler_is_active()) { + if (!dispatch_time.IsNull()) { + if (aLastEventDelay) { + *aLastEventDelay = TimeStamp::Now() - dispatch_time; + } + } + } + } else if (profiler_is_active()) { + if (aLastEventDelay) { + // if we just turned on the profiler, we don't have dispatch + // times for events already in the queue. + *aLastEventDelay = TimeDuration(); + } + } + + nsCOMPtr<nsIRunnable> result = mQueue.Pop(); + return result.forget(); +} + +template <size_t ItemsPerPage> +bool EventQueueInternal<ItemsPerPage>::IsEmpty( + const MutexAutoLock& aProofOfLock) { + return mQueue.IsEmpty(); +} + +template <size_t ItemsPerPage> +bool EventQueueInternal<ItemsPerPage>::HasReadyEvent( + const MutexAutoLock& aProofOfLock) { + return !IsEmpty(aProofOfLock); +} + +template <size_t ItemsPerPage> +size_t EventQueueInternal<ItemsPerPage>::Count( + const MutexAutoLock& aProofOfLock) const { + return mQueue.Count(); +} + +namespace mozilla { +template class EventQueueSized<16>; // Used by ThreadEventQueue +template class EventQueueSized<64>; // Used by ThrottledEventQueue +namespace detail { +template class EventQueueInternal<16>; // Used by ThreadEventQueue +template class EventQueueInternal<64>; // Used by ThrottledEventQueue +} // namespace detail +} // namespace mozilla |