Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
1 /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
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/. */
6 #ifndef nsBaseAppShell_h__
7 #define nsBaseAppShell_h__
9 #include "mozilla/Atomics.h"
10 #include "nsIAppShell.h"
11 #include "nsIThreadInternal.h"
12 #include "nsIObserver.h"
13 #include "nsIRunnable.h"
14 #include "nsCOMPtr.h"
15 #include "nsTArray.h"
16 #include "prinrval.h"
18 /**
19 * A singleton that manages the UI thread's event queue. Subclass this class
20 * to enable platform-specific event queue support.
21 */
22 class nsBaseAppShell : public nsIAppShell, public nsIThreadObserver,
23 public nsIObserver
24 {
25 public:
26 NS_DECL_THREADSAFE_ISUPPORTS
27 NS_DECL_NSIAPPSHELL
28 NS_DECL_NSITHREADOBSERVER
29 NS_DECL_NSIOBSERVER
31 nsBaseAppShell();
33 protected:
34 virtual ~nsBaseAppShell();
36 /**
37 * This method is called by subclasses when the app shell singleton is
38 * instantiated.
39 */
40 nsresult Init();
42 /**
43 * Called by subclasses from a native event. See ScheduleNativeEventCallback.
44 */
45 void NativeEventCallback();
47 /**
48 * Make a decision as to whether or not NativeEventCallback will
49 * trigger gecko event processing when there are pending gecko
50 * events.
51 */
52 virtual void DoProcessMoreGeckoEvents();
54 /**
55 * Implemented by subclasses. Invoke NativeEventCallback from a native
56 * event. This method may be called on any thread.
57 */
58 virtual void ScheduleNativeEventCallback() = 0;
60 /**
61 * Implemented by subclasses. Process the next native event. Only wait for
62 * the next native event if mayWait is true. This method is only called on
63 * the main application thread.
64 *
65 * @param mayWait
66 * If "true", then this method may wait if necessary for the next available
67 * native event. DispatchNativeEvent may be called to unblock a call to
68 * ProcessNextNativeEvent that is waiting.
69 * @return
70 * This method returns "true" if a native event was processed.
71 */
72 virtual bool ProcessNextNativeEvent(bool mayWait) = 0;
74 int32_t mSuspendNativeCount;
75 uint32_t mEventloopNestingLevel;
77 private:
78 bool DoProcessNextNativeEvent(bool mayWait, uint32_t recursionDepth);
80 bool DispatchDummyEvent(nsIThread* target);
82 void IncrementEventloopNestingLevel();
83 void DecrementEventloopNestingLevel();
85 /**
86 * Runs all synchronous sections which are queued up in mSyncSections.
87 */
88 void RunSyncSectionsInternal(bool stable, uint32_t threadRecursionLevel);
90 void RunSyncSections(bool stable, uint32_t threadRecursionLevel)
91 {
92 if (!mSyncSections.IsEmpty()) {
93 RunSyncSectionsInternal(stable, threadRecursionLevel);
94 }
95 }
97 void ScheduleSyncSection(nsIRunnable* runnable, bool stable);
99 struct SyncSection {
100 SyncSection()
101 : mStable(false), mEventloopNestingLevel(0), mThreadRecursionLevel(0)
102 { }
104 void Forget(SyncSection* other) {
105 other->mStable = mStable;
106 other->mEventloopNestingLevel = mEventloopNestingLevel;
107 other->mThreadRecursionLevel = mThreadRecursionLevel;
108 other->mRunnable = mRunnable.forget();
109 }
111 bool mStable;
112 uint32_t mEventloopNestingLevel;
113 uint32_t mThreadRecursionLevel;
114 nsCOMPtr<nsIRunnable> mRunnable;
115 };
117 nsCOMPtr<nsIRunnable> mDummyEvent;
118 /**
119 * mBlockedWait points back to a slot that controls the wait loop in
120 * an outer OnProcessNextEvent invocation. Nested calls always set
121 * it to false to unblock an outer loop, since all events may
122 * have been consumed by the inner event loop(s).
123 */
124 bool *mBlockedWait;
125 int32_t mFavorPerf;
126 mozilla::Atomic<bool> mNativeEventPending;
127 PRIntervalTime mStarvationDelay;
128 PRIntervalTime mSwitchTime;
129 PRIntervalTime mLastNativeEventTime;
130 enum EventloopNestingState {
131 eEventloopNone, // top level thread execution
132 eEventloopXPCOM, // innermost native event loop is ProcessNextNativeEvent
133 eEventloopOther // innermost native event loop is a native library/plugin etc
134 };
135 EventloopNestingState mEventloopNestingState;
136 nsTArray<SyncSection> mSyncSections;
137 bool mRunning;
138 bool mExiting;
139 /**
140 * mBlockNativeEvent blocks the appshell from processing native events.
141 * It is set to true while a nested native event loop (eEventloopOther)
142 * is processing gecko events in NativeEventCallback(), thus queuing up
143 * native events until we return to that loop (bug 420148).
144 * We force mBlockNativeEvent to false in case handling one of the gecko
145 * events spins up a nested XPCOM event loop (eg. modal window) which would
146 * otherwise lead to a "deadlock" where native events aren't processed at all.
147 */
148 bool mBlockNativeEvent;
149 /**
150 * Tracks whether we have processed any gecko events in NativeEventCallback so
151 * that we can avoid erroneously entering a blocking loop waiting for gecko
152 * events to show up during OnProcessNextEvent. This is required because on
153 * OS X ProcessGeckoEvents may be invoked inside the context of
154 * ProcessNextNativeEvent and may result in NativeEventCallback being invoked
155 * and in turn invoking NS_ProcessPendingEvents. Because
156 * ProcessNextNativeEvent may be invoked prior to the NS_HasPendingEvents
157 * waiting loop, this is the only way to make the loop aware that events may
158 * have been processed.
159 *
160 * This variable is set to false in OnProcessNextEvent prior to the first
161 * call to DoProcessNextNativeEvent. It is set to true by
162 * NativeEventCallback after calling NS_ProcessPendingEvents.
163 */
164 bool mProcessedGeckoEvents;
165 };
167 #endif // nsBaseAppShell_h__