Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/AbstractThread.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
#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
3
  static AbstractThread* GetCurrent() { return sCurrentThreadTLS.get(); }
48
49
3
  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
  // AbstractThreads preserve their refcounts when recording/replaying, as
60
  // otherwise the thread which releases the last reference may vary between
61
  // recording and replaying.
62
  NS_DECL_THREADSAFE_ISUPPORTS_WITH_RECORDING(recordreplay::Behavior::Preserve)
63
64
  // We don't use NS_DECL_NSIEVENTTARGET so that we can remove the default
65
  // |flags| parameter from Dispatch. Otherwise, a single-argument Dispatch call
66
  // would be ambiguous.
67
  NS_IMETHOD_(bool) IsOnCurrentThreadInfallible(void) override;
68
  NS_IMETHOD IsOnCurrentThread(bool *_retval) override;
69
  NS_IMETHOD Dispatch(already_AddRefed<nsIRunnable> event, uint32_t flags) override;
70
  NS_IMETHOD DispatchFromScript(nsIRunnable *event, uint32_t flags) override;
71
  NS_IMETHOD DelayedDispatch(already_AddRefed<nsIRunnable> event, uint32_t delay) override;
72
73
  enum DispatchReason { NormalDispatch, TailDispatch };
74
  virtual nsresult Dispatch(already_AddRefed<nsIRunnable> aRunnable,
75
                            DispatchReason aReason = NormalDispatch) = 0;
76
77
  virtual bool IsCurrentThreadIn() = 0;
78
79
  // Returns a TaskDispatcher that will dispatch its tasks when the currently-
80
  // running tasks pops off the stack.
81
  //
82
  // May only be called when running within the it is invoked up, and only on
83
  // threads which support it.
84
  virtual TaskDispatcher& TailDispatcher() = 0;
85
86
  // Returns true if we have tail tasks scheduled, or if this isn't known.
87
  // Returns false if we definitely don't have any tail tasks.
88
0
  virtual bool MightHaveTailTasks() { return true; }
89
90
  // Helper functions for methods on the tail TasklDispatcher. These check
91
  // HasTailTasks to avoid allocating a TailDispatcher if it isn't
92
  // needed.
93
  nsresult TailDispatchTasksFor(AbstractThread* aThread);
94
  bool HasTailTasksFor(AbstractThread* aThread);
95
96
  // Returns true if this supports the tail dispatcher.
97
0
  bool SupportsTailDispatch() const { return mSupportsTailDispatch; }
98
99
  // Returns true if this thread requires all dispatches originating from
100
  // aThread go through the tail dispatcher.
101
  bool RequiresTailDispatch(AbstractThread* aThread) const;
102
  bool RequiresTailDispatchFromCurrentThread() const;
103
104
0
  virtual TaskQueue* AsTaskQueue() { MOZ_CRASH("Not a task queue!"); }
105
0
  virtual nsIEventTarget* AsEventTarget() { MOZ_CRASH("Not an event target!"); }
106
107
  // Returns the non-DocGroup version of AbstractThread on the main thread.
108
  // A DocGroup-versioned one is available in DispatcherTrait::AbstractThreadFor().
109
  // Note: DispatcherTrait::AbstractThreadFor() SHALL be used when possible.
110
  static AbstractThread* MainThread();
111
112
  // Must be called exactly once during startup.
113
  static void InitTLS();
114
  static void InitMainThread();
115
116
  void DispatchStateChange(already_AddRefed<nsIRunnable> aRunnable);
117
118
  static void DispatchDirectTask(already_AddRefed<nsIRunnable> aRunnable);
119
120
  // Create a runnable that will run |aRunnable| and drain the direct tasks
121
  // generated by it.
122
  virtual already_AddRefed<nsIRunnable>
123
  CreateDirectTaskDrainer(already_AddRefed<nsIRunnable> aRunnable)
124
0
  {
125
0
    MOZ_CRASH("Not support!");
126
0
  }
127
128
  struct AutoEnter
129
  {
130
    explicit AutoEnter(AbstractThread* aThread)
131
0
    {
132
0
      mLastCurrentThread = sCurrentThreadTLS.get();
133
0
      sCurrentThreadTLS.set(aThread);
134
0
    }
135
136
    ~AutoEnter()
137
0
    {
138
0
      sCurrentThreadTLS.set(mLastCurrentThread);
139
0
    }
140
141
  private:
142
    AbstractThread* mLastCurrentThread = nullptr;
143
  };
144
145
protected:
146
0
  virtual ~AbstractThread() {}
147
  static MOZ_THREAD_LOCAL(AbstractThread*) sCurrentThreadTLS;
148
149
  // True if we want to require that every task dispatched from tasks running in
150
  // this queue go through our queue's tail dispatcher.
151
  const bool mSupportsTailDispatch;
152
};
153
154
} // namespace mozilla
155
156
#endif