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