Mypal/xpcom/threads/ThrottledEventQueue.h

94 lines
3.8 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
// nsIEventTarget wrapper for throttling event dispatch.
#ifndef mozilla_ThrottledEventQueue_h
#define mozilla_ThrottledEventQueue_h
#include "nsIEventTarget.h"
namespace mozilla {
// A ThrottledEventQueue is an event target that can be used to throttle
// events being dispatched to another base target. It maintains its
// own queue of events and only dispatches one at a time to the wrapped
// target. This can be used to avoid flooding the base target.
//
// Flooding is avoided via a very simply principal. Runnables dispatched
// to the ThrottledEventQueue are only dispatched to the base target
// one at a time. Only once that runnable has executed will we dispatch
// the next runnable to the base target. This in effect makes all
// runnables passing through the ThrottledEventQueue yield to other work
// on the base target.
//
// ThrottledEventQueue keeps runnables waiting to be dispatched to the
// base in its own internal queue. Code can query the length of this
// queue using IsEmpty() and Length(). Further, code implement back
// pressure by checking the depth of the queue and deciding to stop
// issuing runnables if they see the ThrottledEventQueue is backed up.
// Code running on other threads could even use AwaitIdle() to block
// all operation until the ThrottledEventQueue drains.
//
// Note, this class is similar to TaskQueue, but also differs in a few
// ways. First, it is a very simple nsIEventTarget implementation. It
// does not use the AbstractThread API.
//
// In addition, ThrottledEventQueue currently dispatches its next
// runnable to the base target *before* running the current event. This
// allows the event code to spin the event loop without stalling the
// ThrottledEventQueue. In contrast, TaskQueue only dispatches its next
// runnable after running the current event. That approach is necessary
// for TaskQueue in order to work with thread pool targets.
//
// So, if you are targeting a thread pool you probably want a TaskQueue.
// If you are targeting a single thread or other non-concurrent event
// target, you probably want a ThrottledEventQueue.
//
// ThrottledEventQueue also implements an automatic shutdown mechanism.
// De-referencing the queue or browser shutdown will automatically begin
// shutdown.
//
// Once shutdown begins all events will bypass the queue and be dispatched
// straight to the underlying base target.
class ThrottledEventQueue final : public nsIEventTarget
{
class Inner;
RefPtr<Inner> mInner;
explicit ThrottledEventQueue(already_AddRefed<Inner> aInner);
~ThrottledEventQueue();
// Begin shutdown of the event queue. This has no effect if shutdown
// is already in process. After this is called nsIEventTarget methods
// will bypass the queue and operate directly on the base target.
// Note, this could be made public if code needs to explicitly shutdown
// for some reason.
void MaybeStartShutdown();
public:
// Attempt to create a ThrottledEventQueue for the given target. This
// may return nullptr if the browser is already shutting down.
static already_AddRefed<ThrottledEventQueue>
Create(nsIEventTarget* aBaseTarget);
// Determine if there are any events pending in the queue.
bool IsEmpty() const;
// Determine how many events are pending in the queue.
uint32_t Length() const;
// Block the current thread until the queue is empty. This may not
// be called on the main thread or the base target.
void AwaitIdle() const;
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIEVENTTARGET
};
} // namespace mozilla
#endif // mozilla_ThrottledEventQueue_h