Bug 1755481: correct documentation of `nsIClipboard::getData`. r=mccr8
[gecko.git] / xpcom / threads / nsThread.h
blob639d9d42bc1ae52b59465de2c8c94c3def0abdc8
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/PerformanceCounter.h"
21 #include "mozilla/RefPtr.h"
22 #include "mozilla/TaskDispatcher.h"
23 #include "mozilla/TimeStamp.h"
24 #include "mozilla/UniquePtr.h"
25 #include "nsIDelayedRunnableObserver.h"
26 #include "nsIDirectTaskDispatcher.h"
27 #include "nsIEventTarget.h"
28 #include "nsISerialEventTarget.h"
29 #include "nsISupportsPriority.h"
30 #include "nsIThread.h"
31 #include "nsIThreadInternal.h"
32 #include "nsTArray.h"
34 namespace mozilla {
35 class CycleCollectedJSContext;
36 class DelayedRunnable;
37 class SynchronizedEventQueue;
38 class ThreadEventQueue;
39 class ThreadEventTarget;
41 template <typename T, size_t Length>
42 class Array;
43 } // namespace mozilla
45 using mozilla::NotNull;
47 class nsIRunnable;
48 class nsLocalExecutionRecord;
49 class nsThreadEnumerator;
50 class nsThreadShutdownContext;
52 // See https://www.w3.org/TR/longtasks
53 #define LONGTASK_BUSY_WINDOW_MS 50
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, PerformanceCounter* aCounter,
71 bool aOldIsIdleRunnable)
72 : mOldEventLoopDepth(aOldEventLoopDepth),
73 mOldPerformanceCounter(aCounter),
74 mOldIsIdleRunnable(aOldIsIdleRunnable) {}
76 Snapshot(const Snapshot&) = default;
77 Snapshot(Snapshot&&) = default;
79 private:
80 friend class PerformanceCounterState;
82 const uint32_t mOldEventLoopDepth;
83 // Non-const so we can move out of it and avoid the extra refcounting.
84 RefPtr<PerformanceCounter> mOldPerformanceCounter;
85 const bool mOldIsIdleRunnable;
88 // Notification that a runnable is about to run. This captures a snapshot of
89 // our current state before we reset to prepare for the new runnable. This
90 // muast be called after mNestedEventLoopDepth has been incremented for the
91 // runnable execution. The performance counter passed in should be the one
92 // for the relevant runnable and may be null. aIsIdleRunnable should be true
93 // if and only if the runnable has idle priority.
94 Snapshot RunnableWillRun(PerformanceCounter* Counter, TimeStamp aNow,
95 bool aIsIdleRunnable);
97 // Notification that a runnable finished executing. This must be passed the
98 // snapshot that RunnableWillRun returned for the same runnable. This must be
99 // called before mNestedEventLoopDepth is decremented after the runnable's
100 // execution.
101 void RunnableDidRun(Snapshot&& aSnapshot);
103 const TimeStamp& LastLongTaskEnd() const { return mLastLongTaskEnd; }
104 const TimeStamp& LastLongNonIdleTaskEnd() const {
105 return mLastLongNonIdleTaskEnd;
108 private:
109 // Called to report accumulated time, as needed, when we're about to run a
110 // runnable or just finished running one.
111 void MaybeReportAccumulatedTime(TimeStamp aNow);
113 // Whether the runnable we are about to run, or just ran, is a nested
114 // runnable, in the sense that there is some other runnable up the stack
115 // spinning the event loop. This must be called before we change our
116 // mCurrentEventLoopDepth (when about to run a new event) or after we restore
117 // it (after we ran one).
118 bool IsNestedRunnable() const {
119 return mNestedEventLoopDepth > mCurrentEventLoopDepth;
122 // The event loop depth of the currently running runnable. Set to the max
123 // value of a uint32_t when there is no runnable running, so when starting to
124 // run a toplevel (not nested) runnable IsNestedRunnable() will test false.
125 uint32_t mCurrentEventLoopDepth = std::numeric_limits<uint32_t>::max();
127 // A reference to the nsThread's mNestedEventLoopDepth, so we can
128 // see what it is right now.
129 const uint32_t& mNestedEventLoopDepth;
131 // A boolean that indicates whether the currently running runnable is an idle
132 // runnable. Only has a useful value between RunnableWillRun() being called
133 // and RunnableDidRun() returning.
134 bool mCurrentRunnableIsIdleRunnable = false;
136 // Whether we're attached to the mainthread nsThread.
137 const bool mIsMainThread;
139 // The timestamp from which time to be accounted for should be measured. This
140 // can be the start of a runnable running or the end of a nested runnable
141 // running.
142 TimeStamp mCurrentTimeSliceStart;
144 // Information about when long tasks last ended.
145 TimeStamp mLastLongTaskEnd;
146 TimeStamp mLastLongNonIdleTaskEnd;
148 // The performance counter to use for accumulating the runtime of
149 // the currently running event. May be null, in which case the
150 // event's running time should not be accounted to any performance
151 // counters.
152 RefPtr<PerformanceCounter> mCurrentPerformanceCounter;
154 } // namespace mozilla
156 // A native thread
157 class nsThread : public nsIThreadInternal,
158 public nsISupportsPriority,
159 public nsIDelayedRunnableObserver,
160 public nsIDirectTaskDispatcher,
161 private mozilla::LinkedListElement<nsThread> {
162 friend mozilla::LinkedList<nsThread>;
163 friend mozilla::LinkedListElement<nsThread>;
165 public:
166 NS_DECL_THREADSAFE_ISUPPORTS
167 NS_DECL_NSIEVENTTARGET_FULL
168 NS_DECL_NSITHREAD
169 NS_DECL_NSITHREADINTERNAL
170 NS_DECL_NSISUPPORTSPRIORITY
171 NS_DECL_NSIDIRECTTASKDISPATCHER
173 enum MainThreadFlag { MAIN_THREAD, NOT_MAIN_THREAD };
175 nsThread(NotNull<mozilla::SynchronizedEventQueue*> aQueue,
176 MainThreadFlag aMainThread, uint32_t aStackSize);
178 private:
179 nsThread();
181 public:
182 // Initialize this as a named wrapper for a new PRThread.
183 nsresult Init(const nsACString& aName);
185 // Initialize this as a wrapper for the current PRThread.
186 nsresult InitCurrentThread();
188 // Get this thread's name, thread-safe.
189 void GetThreadName(nsACString& aNameBuffer);
191 // Set this thread's name. Consider using
192 // NS_SetCurrentThreadName if you are not sure.
193 void SetThreadNameInternal(const nsACString& aName);
195 private:
196 // Initializes the mThreadId and stack base/size members, and adds the thread
197 // to the ThreadList().
198 void InitCommon();
200 public:
201 // The PRThread corresponding to this thread.
202 PRThread* GetPRThread() const { return mThread; }
204 const void* StackBase() const { return mStackBase; }
205 size_t StackSize() const { return mStackSize; }
207 uint32_t ThreadId() const { return mThreadId; }
209 // If this flag is true, then the nsThread was created using
210 // nsIThreadManager::NewThread.
211 bool ShutdownRequired() { return mShutdownRequired; }
213 // Lets GetRunningEventDelay() determine if the pool this is part
214 // of has an unstarted thread
215 void SetPoolThreadFreePtr(mozilla::Atomic<bool, mozilla::Relaxed>* aPtr) {
216 mIsAPoolThreadFree = aPtr;
219 void SetScriptObserver(mozilla::CycleCollectedJSContext* aScriptObserver);
221 uint32_t RecursionDepth() const;
223 void ShutdownComplete(NotNull<nsThreadShutdownContext*> aContext);
225 void WaitForAllAsynchronousShutdowns();
227 static const uint32_t kRunnableNameBufSize = 1000;
228 static mozilla::Array<char, kRunnableNameBufSize> sMainThreadRunnableName;
230 mozilla::SynchronizedEventQueue* EventQueue() { return mEvents.get(); }
232 bool ShuttingDown() const { return mShutdownContext != nullptr; }
234 static bool GetLabeledRunnableName(nsIRunnable* aEvent, nsACString& aName,
235 mozilla::EventQueuePriority aPriority);
237 virtual mozilla::PerformanceCounter* GetPerformanceCounter(
238 nsIRunnable* aEvent) const;
240 static mozilla::PerformanceCounter* GetPerformanceCounterBase(
241 nsIRunnable* aEvent);
243 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
245 // Returns the size of this object, its PRThread, and its shutdown contexts,
246 // but excluding its event queues.
247 size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
249 size_t SizeOfEventQueues(mozilla::MallocSizeOf aMallocSizeOf) const;
251 static nsThreadEnumerator Enumerate();
253 // When entering local execution mode a new event queue is created and used as
254 // an event source. This queue is only accessible through an
255 // nsLocalExecutionGuard constructed from the nsLocalExecutionRecord returned
256 // by this function, effectively restricting the events that get run while in
257 // local execution mode to those dispatched by the owner of the guard object.
259 // Local execution is not nestable. When the nsLocalExecutionGuard is
260 // destructed, the thread exits the local execution mode.
262 // Note that code run in local execution mode is not considered a task in the
263 // spec sense. Events from the local queue are considered part of the
264 // enclosing task and as such do not trigger profiling hooks, observer
265 // notifications, etc.
266 nsLocalExecutionRecord EnterLocalExecution();
268 void SetUseHangMonitor(bool aValue) {
269 MOZ_ASSERT(IsOnCurrentThread());
270 mUseHangMonitor = aValue;
273 void OnDelayedRunnableCreated(mozilla::DelayedRunnable* aRunnable) override;
274 void OnDelayedRunnableScheduled(mozilla::DelayedRunnable* aRunnable) override;
275 void OnDelayedRunnableRan(mozilla::DelayedRunnable* aRunnable) override;
277 private:
278 void DoMainThreadSpecificProcessing() const;
280 protected:
281 friend class nsThreadShutdownEvent;
283 friend class nsThreadEnumerator;
285 virtual ~nsThread();
287 static void ThreadFunc(void* aArg);
289 // Helper
290 already_AddRefed<nsIThreadObserver> GetObserver() {
291 nsIThreadObserver* obs;
292 nsThread::GetObserver(&obs);
293 return already_AddRefed<nsIThreadObserver>(obs);
296 already_AddRefed<nsThreadShutdownContext> ShutdownInternal(bool aSync);
298 friend class nsThreadManager;
299 friend class nsThreadPool;
301 static mozilla::OffTheBooksMutex& ThreadListMutex();
302 static mozilla::LinkedList<nsThread>& ThreadList();
303 static void ClearThreadList();
305 void AddToThreadList();
306 void MaybeRemoveFromThreadList();
308 // Whether or not these members have a value determines whether the nsThread
309 // is treated as a full XPCOM thread or as a thin wrapper.
311 // For full nsThreads, they will always contain valid pointers. For thin
312 // wrappers around non-XPCOM threads, they will be null, and event dispatch
313 // methods which rely on them will fail (and assert) if called.
314 RefPtr<mozilla::SynchronizedEventQueue> mEvents;
315 RefPtr<mozilla::ThreadEventTarget> mEventTarget;
317 // The number of outstanding nsThreadShutdownContext started by this thread.
318 // The thread will not be allowed to exit until this number reaches 0.
319 uint32_t mOutstandingShutdownContexts;
320 // The shutdown context for ourselves.
321 RefPtr<nsThreadShutdownContext> mShutdownContext;
323 mozilla::CycleCollectedJSContext* mScriptObserver;
325 // Our name.
326 mozilla::DataMutex<nsCString> mThreadName;
328 void* mStackBase = nullptr;
329 uint32_t mStackSize;
330 uint32_t mThreadId;
332 uint32_t mNestedEventLoopDepth;
334 mozilla::Atomic<bool> mShutdownRequired;
336 int8_t mPriority;
338 const bool mIsMainThread;
339 bool mUseHangMonitor;
340 mozilla::Atomic<bool, mozilla::Relaxed>* mIsAPoolThreadFree;
342 // Set to true if this thread creates a JSRuntime.
343 bool mCanInvokeJS;
345 bool mHasTLSEntry = false;
347 // The time the currently running event spent in event queues, and
348 // when it started running. If no event is running, they are
349 // TimeDuration() & TimeStamp().
350 mozilla::TimeDuration mLastEventDelay;
351 mozilla::TimeStamp mLastEventStart;
353 #ifdef EARLY_BETA_OR_EARLIER
354 nsCString mNameForWakeupTelemetry;
355 mozilla::TimeStamp mLastWakeupCheckTime;
356 uint32_t mWakeupCount = 0;
357 #endif
359 mozilla::PerformanceCounterState mPerformanceCounterState;
361 bool mIsInLocalExecutionMode = false;
363 mozilla::SimpleTaskQueue mDirectTasks;
366 class nsThreadShutdownContext final : public nsIThreadShutdown {
367 public:
368 NS_DECL_THREADSAFE_ISUPPORTS
369 NS_DECL_NSITHREADSHUTDOWN
371 private:
372 friend class nsThread;
373 friend class nsThreadShutdownEvent;
374 friend class nsThreadShutdownAckEvent;
376 nsThreadShutdownContext(NotNull<nsThread*> aTerminatingThread,
377 nsThread* aJoiningThread)
378 : mTerminatingThread(aTerminatingThread),
379 mTerminatingPRThread(aTerminatingThread->GetPRThread()),
380 mJoiningThread(aJoiningThread,
381 "nsThreadShutdownContext::mJoiningThread") {}
383 ~nsThreadShutdownContext() = default;
385 // Must be called on the joining thread.
386 void MarkCompleted();
388 // NB: This may be the last reference.
389 NotNull<RefPtr<nsThread>> const mTerminatingThread;
390 PRThread* const mTerminatingPRThread;
392 // May only be accessed on the joining thread.
393 bool mCompleted = false;
394 nsTArray<nsCOMPtr<nsIRunnable>> mCompletionCallbacks;
396 // The thread waiting for this thread to shut down. Will either be cleared by
397 // the joining thread if `StopWaitingAndLeakThread` is called or by the
398 // terminating thread upon exiting and notifying the joining thread.
399 mozilla::DataMutex<RefPtr<nsThread>> mJoiningThread;
402 // This RAII class controls the duration of the associated nsThread's local
403 // execution mode and provides access to the local event target. (See
404 // nsThread::EnterLocalExecution() for details.) It is constructed from an
405 // nsLocalExecutionRecord, which can only be constructed by nsThread.
406 class MOZ_RAII nsLocalExecutionGuard final {
407 public:
408 MOZ_IMPLICIT nsLocalExecutionGuard(
409 nsLocalExecutionRecord&& aLocalExecutionRecord);
410 nsLocalExecutionGuard(const nsLocalExecutionGuard&) = delete;
411 nsLocalExecutionGuard(nsLocalExecutionGuard&&) = delete;
412 ~nsLocalExecutionGuard();
414 nsCOMPtr<nsISerialEventTarget> GetEventTarget() const {
415 return mLocalEventTarget;
418 private:
419 mozilla::SynchronizedEventQueue& mEventQueueStack;
420 nsCOMPtr<nsISerialEventTarget> mLocalEventTarget;
421 bool& mLocalExecutionFlag;
424 class MOZ_TEMPORARY_CLASS nsLocalExecutionRecord final {
425 private:
426 friend class nsThread;
427 friend class nsLocalExecutionGuard;
429 nsLocalExecutionRecord(mozilla::SynchronizedEventQueue& aEventQueueStack,
430 bool& aLocalExecutionFlag)
431 : mEventQueueStack(aEventQueueStack),
432 mLocalExecutionFlag(aLocalExecutionFlag) {}
434 nsLocalExecutionRecord(nsLocalExecutionRecord&&) = default;
436 public:
437 nsLocalExecutionRecord(const nsLocalExecutionRecord&) = delete;
439 private:
440 mozilla::SynchronizedEventQueue& mEventQueueStack;
441 bool& mLocalExecutionFlag;
444 class MOZ_STACK_CLASS nsThreadEnumerator final {
445 public:
446 nsThreadEnumerator() = default;
448 auto begin() { return nsThread::ThreadList().begin(); }
449 auto end() { return nsThread::ThreadList().end(); }
451 private:
452 mozilla::OffTheBooksMutexAutoLock mMal{nsThread::ThreadListMutex()};
455 #if defined(XP_UNIX) && !defined(ANDROID) && !defined(DEBUG) && HAVE_UALARM && \
456 defined(_GNU_SOURCE)
457 # define MOZ_CANARY
459 extern int sCanaryOutputFD;
460 #endif
462 #endif // nsThread_h__