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 #ifndef nsThread_h__
8 #define nsThread_h__
9 
10 #include "MainThreadUtils.h"
11 #include "mozilla/AlreadyAddRefed.h"
12 #include "mozilla/Atomics.h"
13 #include "mozilla/Attributes.h"
14 #include "mozilla/EventQueue.h"
15 #include "mozilla/LinkedList.h"
16 #include "mozilla/MemoryReporting.h"
17 #include "mozilla/Mutex.h"
18 #include "mozilla/NotNull.h"
19 #include "mozilla/PerformanceCounter.h"
20 #include "mozilla/RefPtr.h"
21 #include "mozilla/TaskDispatcher.h"
22 #include "mozilla/TimeStamp.h"
23 #include "mozilla/UniquePtr.h"
24 #include "nsIDelayedRunnableObserver.h"
25 #include "nsIDirectTaskDispatcher.h"
26 #include "nsIEventTarget.h"
27 #include "nsISerialEventTarget.h"
28 #include "nsISupportsPriority.h"
29 #include "nsIThread.h"
30 #include "nsIThreadInternal.h"
31 #include "nsTArray.h"
32 
33 namespace mozilla {
34 class CycleCollectedJSContext;
35 class DelayedRunnable;
36 class SynchronizedEventQueue;
37 class ThreadEventQueue;
38 class ThreadEventTarget;
39 
40 template <typename T, size_t Length>
41 class Array;
42 }  // namespace mozilla
43 
44 using mozilla::NotNull;
45 
46 class nsIRunnable;
47 class nsLocalExecutionRecord;
48 class nsThreadEnumerator;
49 
50 // See https://www.w3.org/TR/longtasks
51 #define LONGTASK_BUSY_WINDOW_MS 50
52 
53 // A class for managing performance counter state.
54 namespace mozilla {
55 class PerformanceCounterState {
56  public:
PerformanceCounterState(const uint32_t & aNestedEventLoopDepthRef,bool aIsMainThread)57   explicit PerformanceCounterState(const uint32_t& aNestedEventLoopDepthRef,
58                                    bool aIsMainThread)
59       : mNestedEventLoopDepth(aNestedEventLoopDepthRef),
60         mIsMainThread(aIsMainThread),
61         // Does it really make sense to initialize these to "now" when we
62         // haven't run any tasks?
63         mLastLongTaskEnd(TimeStamp::Now()),
64         mLastLongNonIdleTaskEnd(mLastLongTaskEnd) {}
65 
66   class Snapshot {
67    public:
Snapshot(uint32_t aOldEventLoopDepth,PerformanceCounter * aCounter,bool aOldIsIdleRunnable)68     Snapshot(uint32_t aOldEventLoopDepth, PerformanceCounter* aCounter,
69              bool aOldIsIdleRunnable)
70         : mOldEventLoopDepth(aOldEventLoopDepth),
71           mOldPerformanceCounter(aCounter),
72           mOldIsIdleRunnable(aOldIsIdleRunnable) {}
73 
74     Snapshot(const Snapshot&) = default;
75     Snapshot(Snapshot&&) = default;
76 
77    private:
78     friend class PerformanceCounterState;
79 
80     const uint32_t mOldEventLoopDepth;
81     // Non-const so we can move out of it and avoid the extra refcounting.
82     RefPtr<PerformanceCounter> mOldPerformanceCounter;
83     const bool mOldIsIdleRunnable;
84   };
85 
86   // Notification that a runnable is about to run.  This captures a snapshot of
87   // our current state before we reset to prepare for the new runnable.  This
88   // muast be called after mNestedEventLoopDepth has been incremented for the
89   // runnable execution.  The performance counter passed in should be the one
90   // for the relevant runnable and may be null.  aIsIdleRunnable should be true
91   // if and only if the runnable has idle priority.
92   Snapshot RunnableWillRun(PerformanceCounter* Counter, TimeStamp aNow,
93                            bool aIsIdleRunnable);
94 
95   // Notification that a runnable finished executing.  This must be passed the
96   // snapshot that RunnableWillRun returned for the same runnable.  This must be
97   // called before mNestedEventLoopDepth is decremented after the runnable's
98   // execution.
99   void RunnableDidRun(Snapshot&& aSnapshot);
100 
LastLongTaskEnd()101   const TimeStamp& LastLongTaskEnd() const { return mLastLongTaskEnd; }
LastLongNonIdleTaskEnd()102   const TimeStamp& LastLongNonIdleTaskEnd() const {
103     return mLastLongNonIdleTaskEnd;
104   }
105 
106  private:
107   // Called to report accumulated time, as needed, when we're about to run a
108   // runnable or just finished running one.
109   void MaybeReportAccumulatedTime(TimeStamp aNow);
110 
111   // Whether the runnable we are about to run, or just ran, is a nested
112   // runnable, in the sense that there is some other runnable up the stack
113   // spinning the event loop.  This must be called before we change our
114   // mCurrentEventLoopDepth (when about to run a new event) or after we restore
115   // it (after we ran one).
IsNestedRunnable()116   bool IsNestedRunnable() const {
117     return mNestedEventLoopDepth > mCurrentEventLoopDepth;
118   }
119 
120   // The event loop depth of the currently running runnable.  Set to the max
121   // value of a uint32_t when there is no runnable running, so when starting to
122   // run a toplevel (not nested) runnable IsNestedRunnable() will test false.
123   uint32_t mCurrentEventLoopDepth = std::numeric_limits<uint32_t>::max();
124 
125   // A reference to the nsThread's mNestedEventLoopDepth, so we can
126   // see what it is right now.
127   const uint32_t& mNestedEventLoopDepth;
128 
129   // A boolean that indicates whether the currently running runnable is an idle
130   // runnable.  Only has a useful value between RunnableWillRun() being called
131   // and RunnableDidRun() returning.
132   bool mCurrentRunnableIsIdleRunnable = false;
133 
134   // Whether we're attached to the mainthread nsThread.
135   const bool mIsMainThread;
136 
137   // The timestamp from which time to be accounted for should be measured.  This
138   // can be the start of a runnable running or the end of a nested runnable
139   // running.
140   TimeStamp mCurrentTimeSliceStart;
141 
142   // Information about when long tasks last ended.
143   TimeStamp mLastLongTaskEnd;
144   TimeStamp mLastLongNonIdleTaskEnd;
145 
146   // The performance counter to use for accumulating the runtime of
147   // the currently running event.  May be null, in which case the
148   // event's running time should not be accounted to any performance
149   // counters.
150   RefPtr<PerformanceCounter> mCurrentPerformanceCounter;
151 };
152 }  // namespace mozilla
153 
154 // A native thread
155 class nsThread : public nsIThreadInternal,
156                  public nsISupportsPriority,
157                  public nsIDelayedRunnableObserver,
158                  public nsIDirectTaskDispatcher,
159                  private mozilla::LinkedListElement<nsThread> {
160   friend mozilla::LinkedList<nsThread>;
161   friend mozilla::LinkedListElement<nsThread>;
162 
163  public:
164   NS_DECL_THREADSAFE_ISUPPORTS
165   NS_DECL_NSIEVENTTARGET_FULL
166   NS_DECL_NSITHREAD
167   NS_DECL_NSITHREADINTERNAL
168   NS_DECL_NSISUPPORTSPRIORITY
169   NS_DECL_NSIDIRECTTASKDISPATCHER
170 
171   enum MainThreadFlag { MAIN_THREAD, NOT_MAIN_THREAD };
172 
173   nsThread(NotNull<mozilla::SynchronizedEventQueue*> aQueue,
174            MainThreadFlag aMainThread, uint32_t aStackSize);
175 
176  private:
177   nsThread();
178 
179  public:
180   // Initialize this as a named wrapper for a new PRThread.
181   nsresult Init(const nsACString& aName);
182 
183   // Initialize this as a wrapper for the current PRThread.
184   nsresult InitCurrentThread();
185 
186  private:
187   // Initializes the mThreadId and stack base/size members, and adds the thread
188   // to the ThreadList().
189   void InitCommon();
190 
191  public:
192   // The PRThread corresponding to this thread.
GetPRThread()193   PRThread* GetPRThread() const { return mThread; }
194 
StackBase()195   const void* StackBase() const { return mStackBase; }
StackSize()196   size_t StackSize() const { return mStackSize; }
197 
ThreadId()198   uint32_t ThreadId() const { return mThreadId; }
199 
200   // If this flag is true, then the nsThread was created using
201   // nsIThreadManager::NewThread.
ShutdownRequired()202   bool ShutdownRequired() { return mShutdownRequired; }
203 
204   // Lets GetRunningEventDelay() determine if the pool this is part
205   // of has an unstarted thread
SetPoolThreadFreePtr(mozilla::Atomic<bool,mozilla::Relaxed> * aPtr)206   void SetPoolThreadFreePtr(mozilla::Atomic<bool, mozilla::Relaxed>* aPtr) {
207     mIsAPoolThreadFree = aPtr;
208   }
209 
210   void SetScriptObserver(mozilla::CycleCollectedJSContext* aScriptObserver);
211 
212   uint32_t RecursionDepth() const;
213 
214   void ShutdownComplete(NotNull<struct nsThreadShutdownContext*> aContext);
215 
216   void WaitForAllAsynchronousShutdowns();
217 
218   static const uint32_t kRunnableNameBufSize = 1000;
219   static mozilla::Array<char, kRunnableNameBufSize> sMainThreadRunnableName;
220 
EventQueue()221   mozilla::SynchronizedEventQueue* EventQueue() { return mEvents.get(); }
222 
ShuttingDown()223   bool ShuttingDown() const { return mShutdownContext != nullptr; }
224 
225   static bool GetLabeledRunnableName(nsIRunnable* aEvent, nsACString& aName,
226                                      mozilla::EventQueuePriority aPriority);
227 
228   virtual mozilla::PerformanceCounter* GetPerformanceCounter(
229       nsIRunnable* aEvent) const;
230 
231   static mozilla::PerformanceCounter* GetPerformanceCounterBase(
232       nsIRunnable* aEvent);
233 
234   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
235 
236   // Returns the size of this object, its PRThread, and its shutdown contexts,
237   // but excluding its event queues.
238   size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
239 
240   size_t SizeOfEventQueues(mozilla::MallocSizeOf aMallocSizeOf) const;
241 
242   static nsThreadEnumerator Enumerate();
243 
244   // When entering local execution mode a new event queue is created and used as
245   // an event source. This queue is only accessible through an
246   // nsLocalExecutionGuard constructed from the nsLocalExecutionRecord returned
247   // by this function, effectively restricting the events that get run while in
248   // local execution mode to those dispatched by the owner of the guard object.
249   //
250   // Local execution is not nestable. When the nsLocalExecutionGuard is
251   // destructed, the thread exits the local execution mode.
252   //
253   // Note that code run in local execution mode is not considered a task in the
254   // spec sense. Events from the local queue are considered part of the
255   // enclosing task and as such do not trigger profiling hooks, observer
256   // notifications, etc.
257   nsLocalExecutionRecord EnterLocalExecution();
258 
SetUseHangMonitor(bool aValue)259   void SetUseHangMonitor(bool aValue) {
260     MOZ_ASSERT(IsOnCurrentThread());
261     mUseHangMonitor = aValue;
262   }
263 
264   void OnDelayedRunnableCreated(mozilla::DelayedRunnable* aRunnable) override;
265   void OnDelayedRunnableScheduled(mozilla::DelayedRunnable* aRunnable) override;
266   void OnDelayedRunnableRan(mozilla::DelayedRunnable* aRunnable) override;
267 
268  private:
269   void DoMainThreadSpecificProcessing() const;
270 
271  protected:
272   friend class nsThreadShutdownEvent;
273 
274   friend class nsThreadEnumerator;
275 
276   virtual ~nsThread();
277 
278   static void ThreadFunc(void* aArg);
279 
280   // Helper
GetObserver()281   already_AddRefed<nsIThreadObserver> GetObserver() {
282     nsIThreadObserver* obs;
283     nsThread::GetObserver(&obs);
284     return already_AddRefed<nsIThreadObserver>(obs);
285   }
286 
287   struct nsThreadShutdownContext* ShutdownInternal(bool aSync);
288 
289   friend class nsThreadManager;
290   friend class nsThreadPool;
291 
292   static mozilla::OffTheBooksMutex& ThreadListMutex();
293   static mozilla::LinkedList<nsThread>& ThreadList();
294   static void ClearThreadList();
295 
296   void AddToThreadList();
297   void MaybeRemoveFromThreadList();
298 
299   // Whether or not these members have a value determines whether the nsThread
300   // is treated as a full XPCOM thread or as a thin wrapper.
301   //
302   // For full nsThreads, they will always contain valid pointers. For thin
303   // wrappers around non-XPCOM threads, they will be null, and event dispatch
304   // methods which rely on them will fail (and assert) if called.
305   RefPtr<mozilla::SynchronizedEventQueue> mEvents;
306   RefPtr<mozilla::ThreadEventTarget> mEventTarget;
307 
308   // The shutdown contexts for any other threads we've asked to shut down.
309   using ShutdownContexts =
310       nsTArray<mozilla::UniquePtr<struct nsThreadShutdownContext>>;
311 
312   // Helper for finding a ShutdownContext in the contexts array.
313   struct ShutdownContextsComp {
314     bool Equals(const ShutdownContexts::elem_type& a,
315                 const ShutdownContexts::elem_type::Pointer b) const;
316   };
317 
318   ShutdownContexts mRequestedShutdownContexts;
319   // The shutdown context for ourselves.
320   struct nsThreadShutdownContext* mShutdownContext;
321 
322   mozilla::CycleCollectedJSContext* mScriptObserver;
323 
324   void* mStackBase = nullptr;
325   uint32_t mStackSize;
326   uint32_t mThreadId;
327 
328   uint32_t mNestedEventLoopDepth;
329 
330   mozilla::Atomic<bool> mShutdownRequired;
331 
332   int8_t mPriority;
333 
334   const bool mIsMainThread;
335   bool mUseHangMonitor;
336   mozilla::Atomic<bool, mozilla::Relaxed>* mIsAPoolThreadFree;
337 
338   // Set to true if this thread creates a JSRuntime.
339   bool mCanInvokeJS;
340 
341   bool mHasTLSEntry = false;
342 
343   // The time the currently running event spent in event queues, and
344   // when it started running.  If no event is running, they are
345   // TimeDuration() & TimeStamp().
346   mozilla::TimeDuration mLastEventDelay;
347   mozilla::TimeStamp mLastEventStart;
348 
349 #ifdef EARLY_BETA_OR_EARLIER
350   nsCString mNameForWakeupTelemetry;
351   mozilla::TimeStamp mLastWakeupCheckTime;
352   uint32_t mWakeupCount = 0;
353 #endif
354 
355   mozilla::PerformanceCounterState mPerformanceCounterState;
356 
357   bool mIsInLocalExecutionMode = false;
358 
359   mozilla::SimpleTaskQueue mDirectTasks;
360 };
361 
362 struct nsThreadShutdownContext {
nsThreadShutdownContextnsThreadShutdownContext363   nsThreadShutdownContext(NotNull<nsThread*> aTerminatingThread,
364                           NotNull<nsThread*> aJoiningThread,
365                           bool aAwaitingShutdownAck)
366       : mTerminatingThread(aTerminatingThread),
367         mTerminatingPRThread(aTerminatingThread->GetPRThread()),
368         mJoiningThread(aJoiningThread),
369         mAwaitingShutdownAck(aAwaitingShutdownAck),
370         mIsMainThreadJoining(NS_IsMainThread()) {
371     MOZ_COUNT_CTOR(nsThreadShutdownContext);
372   }
373   MOZ_COUNTED_DTOR(nsThreadShutdownContext)
374 
375   // NB: This will be the last reference.
376   NotNull<RefPtr<nsThread>> mTerminatingThread;
377   PRThread* const mTerminatingPRThread;
378   NotNull<nsThread*> MOZ_UNSAFE_REF(
379       "Thread manager is holding reference to joining thread") mJoiningThread;
380   bool mAwaitingShutdownAck;
381   bool mIsMainThreadJoining;
382 };
383 
384 // This RAII class controls the duration of the associated nsThread's local
385 // execution mode and provides access to the local event target. (See
386 // nsThread::EnterLocalExecution() for details.) It is constructed from an
387 // nsLocalExecutionRecord, which can only be constructed by nsThread.
388 class MOZ_RAII nsLocalExecutionGuard final {
389  public:
390   MOZ_IMPLICIT nsLocalExecutionGuard(
391       nsLocalExecutionRecord&& aLocalExecutionRecord);
392   nsLocalExecutionGuard(const nsLocalExecutionGuard&) = delete;
393   nsLocalExecutionGuard(nsLocalExecutionGuard&&) = delete;
394   ~nsLocalExecutionGuard();
395 
GetEventTarget()396   nsCOMPtr<nsISerialEventTarget> GetEventTarget() const {
397     return mLocalEventTarget;
398   }
399 
400  private:
401   mozilla::SynchronizedEventQueue& mEventQueueStack;
402   nsCOMPtr<nsISerialEventTarget> mLocalEventTarget;
403   bool& mLocalExecutionFlag;
404 };
405 
406 class MOZ_TEMPORARY_CLASS nsLocalExecutionRecord final {
407  private:
408   friend class nsThread;
409   friend class nsLocalExecutionGuard;
410 
nsLocalExecutionRecord(mozilla::SynchronizedEventQueue & aEventQueueStack,bool & aLocalExecutionFlag)411   nsLocalExecutionRecord(mozilla::SynchronizedEventQueue& aEventQueueStack,
412                          bool& aLocalExecutionFlag)
413       : mEventQueueStack(aEventQueueStack),
414         mLocalExecutionFlag(aLocalExecutionFlag) {}
415 
416   nsLocalExecutionRecord(nsLocalExecutionRecord&&) = default;
417 
418  public:
419   nsLocalExecutionRecord(const nsLocalExecutionRecord&) = delete;
420 
421  private:
422   mozilla::SynchronizedEventQueue& mEventQueueStack;
423   bool& mLocalExecutionFlag;
424 };
425 
426 class MOZ_STACK_CLASS nsThreadEnumerator final {
427  public:
428   nsThreadEnumerator() = default;
429 
begin()430   auto begin() { return nsThread::ThreadList().begin(); }
end()431   auto end() { return nsThread::ThreadList().end(); }
432 
433  private:
434   mozilla::OffTheBooksMutexAutoLock mMal{nsThread::ThreadListMutex()};
435 };
436 
437 #if defined(XP_UNIX) && !defined(ANDROID) && !defined(DEBUG) && HAVE_UALARM && \
438     defined(_GNU_SOURCE)
439 #  define MOZ_CANARY
440 
441 extern int sCanaryOutputFD;
442 #endif
443 
444 #endif  // nsThread_h__
445