|
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/. */ |
|
5 |
|
6 #ifndef nsBaseAppShell_h__ |
|
7 #define nsBaseAppShell_h__ |
|
8 |
|
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" |
|
17 |
|
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 |
|
30 |
|
31 nsBaseAppShell(); |
|
32 |
|
33 protected: |
|
34 virtual ~nsBaseAppShell(); |
|
35 |
|
36 /** |
|
37 * This method is called by subclasses when the app shell singleton is |
|
38 * instantiated. |
|
39 */ |
|
40 nsresult Init(); |
|
41 |
|
42 /** |
|
43 * Called by subclasses from a native event. See ScheduleNativeEventCallback. |
|
44 */ |
|
45 void NativeEventCallback(); |
|
46 |
|
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(); |
|
53 |
|
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; |
|
59 |
|
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; |
|
73 |
|
74 int32_t mSuspendNativeCount; |
|
75 uint32_t mEventloopNestingLevel; |
|
76 |
|
77 private: |
|
78 bool DoProcessNextNativeEvent(bool mayWait, uint32_t recursionDepth); |
|
79 |
|
80 bool DispatchDummyEvent(nsIThread* target); |
|
81 |
|
82 void IncrementEventloopNestingLevel(); |
|
83 void DecrementEventloopNestingLevel(); |
|
84 |
|
85 /** |
|
86 * Runs all synchronous sections which are queued up in mSyncSections. |
|
87 */ |
|
88 void RunSyncSectionsInternal(bool stable, uint32_t threadRecursionLevel); |
|
89 |
|
90 void RunSyncSections(bool stable, uint32_t threadRecursionLevel) |
|
91 { |
|
92 if (!mSyncSections.IsEmpty()) { |
|
93 RunSyncSectionsInternal(stable, threadRecursionLevel); |
|
94 } |
|
95 } |
|
96 |
|
97 void ScheduleSyncSection(nsIRunnable* runnable, bool stable); |
|
98 |
|
99 struct SyncSection { |
|
100 SyncSection() |
|
101 : mStable(false), mEventloopNestingLevel(0), mThreadRecursionLevel(0) |
|
102 { } |
|
103 |
|
104 void Forget(SyncSection* other) { |
|
105 other->mStable = mStable; |
|
106 other->mEventloopNestingLevel = mEventloopNestingLevel; |
|
107 other->mThreadRecursionLevel = mThreadRecursionLevel; |
|
108 other->mRunnable = mRunnable.forget(); |
|
109 } |
|
110 |
|
111 bool mStable; |
|
112 uint32_t mEventloopNestingLevel; |
|
113 uint32_t mThreadRecursionLevel; |
|
114 nsCOMPtr<nsIRunnable> mRunnable; |
|
115 }; |
|
116 |
|
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 }; |
|
166 |
|
167 #endif // nsBaseAppShell_h__ |