/* 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 "nsAutoPtr.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 watch and // cancel any long blocking synchronous IO. Must be predeclared here // since including windows.h breaks stuff with number of macro definition // conflicts. class BlockingIOWatcher; } class CacheIOThread : public nsIThreadObserver { virtual ~CacheIOThread(); public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSITHREADOBSERVER CacheIOThread(); typedef nsTArray<nsCOMPtr<nsIRunnable>> EventQueue; 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); /** * 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); bool EventsPending(uint32_t aLastLevel = LAST_LEVEL); nsresult DispatchInternal(already_AddRefed<nsIRunnable> aRunnable, uint32_t aLevel); bool YieldInternal(); static CacheIOThread* sSelf; mozilla::Monitor mMonitor; PRThread* mThread; UniquePtr<detail::BlockingIOWatcher> mBlockingIOWatcher; Atomic<nsIThread *> mXPCOMThread; Atomic<uint32_t, Relaxed> mLowestLevelWaiting; uint32_t mCurrentlyExecutingLevel; // 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]; // Raised when nsIEventTarget.Dispatch() is called on this thread Atomic<bool, Relaxed> mHasXPCOMEvents; // See YieldAndRerun() above bool mRerunCurrentEvent; // Signal to process all pending events and then shutdown // Synchronized by mMonitor bool mShutdown; // 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; #ifdef DEBUG bool mInsideLoop; #endif }; } // namespace net } // namespace mozilla #endif