Line data Source code
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 : #if !defined(AbstractThread_h_)
8 : #define AbstractThread_h_
9 :
10 : #include "mozilla/RefPtr.h"
11 : #include "mozilla/ThreadLocal.h"
12 : #include "nscore.h"
13 : #include "nsIRunnable.h"
14 : #include "nsISerialEventTarget.h"
15 : #include "nsISupportsImpl.h"
16 : #include "nsIThread.h"
17 :
18 : namespace mozilla {
19 :
20 : class TaskQueue;
21 : class TaskDispatcher;
22 :
23 : /*
24 : * NOTE: PLEASE AVOID USE OF AbstractThread OUTSIDE MEDIA CODE WHEN POSSIBLE.
25 : * The nsISerialEventTarget interface should be preferred. AbstractThread
26 : * has unusual "tail dispatch" semantics that usually are not needed outside
27 : * of media code.
28 : *
29 : * We often want to run tasks on a target that guarantees that events will never
30 : * run in parallel. There are various target types that achieve this - namely
31 : * nsIThread and TaskQueue. Note that nsIThreadPool (which implements
32 : * nsIEventTarget) does not have this property, so we do not want to use
33 : * nsIEventTarget for this purpose. This class encapsulates the specifics of
34 : * the structures we might use here and provides a consistent interface.
35 : *
36 : * At present, the supported AbstractThread implementations are TaskQueue,
37 : * AbstractThread::MainThread() and DocGroup::AbstractThreadFor().
38 : * If you add support for another thread that is not the MainThread, you'll need
39 : * to figure out how to make it unique such that comparing AbstractThread
40 : * pointers is equivalent to comparing nsIThread pointers.
41 : */
42 : class AbstractThread : public nsISerialEventTarget
43 : {
44 : public:
45 : // Returns the AbstractThread that the caller is currently running in, or null
46 : // if the caller is not running in an AbstractThread.
47 12 : static AbstractThread* GetCurrent() { return sCurrentThreadTLS.get(); }
48 :
49 8 : AbstractThread(bool aSupportsTailDispatch) : mSupportsTailDispatch(aSupportsTailDispatch) {}
50 :
51 : // Returns an AbstractThread wrapper of a nsIThread.
52 : static already_AddRefed<AbstractThread>
53 : CreateXPCOMThreadWrapper(nsIThread* aThread, bool aRequireTailDispatch);
54 :
55 : // Returns an AbstractThread wrapper of a non-nsIThread EventTarget on the main thread.
56 : static already_AddRefed<AbstractThread>
57 : CreateEventTargetWrapper(nsIEventTarget* aEventTarget, bool aRequireTailDispatch);
58 :
59 : NS_DECL_THREADSAFE_ISUPPORTS
60 :
61 : // We don't use NS_DECL_NSIEVENTTARGET so that we can remove the default
62 : // |flags| parameter from Dispatch. Otherwise, a single-argument Dispatch call
63 : // would be ambiguous.
64 : NS_IMETHOD_(bool) IsOnCurrentThreadInfallible(void) override;
65 : NS_IMETHOD IsOnCurrentThread(bool *_retval) override;
66 : NS_IMETHOD Dispatch(already_AddRefed<nsIRunnable> event, uint32_t flags) override;
67 : NS_IMETHOD DispatchFromScript(nsIRunnable *event, uint32_t flags) override;
68 : NS_IMETHOD DelayedDispatch(already_AddRefed<nsIRunnable> event, uint32_t delay) override;
69 :
70 : enum DispatchFailureHandling { AssertDispatchSuccess, DontAssertDispatchSuccess };
71 : enum DispatchReason { NormalDispatch, TailDispatch };
72 : virtual void Dispatch(already_AddRefed<nsIRunnable> aRunnable,
73 : DispatchFailureHandling aHandling = AssertDispatchSuccess,
74 : DispatchReason aReason = NormalDispatch) = 0;
75 :
76 : virtual bool IsCurrentThreadIn() = 0;
77 :
78 : // Returns a TaskDispatcher that will dispatch its tasks when the currently-
79 : // running tasks pops off the stack.
80 : //
81 : // May only be called when running within the it is invoked up, and only on
82 : // threads which support it.
83 : virtual TaskDispatcher& TailDispatcher() = 0;
84 :
85 : // Returns true if we have tail tasks scheduled, or if this isn't known.
86 : // Returns false if we definitely don't have any tail tasks.
87 0 : virtual bool MightHaveTailTasks() { return true; }
88 :
89 : // Helper functions for methods on the tail TasklDispatcher. These check
90 : // HasTailTasks to avoid allocating a TailDispatcher if it isn't
91 : // needed.
92 : void TailDispatchTasksFor(AbstractThread* aThread);
93 : bool HasTailTasksFor(AbstractThread* aThread);
94 :
95 : // Returns true if this supports the tail dispatcher.
96 8 : bool SupportsTailDispatch() const { return mSupportsTailDispatch; }
97 :
98 : // Returns true if this thread requires all dispatches originating from
99 : // aThread go through the tail dispatcher.
100 : bool RequiresTailDispatch(AbstractThread* aThread) const;
101 : bool RequiresTailDispatchFromCurrentThread() const;
102 :
103 0 : virtual TaskQueue* AsTaskQueue() { MOZ_CRASH("Not a task queue!"); }
104 0 : virtual nsIEventTarget* AsEventTarget() { MOZ_CRASH("Not an event target!"); }
105 :
106 : // Returns the non-DocGroup version of AbstractThread on the main thread.
107 : // A DocGroup-versioned one is available in DispatcherTrait::AbstractThreadFor().
108 : // Note: DispatcherTrait::AbstractThreadFor() SHALL be used when possible.
109 : static AbstractThread* MainThread();
110 :
111 : // Must be called exactly once during startup.
112 : static void InitTLS();
113 : static void InitMainThread();
114 :
115 : void DispatchStateChange(already_AddRefed<nsIRunnable> aRunnable);
116 :
117 : static void DispatchDirectTask(already_AddRefed<nsIRunnable> aRunnable);
118 :
119 : // Create a runnable that will run |aRunnable| and drain the direct tasks
120 : // generated by it.
121 : virtual already_AddRefed<nsIRunnable>
122 0 : CreateDirectTaskDrainer(already_AddRefed<nsIRunnable> aRunnable)
123 : {
124 0 : MOZ_CRASH("Not support!");
125 : }
126 :
127 : protected:
128 0 : virtual ~AbstractThread() {}
129 : static MOZ_THREAD_LOCAL(AbstractThread*) sCurrentThreadTLS;
130 :
131 : // True if we want to require that every task dispatched from tasks running in
132 : // this queue go through our queue's tail dispatcher.
133 : const bool mSupportsTailDispatch;
134 : };
135 :
136 : } // namespace mozilla
137 :
138 : #endif
|