/src/mozilla-central/xpcom/threads/ThrottledEventQueue.h
Line | Count | Source (jump to first uncovered line) |
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 | | // nsIEventTarget wrapper for throttling event dispatch. |
8 | | |
9 | | #ifndef mozilla_ThrottledEventQueue_h |
10 | | #define mozilla_ThrottledEventQueue_h |
11 | | |
12 | | #include "nsISerialEventTarget.h" |
13 | | |
14 | | #define NS_THROTTLEDEVENTQUEUE_IID \ |
15 | | { 0x8f3cf7dc, 0xfc14, 0x4ad5, \ |
16 | | { 0x9f, 0xd5, 0xdb, 0x79, 0xbc, 0xe6, 0xd5, 0x08 } } |
17 | | |
18 | | namespace mozilla { |
19 | | |
20 | | // A ThrottledEventQueue is an event target that can be used to throttle |
21 | | // events being dispatched to another base target. It maintains its |
22 | | // own queue of events and only dispatches one at a time to the wrapped |
23 | | // target. This can be used to avoid flooding the base target. |
24 | | // |
25 | | // Flooding is avoided via a very simply principal. Runnables dispatched |
26 | | // to the ThrottledEventQueue are only dispatched to the base target |
27 | | // one at a time. Only once that runnable has executed will we dispatch |
28 | | // the next runnable to the base target. This in effect makes all |
29 | | // runnables passing through the ThrottledEventQueue yield to other work |
30 | | // on the base target. |
31 | | // |
32 | | // ThrottledEventQueue keeps runnables waiting to be dispatched to the |
33 | | // base in its own internal queue. Code can query the length of this |
34 | | // queue using IsEmpty() and Length(). Further, code implement back |
35 | | // pressure by checking the depth of the queue and deciding to stop |
36 | | // issuing runnables if they see the ThrottledEventQueue is backed up. |
37 | | // Code running on other threads could even use AwaitIdle() to block |
38 | | // all operation until the ThrottledEventQueue drains. |
39 | | // |
40 | | // Note, this class is similar to TaskQueue, but also differs in a few |
41 | | // ways. First, it is a very simple nsIEventTarget implementation. It |
42 | | // does not use the AbstractThread API. |
43 | | // |
44 | | // In addition, ThrottledEventQueue currently dispatches its next |
45 | | // runnable to the base target *before* running the current event. This |
46 | | // allows the event code to spin the event loop without stalling the |
47 | | // ThrottledEventQueue. In contrast, TaskQueue only dispatches its next |
48 | | // runnable after running the current event. That approach is necessary |
49 | | // for TaskQueue in order to work with thread pool targets. |
50 | | // |
51 | | // So, if you are targeting a thread pool you probably want a TaskQueue. |
52 | | // If you are targeting a single thread or other non-concurrent event |
53 | | // target, you probably want a ThrottledEventQueue. |
54 | | // |
55 | | // If you drop a ThrottledEventQueue while its queue still has events to be run, |
56 | | // they will continue to be dispatched as usual to the base. Only once the last |
57 | | // event has run will all the ThrottledEventQueue's memory be freed. |
58 | | class ThrottledEventQueue final : public nsISerialEventTarget |
59 | | { |
60 | | class Inner; |
61 | | RefPtr<Inner> mInner; |
62 | | |
63 | | explicit ThrottledEventQueue(already_AddRefed<Inner> aInner); |
64 | 0 | ~ThrottledEventQueue() = default; |
65 | | |
66 | | public: |
67 | | // Attempt to create a ThrottledEventQueue for the given target. This |
68 | | // may return nullptr if the browser is already shutting down. |
69 | | static already_AddRefed<ThrottledEventQueue> |
70 | | Create(nsISerialEventTarget* aBaseTarget); |
71 | | |
72 | | // Determine if there are any events pending in the queue. |
73 | | bool IsEmpty() const; |
74 | | |
75 | | // Determine how many events are pending in the queue. |
76 | | uint32_t Length() const; |
77 | | |
78 | | // Block the current thread until the queue is empty. This may not |
79 | | // be called on the main thread or the base target. |
80 | | void AwaitIdle() const; |
81 | | |
82 | | NS_DECL_THREADSAFE_ISUPPORTS |
83 | | NS_DECL_NSIEVENTTARGET_FULL |
84 | | |
85 | | NS_DECLARE_STATIC_IID_ACCESSOR(NS_THROTTLEDEVENTQUEUE_IID); |
86 | | }; |
87 | | |
88 | | NS_DEFINE_STATIC_IID_ACCESSOR(ThrottledEventQueue, NS_THROTTLEDEVENTQUEUE_IID); |
89 | | |
90 | | } // namespace mozilla |
91 | | |
92 | | #endif // mozilla_ThrottledEventQueue_h |