Backed out 3 changesets (bug 1854934) for causing build bustages on widget/windows...
[gecko.git] / xpcom / threads / nsThread.h
blob72aff9d50f29e2efb7b617d3ba8d1a9a023c634f
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/. */
7 #ifndef nsThread_h__
8 #define nsThread_h__
10 #include "MainThreadUtils.h"
11 #include "mozilla/AlreadyAddRefed.h"
12 #include "mozilla/Atomics.h"
13 #include "mozilla/Attributes.h"
14 #include "mozilla/DataMutex.h"
15 #include "mozilla/EventQueue.h"
16 #include "mozilla/LinkedList.h"
17 #include "mozilla/MemoryReporting.h"
18 #include "mozilla/Mutex.h"
19 #include "mozilla/NotNull.h"
20 #include "mozilla/RefPtr.h"
21 #include "mozilla/TaskDispatcher.h"
22 #include "mozilla/TimeStamp.h"
23 #include "mozilla/UniquePtr.h"
24 #include "nsIDirectTaskDispatcher.h"
25 #include "nsIEventTarget.h"
26 #include "nsISerialEventTarget.h"
27 #include "nsISupportsPriority.h"
28 #include "nsIThread.h"
29 #include "nsIThreadInternal.h"
30 #include "nsTArray.h"
32 namespace mozilla {
33 class CycleCollectedJSContext;
34 class DelayedRunnable;
35 class SynchronizedEventQueue;
36 class ThreadEventQueue;
37 class ThreadEventTarget;
39 template <typename T, size_t Length>
40 class Array;
41 } // namespace mozilla
43 using mozilla::NotNull;
45 class nsIRunnable;
46 class nsThreadEnumerator;
47 class nsThreadShutdownContext;
49 // See https://www.w3.org/TR/longtasks
50 #define LONGTASK_BUSY_WINDOW_MS 50
52 // Time a Runnable executes before we accumulate telemetry on it
53 #define LONGTASK_TELEMETRY_MS 30
55 // A class for managing performance counter state.
56 namespace mozilla {
57 class PerformanceCounterState {
58 public:
59 explicit PerformanceCounterState(const uint32_t& aNestedEventLoopDepthRef,
60 bool aIsMainThread)
61 : mNestedEventLoopDepth(aNestedEventLoopDepthRef),
62 mIsMainThread(aIsMainThread),
63 // Does it really make sense to initialize these to "now" when we
64 // haven't run any tasks?
65 mLastLongTaskEnd(TimeStamp::Now()),
66 mLastLongNonIdleTaskEnd(mLastLongTaskEnd) {}
68 class Snapshot {
69 public:
70 Snapshot(uint32_t aOldEventLoopDepth, bool aOldIsIdleRunnable)
71 : mOldEventLoopDepth(aOldEventLoopDepth),
72 mOldIsIdleRunnable(aOldIsIdleRunnable) {}
74 Snapshot(const Snapshot&) = default;
75 Snapshot(Snapshot&&) = default;
77 private:
78 friend class PerformanceCounterState;
80 const uint32_t mOldEventLoopDepth;
81 const bool mOldIsIdleRunnable;
84 // Notification that a runnable is about to run. This captures a snapshot of
85 // our current state before we reset to prepare for the new runnable. This
86 // muast be called after mNestedEventLoopDepth has been incremented for the
87 // runnable execution. The performance counter passed in should be the one
88 // for the relevant runnable and may be null. aIsIdleRunnable should be true
89 // if and only if the runnable has idle priority.
90 Snapshot RunnableWillRun(TimeStamp aNow, bool aIsIdleRunnable);
92 // Notification that a runnable finished executing. This must be passed the
93 // snapshot that RunnableWillRun returned for the same runnable. This must be
94 // called before mNestedEventLoopDepth is decremented after the runnable's
95 // execution.
96 void RunnableDidRun(const nsCString& aName, Snapshot&& aSnapshot);
98 const TimeStamp& LastLongTaskEnd() const { return mLastLongTaskEnd; }
99 const TimeStamp& LastLongNonIdleTaskEnd() const {
100 return mLastLongNonIdleTaskEnd;
103 private:
104 // Called to report accumulated time, as needed, when we're about to run a
105 // runnable or just finished running one.
106 void MaybeReportAccumulatedTime(const nsCString& aName, TimeStamp aNow);
108 // Whether the runnable we are about to run, or just ran, is a nested
109 // runnable, in the sense that there is some other runnable up the stack
110 // spinning the event loop. This must be called before we change our
111 // mCurrentEventLoopDepth (when about to run a new event) or after we restore
112 // it (after we ran one).
113 bool IsNestedRunnable() const {
114 return mNestedEventLoopDepth > mCurrentEventLoopDepth;
117 // The event loop depth of the currently running runnable. Set to the max
118 // value of a uint32_t when there is no runnable running, so when starting to
119 // run a toplevel (not nested) runnable IsNestedRunnable() will test false.
120 uint32_t mCurrentEventLoopDepth = std::numeric_limits<uint32_t>::max();
122 // A reference to the nsThread's mNestedEventLoopDepth, so we can
123 // see what it is right now.
124 const uint32_t& mNestedEventLoopDepth;
126 // A boolean that indicates whether the currently running runnable is an idle
127 // runnable. Only has a useful value between RunnableWillRun() being called
128 // and RunnableDidRun() returning.
129 bool mCurrentRunnableIsIdleRunnable = false;
131 // Whether we're attached to the mainthread nsThread.
132 const bool mIsMainThread;
134 // The timestamp from which time to be accounted for should be measured. This
135 // can be the start of a runnable running or the end of a nested runnable
136 // running.
137 TimeStamp mCurrentTimeSliceStart;
139 // Information about when long tasks last ended.
140 TimeStamp mLastLongTaskEnd;
141 TimeStamp mLastLongNonIdleTaskEnd;
143 } // namespace mozilla
145 // A native thread
146 class nsThread : public nsIThreadInternal,
147 public nsISupportsPriority,
148 public nsIDirectTaskDispatcher,
149 private mozilla::LinkedListElement<nsThread> {
150 friend mozilla::LinkedList<nsThread>;
151 friend mozilla::LinkedListElement<nsThread>;
153 public:
154 NS_DECL_THREADSAFE_ISUPPORTS
155 NS_DECL_NSIEVENTTARGET_FULL
156 NS_DECL_NSITHREAD
157 NS_DECL_NSITHREADINTERNAL
158 NS_DECL_NSISUPPORTSPRIORITY
159 NS_DECL_NSIDIRECTTASKDISPATCHER
161 enum MainThreadFlag { MAIN_THREAD, NOT_MAIN_THREAD };
163 nsThread(NotNull<mozilla::SynchronizedEventQueue*> aQueue,
164 MainThreadFlag aMainThread,
165 nsIThreadManager::ThreadCreationOptions aOptions);
167 private:
168 nsThread();
170 public:
171 // Initialize this as a named wrapper for a new PRThread.
172 nsresult Init(const nsACString& aName);
174 // Initialize this as a wrapper for the current PRThread.
175 nsresult InitCurrentThread();
177 // Get this thread's name, thread-safe.
178 void GetThreadName(nsACString& aNameBuffer);
180 // Set this thread's name. Consider using
181 // NS_SetCurrentThreadName if you are not sure.
182 void SetThreadNameInternal(const nsACString& aName);
184 private:
185 // Initializes the mThreadId and stack base/size members, and adds the thread
186 // to the ThreadList().
187 void InitCommon();
189 public:
190 // The PRThread corresponding to this thread.
191 PRThread* GetPRThread() const { return mThread; }
193 const void* StackBase() const { return mStackBase; }
194 size_t StackSize() const { return mStackSize; }
196 uint32_t ThreadId() const { return mThreadId; }
198 // If this flag is true, then the nsThread was created using
199 // nsIThreadManager::NewThread.
200 bool ShutdownRequired() { return mShutdownRequired; }
202 // Lets GetRunningEventDelay() determine if the pool this is part
203 // of has an unstarted thread
204 void SetPoolThreadFreePtr(mozilla::Atomic<bool, mozilla::Relaxed>* aPtr) {
205 mIsAPoolThreadFree = aPtr;
208 void SetScriptObserver(mozilla::CycleCollectedJSContext* aScriptObserver);
210 uint32_t RecursionDepth() const;
212 void ShutdownComplete(NotNull<nsThreadShutdownContext*> aContext);
214 void WaitForAllAsynchronousShutdowns();
216 static const uint32_t kRunnableNameBufSize = 1000;
217 static mozilla::Array<char, kRunnableNameBufSize> sMainThreadRunnableName;
219 mozilla::SynchronizedEventQueue* EventQueue() { return mEvents.get(); }
221 bool ShuttingDown() const { return mShutdownContext != nullptr; }
223 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
225 // Returns the size of this object, its PRThread, and its shutdown contexts,
226 // but excluding its event queues.
227 size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
229 size_t SizeOfEventQueues(mozilla::MallocSizeOf aMallocSizeOf) const;
231 static nsThreadEnumerator Enumerate();
233 void SetUseHangMonitor(bool aValue) {
234 MOZ_ASSERT(IsOnCurrentThread());
235 mUseHangMonitor = aValue;
238 private:
239 void DoMainThreadSpecificProcessing() const;
241 protected:
242 friend class nsThreadShutdownEvent;
244 friend class nsThreadEnumerator;
246 virtual ~nsThread();
248 static void ThreadFunc(void* aArg);
250 // Helper
251 already_AddRefed<nsIThreadObserver> GetObserver() {
252 nsIThreadObserver* obs;
253 nsThread::GetObserver(&obs);
254 return already_AddRefed<nsIThreadObserver>(obs);
257 already_AddRefed<nsThreadShutdownContext> ShutdownInternal(bool aSync);
259 friend class nsThreadManager;
260 friend class nsThreadPool;
262 static mozilla::OffTheBooksMutex& ThreadListMutex();
263 static mozilla::LinkedList<nsThread>& ThreadList();
265 void AddToThreadList();
266 void MaybeRemoveFromThreadList();
268 // Whether or not these members have a value determines whether the nsThread
269 // is treated as a full XPCOM thread or as a thin wrapper.
271 // For full nsThreads, they will always contain valid pointers. For thin
272 // wrappers around non-XPCOM threads, they will be null, and event dispatch
273 // methods which rely on them will fail (and assert) if called.
274 RefPtr<mozilla::SynchronizedEventQueue> mEvents;
275 RefPtr<mozilla::ThreadEventTarget> mEventTarget;
277 // The number of outstanding nsThreadShutdownContext started by this thread.
278 // The thread will not be allowed to exit until this number reaches 0.
279 uint32_t mOutstandingShutdownContexts;
280 // The shutdown context for ourselves.
281 RefPtr<nsThreadShutdownContext> mShutdownContext;
283 mozilla::CycleCollectedJSContext* mScriptObserver;
285 // Our name.
286 mozilla::DataMutex<nsCString> mThreadName;
288 void* mStackBase = nullptr;
289 uint32_t mStackSize;
290 uint32_t mThreadId;
292 uint32_t mNestedEventLoopDepth;
294 mozilla::Atomic<bool> mShutdownRequired;
296 int8_t mPriority;
298 const bool mIsMainThread;
299 bool mUseHangMonitor;
300 const bool mIsUiThread;
301 mozilla::Atomic<bool, mozilla::Relaxed>* mIsAPoolThreadFree;
303 // Set to true if this thread creates a JSRuntime.
304 bool mCanInvokeJS;
306 // The time the currently running event spent in event queues, and
307 // when it started running. If no event is running, they are
308 // TimeDuration() & TimeStamp().
309 mozilla::TimeDuration mLastEventDelay;
310 mozilla::TimeStamp mLastEventStart;
312 #ifdef EARLY_BETA_OR_EARLIER
313 nsCString mNameForWakeupTelemetry;
314 mozilla::TimeStamp mLastWakeupCheckTime;
315 uint32_t mWakeupCount = 0;
316 #endif
318 mozilla::PerformanceCounterState mPerformanceCounterState;
320 mozilla::SimpleTaskQueue mDirectTasks;
323 class nsThreadShutdownContext final : public nsIThreadShutdown {
324 public:
325 NS_DECL_THREADSAFE_ISUPPORTS
326 NS_DECL_NSITHREADSHUTDOWN
328 private:
329 friend class nsThread;
330 friend class nsThreadShutdownEvent;
331 friend class nsThreadShutdownAckEvent;
333 nsThreadShutdownContext(NotNull<nsThread*> aTerminatingThread,
334 nsThread* aJoiningThread)
335 : mTerminatingThread(aTerminatingThread),
336 mTerminatingPRThread(aTerminatingThread->GetPRThread()),
337 mJoiningThreadMutex("nsThreadShutdownContext::mJoiningThreadMutex"),
338 mJoiningThread(aJoiningThread) {}
340 ~nsThreadShutdownContext() = default;
342 // Must be called on the joining thread.
343 void MarkCompleted();
345 // NB: This may be the last reference.
346 NotNull<RefPtr<nsThread>> const mTerminatingThread;
347 PRThread* const mTerminatingPRThread;
349 // May only be accessed on the joining thread.
350 bool mCompleted = false;
351 nsTArray<nsCOMPtr<nsIRunnable>> mCompletionCallbacks;
353 // The thread waiting for this thread to shut down. Will either be cleared by
354 // the joining thread if `StopWaitingAndLeakThread` is called or by the
355 // terminating thread upon exiting and notifying the joining thread.
356 mozilla::Mutex mJoiningThreadMutex;
357 RefPtr<nsThread> mJoiningThread MOZ_GUARDED_BY(mJoiningThreadMutex);
358 bool mThreadLeaked MOZ_GUARDED_BY(mJoiningThreadMutex) = false;
361 class MOZ_STACK_CLASS nsThreadEnumerator final {
362 public:
363 nsThreadEnumerator() = default;
365 auto begin() { return nsThread::ThreadList().begin(); }
366 auto end() { return nsThread::ThreadList().end(); }
368 private:
369 mozilla::OffTheBooksMutexAutoLock mMal{nsThread::ThreadListMutex()};
372 #if defined(XP_UNIX) && !defined(ANDROID) && !defined(DEBUG) && HAVE_UALARM && \
373 defined(_GNU_SOURCE)
374 # define MOZ_CANARY
376 extern int sCanaryOutputFD;
377 #endif
379 #endif // nsThread_h__