CacheIOThread.h (5143B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifndef CacheIOThread__h__ 6 #define CacheIOThread__h__ 7 8 #include "nsIThreadInternal.h" 9 #include "nsISupportsImpl.h" 10 #include "prthread.h" 11 #include "nsTArray.h" 12 #include "mozilla/Monitor.h" 13 #include "mozilla/Atomics.h" 14 #include "mozilla/UniquePtr.h" 15 16 class nsIRunnable; 17 18 namespace mozilla { 19 namespace net { 20 21 namespace detail { 22 // A class keeping platform specific information needed to 23 // cancel any long blocking synchronous IO. Must be predeclared here 24 // since including windows.h breaks stuff with number of macro definition 25 // conflicts. 26 class NativeThreadHandle; 27 } // namespace detail 28 29 class CacheIOThread final : public nsIThreadObserver { 30 virtual ~CacheIOThread(); 31 32 public: 33 NS_DECL_THREADSAFE_ISUPPORTS 34 NS_DECL_NSITHREADOBSERVER 35 36 CacheIOThread(); 37 38 // We have LAST_LEVEL times queues, so keep the inline storage reasonable. 39 using EventQueue = AutoTArray<nsCOMPtr<nsIRunnable>, 32>; 40 41 enum ELevel : uint32_t { 42 OPEN_PRIORITY, 43 READ_PRIORITY, 44 MANAGEMENT, // Doesn't do any actual I/O 45 OPEN, 46 READ, 47 WRITE_PRIORITY, 48 WRITE, 49 INDEX, 50 EVICT, 51 LAST_LEVEL, 52 53 // This is actually executed as the first level, but we want this enum 54 // value merely as an indicator while other values are used as indexes 55 // to the queue array. Hence put at end and not as the first. 56 XPCOM_LEVEL 57 }; 58 59 nsresult Init(); 60 nsresult Dispatch(nsIRunnable* aRunnable, uint32_t aLevel); 61 nsresult Dispatch(already_AddRefed<nsIRunnable>, uint32_t aLevel); 62 // Makes sure that any previously posted event to OPEN or OPEN_PRIORITY 63 // levels (such as file opennings and dooms) are executed before aRunnable 64 // that is intended to evict stuff from the cache. 65 nsresult DispatchAfterPendingOpens(nsIRunnable* aRunnable); 66 bool IsCurrentThread(); 67 68 uint32_t QueueSize(bool highPriority); 69 70 uint32_t EventCounter() const { return mEventCounter; } 71 72 /** 73 * Callable only on this thread, checks if there is an event waiting in 74 * the event queue with a higher execution priority. If so, the result 75 * is true and the current event handler should break it's work and return 76 * from Run() method immediately. The event handler will be rerun again 77 * when all more priority events are processed. Events pending after this 78 * handler (i.e. the one that called YieldAndRerun()) will not execute sooner 79 * then this handler is executed w/o a call to YieldAndRerun(). 80 */ 81 static bool YieldAndRerun() { return sSelf ? sSelf->YieldInternal() : false; } 82 83 void Shutdown(); 84 // This method checks if there is a long blocking IO on the 85 // IO thread and tries to cancel it. It waits maximum of 86 // two seconds. 87 void CancelBlockingIO(); 88 already_AddRefed<nsIEventTarget> Target(); 89 90 // A stack class used to annotate running interruptable I/O event 91 class Cancelable { 92 bool mCancelable; 93 94 public: 95 explicit Cancelable(bool aCancelable); 96 ~Cancelable(); 97 }; 98 99 // Memory reporting 100 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 101 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 102 103 private: 104 static void ThreadFunc(void* aClosure); 105 void ThreadFunc(); 106 void LoopOneLevel(uint32_t aLevel) MOZ_REQUIRES(mMonitor); 107 bool EventsPending(uint32_t aLastLevel = LAST_LEVEL); 108 nsresult DispatchInternal(already_AddRefed<nsIRunnable> aRunnable, 109 uint32_t aLevel); 110 bool YieldInternal(); 111 112 static CacheIOThread* sSelf; 113 114 mozilla::Monitor mMonitor{"CacheIOThread"}; 115 PRThread* mThread{nullptr}; 116 // Only set in Init(), before the thread is started, which reads it but never 117 // writes 118 UniquePtr<detail::NativeThreadHandle> mNativeThreadHandle; 119 Atomic<nsIThread*> mXPCOMThread{nullptr}; 120 Atomic<uint32_t, Relaxed> mLowestLevelWaiting{LAST_LEVEL}; 121 uint32_t mCurrentlyExecutingLevel{0}; // only accessed on CacheIO Thread 122 123 // Keeps the length of the each event queue, since LoopOneLevel moves all 124 // events into a local array. 125 Atomic<int32_t> mQueueLength[LAST_LEVEL]; 126 127 EventQueue mEventQueue[LAST_LEVEL] MOZ_GUARDED_BY(mMonitor); 128 // Raised when nsIEventTarget.Dispatch() is called on this thread 129 Atomic<bool, Relaxed> mHasXPCOMEvents{false}; 130 // See YieldAndRerun() above 131 bool mRerunCurrentEvent{false}; // Only accessed on the cache thread 132 // Signal to process all pending events and then shutdown 133 // Synchronized by mMonitor 134 bool mShutdown MOZ_GUARDED_BY(mMonitor){false}; 135 // If > 0 there is currently an I/O operation on the thread that 136 // can be canceled when after shutdown, see the Shutdown() method 137 // for usage. Made a counter to allow nesting of the Cancelable class. 138 Atomic<uint32_t, Relaxed> mIOCancelableEvents{0}; 139 // Event counter that increases with every event processed. 140 Atomic<uint32_t, Relaxed> mEventCounter{0}; 141 #ifdef DEBUG 142 bool mInsideLoop MOZ_GUARDED_BY(mMonitor){true}; 143 #endif 144 }; 145 146 } // namespace net 147 } // namespace mozilla 148 149 #endif