diff options
Diffstat (limited to 'netwerk/cache2/CacheIOThread.h')
-rw-r--r-- | netwerk/cache2/CacheIOThread.h | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/netwerk/cache2/CacheIOThread.h b/netwerk/cache2/CacheIOThread.h new file mode 100644 index 0000000000..4cb8a964b8 --- /dev/null +++ b/netwerk/cache2/CacheIOThread.h @@ -0,0 +1,149 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CacheIOThread__h__ +#define CacheIOThread__h__ + +#include "nsIThreadInternal.h" +#include "nsISupportsImpl.h" +#include "prthread.h" +#include "nsTArray.h" +#include "mozilla/Monitor.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/Atomics.h" +#include "mozilla/UniquePtr.h" + +class nsIRunnable; + +namespace mozilla { +namespace net { + +namespace detail { +// A class keeping platform specific information needed to +// cancel any long blocking synchronous IO. Must be predeclared here +// since including windows.h breaks stuff with number of macro definition +// conflicts. +class NativeThreadHandle; +} // namespace detail + +class CacheIOThread final : public nsIThreadObserver { + virtual ~CacheIOThread(); + + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSITHREADOBSERVER + + CacheIOThread(); + + using EventQueue = nsTArray<nsCOMPtr<nsIRunnable>>; + + enum ELevel : uint32_t { + OPEN_PRIORITY, + READ_PRIORITY, + MANAGEMENT, // Doesn't do any actual I/O + OPEN, + READ, + WRITE_PRIORITY, + WRITE, + INDEX, + EVICT, + LAST_LEVEL, + + // This is actually executed as the first level, but we want this enum + // value merely as an indicator while other values are used as indexes + // to the queue array. Hence put at end and not as the first. + XPCOM_LEVEL + }; + + nsresult Init(); + nsresult Dispatch(nsIRunnable* aRunnable, uint32_t aLevel); + nsresult Dispatch(already_AddRefed<nsIRunnable>, uint32_t aLevel); + // Makes sure that any previously posted event to OPEN or OPEN_PRIORITY + // levels (such as file opennings and dooms) are executed before aRunnable + // that is intended to evict stuff from the cache. + nsresult DispatchAfterPendingOpens(nsIRunnable* aRunnable); + bool IsCurrentThread(); + + uint32_t QueueSize(bool highPriority); + + uint32_t EventCounter() const { return mEventCounter; } + + /** + * Callable only on this thread, checks if there is an event waiting in + * the event queue with a higher execution priority. If so, the result + * is true and the current event handler should break it's work and return + * from Run() method immediately. The event handler will be rerun again + * when all more priority events are processed. Events pending after this + * handler (i.e. the one that called YieldAndRerun()) will not execute sooner + * then this handler is executed w/o a call to YieldAndRerun(). + */ + static bool YieldAndRerun() { return sSelf ? sSelf->YieldInternal() : false; } + + void Shutdown(); + // This method checks if there is a long blocking IO on the + // IO thread and tries to cancel it. It waits maximum of + // two seconds. + void CancelBlockingIO(); + already_AddRefed<nsIEventTarget> Target(); + + // A stack class used to annotate running interruptable I/O event + class Cancelable { + bool mCancelable; + + public: + explicit Cancelable(bool aCancelable); + ~Cancelable(); + }; + + // Memory reporting + size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + private: + static void ThreadFunc(void* aClosure); + void ThreadFunc(); + void LoopOneLevel(uint32_t aLevel) MOZ_REQUIRES(mMonitor); + bool EventsPending(uint32_t aLastLevel = LAST_LEVEL); + nsresult DispatchInternal(already_AddRefed<nsIRunnable> aRunnable, + uint32_t aLevel); + bool YieldInternal(); + + static CacheIOThread* sSelf; + + mozilla::Monitor mMonitor{"CacheIOThread"}; + PRThread* mThread{nullptr}; + // Only set in Init(), before the thread is started, which reads it but never + // writes + UniquePtr<detail::NativeThreadHandle> mNativeThreadHandle; + Atomic<nsIThread*> mXPCOMThread{nullptr}; + Atomic<uint32_t, Relaxed> mLowestLevelWaiting{LAST_LEVEL}; + uint32_t mCurrentlyExecutingLevel{0}; // only accessed on CacheIO Thread + + // Keeps the length of the each event queue, since LoopOneLevel moves all + // events into a local array. + Atomic<int32_t> mQueueLength[LAST_LEVEL]; + + EventQueue mEventQueue[LAST_LEVEL] MOZ_GUARDED_BY(mMonitor); + // Raised when nsIEventTarget.Dispatch() is called on this thread + Atomic<bool, Relaxed> mHasXPCOMEvents{false}; + // See YieldAndRerun() above + bool mRerunCurrentEvent{false}; // Only accessed on the cache thread + // Signal to process all pending events and then shutdown + // Synchronized by mMonitor + bool mShutdown MOZ_GUARDED_BY(mMonitor){false}; + // If > 0 there is currently an I/O operation on the thread that + // can be canceled when after shutdown, see the Shutdown() method + // for usage. Made a counter to allow nesting of the Cancelable class. + Atomic<uint32_t, Relaxed> mIOCancelableEvents{0}; + // Event counter that increases with every event processed. + Atomic<uint32_t, Relaxed> mEventCounter{0}; +#ifdef DEBUG + bool mInsideLoop MOZ_GUARDED_BY(mMonitor){true}; +#endif +}; + +} // namespace net +} // namespace mozilla + +#endif |