Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "ThreadResponsiveness.h"
7 : #include "platform.h"
8 : #include "nsComponentManagerUtils.h"
9 : #include "nsThreadUtils.h"
10 : #include "nsITimer.h"
11 : #include "mozilla/Mutex.h"
12 :
13 : using mozilla::Mutex;
14 : using mozilla::MutexAutoLock;
15 : using mozilla::TimeStamp;
16 :
17 : class CheckResponsivenessTask : public mozilla::Runnable,
18 : public nsITimerCallback {
19 : public:
20 0 : CheckResponsivenessTask()
21 0 : : mozilla::Runnable("CheckResponsivenessTask")
22 : , mLastTracerTime(TimeStamp::Now())
23 : , mMutex("CheckResponsivenessTask")
24 : , mTimer(nullptr)
25 : , mHasEverBeenSuccessfullyDispatched(false)
26 0 : , mStop(false)
27 : {
28 0 : }
29 :
30 : protected:
31 0 : ~CheckResponsivenessTask()
32 0 : {
33 0 : }
34 :
35 : public:
36 :
37 : // Must be called from the same thread every time. Call that the "update"
38 : // thread, because it's the thread that ThreadResponsiveness::Update() is
39 : // called on. In reality it's the profiler's sampler thread.
40 0 : void DoFirstDispatchIfNeeded()
41 : {
42 0 : if (mHasEverBeenSuccessfullyDispatched) {
43 0 : return;
44 : }
45 :
46 : // Dispatching can fail during early startup, particularly when
47 : // MOZ_PROFILER_STARTUP is used.
48 0 : nsresult rv = NS_DispatchToMainThread(this);
49 0 : if (NS_SUCCEEDED(rv)) {
50 0 : mHasEverBeenSuccessfullyDispatched = true;
51 : }
52 : }
53 :
54 : // Can only run on the main thread.
55 0 : NS_IMETHOD Run() override
56 : {
57 0 : MutexAutoLock mon(mMutex);
58 0 : if (mStop)
59 0 : return NS_OK;
60 :
61 : // This is raced on because we might pause the thread here
62 : // for profiling so if we tried to use a monitor to protect
63 : // mLastTracerTime we could deadlock. We're risking seeing
64 : // a partial write which will show up as an outlier in our
65 : // performance data.
66 0 : mLastTracerTime = TimeStamp::Now();
67 0 : if (!mTimer) {
68 0 : mTimer = do_CreateInstance("@mozilla.org/timer;1");
69 : }
70 0 : mTimer->InitWithCallback(this, 16, nsITimer::TYPE_ONE_SHOT);
71 :
72 0 : return NS_OK;
73 : }
74 :
75 0 : NS_IMETHOD Notify(nsITimer* aTimer) final
76 : {
77 0 : NS_DispatchToMainThread(this);
78 0 : return NS_OK;
79 : }
80 :
81 0 : void Terminate() {
82 0 : MutexAutoLock mon(mMutex);
83 0 : mStop = true;
84 0 : }
85 :
86 0 : const TimeStamp& GetLastTracerTime() const {
87 0 : return mLastTracerTime;
88 : }
89 :
90 : NS_DECL_ISUPPORTS_INHERITED
91 :
92 : private:
93 : TimeStamp mLastTracerTime;
94 : Mutex mMutex;
95 : nsCOMPtr<nsITimer> mTimer;
96 : bool mHasEverBeenSuccessfullyDispatched; // only accessed on the "update" thread
97 : bool mStop;
98 : };
99 :
100 0 : NS_IMPL_ISUPPORTS_INHERITED(CheckResponsivenessTask, mozilla::Runnable,
101 : nsITimerCallback)
102 :
103 0 : ThreadResponsiveness::ThreadResponsiveness()
104 0 : : mActiveTracerEvent(new CheckResponsivenessTask())
105 : {
106 0 : MOZ_COUNT_CTOR(ThreadResponsiveness);
107 0 : }
108 :
109 0 : ThreadResponsiveness::~ThreadResponsiveness()
110 : {
111 0 : MOZ_COUNT_DTOR(ThreadResponsiveness);
112 0 : mActiveTracerEvent->Terminate();
113 0 : }
114 :
115 : void
116 0 : ThreadResponsiveness::Update()
117 : {
118 0 : mActiveTracerEvent->DoFirstDispatchIfNeeded();
119 0 : mLastTracerTime = mActiveTracerEvent->GetLastTracerTime();
120 0 : }
121 :
|