michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_lazyidlethread_h__ michael@0: #define mozilla_lazyidlethread_h__ michael@0: michael@0: #ifndef MOZILLA_INTERNAL_API michael@0: #error "This header is only usable from within libxul (MOZILLA_INTERNAL_API)." michael@0: #endif michael@0: michael@0: #include "nsIObserver.h" michael@0: #include "nsIThreadInternal.h" michael@0: #include "nsITimer.h" michael@0: michael@0: #include "mozilla/Mutex.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsTArray.h" michael@0: #include "nsString.h" michael@0: #include "mozilla/Attributes.h" michael@0: michael@0: #define IDLE_THREAD_TOPIC "thread-shutting-down" michael@0: michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * This class provides a basic event target that creates its thread lazily and michael@0: * destroys its thread after a period of inactivity. It may be created on any michael@0: * thread but it may only be used from the thread on which it is created. If it michael@0: * is created on the main thread then it will automatically join its thread on michael@0: * XPCOM shutdown using the Observer Service. michael@0: */ michael@0: class LazyIdleThread MOZ_FINAL : public nsIThread, michael@0: public nsITimerCallback, michael@0: public nsIThreadObserver, michael@0: public nsIObserver michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIEVENTTARGET michael@0: NS_DECL_NSITHREAD michael@0: NS_DECL_NSITIMERCALLBACK michael@0: NS_DECL_NSITHREADOBSERVER michael@0: NS_DECL_NSIOBSERVER michael@0: michael@0: enum ShutdownMethod { michael@0: AutomaticShutdown = 0, michael@0: ManualShutdown michael@0: }; michael@0: michael@0: /** michael@0: * Create a new LazyIdleThread that will destroy its thread after the given michael@0: * number of milliseconds. michael@0: */ michael@0: LazyIdleThread(uint32_t aIdleTimeoutMS, michael@0: const nsCSubstring& aName, michael@0: ShutdownMethod aShutdownMethod = AutomaticShutdown, michael@0: nsIObserver* aIdleObserver = nullptr); michael@0: michael@0: /** michael@0: * Add an observer that will be notified when the thread is idle and about to michael@0: * be shut down. The aSubject argument can be QueryInterface'd to an nsIThread michael@0: * that can be used to post cleanup events. The aTopic argument will be michael@0: * IDLE_THREAD_TOPIC, and aData will be null. The LazyIdleThread does not add michael@0: * a reference to the observer to avoid circular references as it is assumed michael@0: * to be the owner. It is the caller's responsibility to clear this observer michael@0: * if the pointer becomes invalid. michael@0: */ michael@0: void SetWeakIdleObserver(nsIObserver* aObserver); michael@0: michael@0: /** michael@0: * Disable the idle timeout for this thread. No effect if the timeout is michael@0: * already disabled. michael@0: */ michael@0: void DisableIdleTimeout(); michael@0: michael@0: /** michael@0: * Enable the idle timeout. No effect if the timeout is already enabled. michael@0: */ michael@0: void EnableIdleTimeout(); michael@0: michael@0: private: michael@0: /** michael@0: * Calls Shutdown(). michael@0: */ michael@0: ~LazyIdleThread(); michael@0: michael@0: /** michael@0: * Called just before dispatching to mThread. michael@0: */ michael@0: void PreDispatch(); michael@0: michael@0: /** michael@0: * Makes sure a valid thread lives in mThread. michael@0: */ michael@0: nsresult EnsureThread(); michael@0: michael@0: /** michael@0: * Called on mThread to set up the thread observer. michael@0: */ michael@0: void InitThread(); michael@0: michael@0: /** michael@0: * Called on mThread to clean up the thread observer. michael@0: */ michael@0: void CleanupThread(); michael@0: michael@0: /** michael@0: * Called on the main thread when mThread believes itself to be idle. Sets up michael@0: * the idle timer. michael@0: */ michael@0: void ScheduleTimer(); michael@0: michael@0: /** michael@0: * Called when we are shutting down mThread. michael@0: */ michael@0: nsresult ShutdownThread(); michael@0: michael@0: /** michael@0: * Deletes this object. Used to delay calling mThread->Shutdown() during the michael@0: * final release (during a GC, for instance). michael@0: */ michael@0: void SelfDestruct(); michael@0: michael@0: /** michael@0: * Returns true if events should be queued rather than immediately dispatched michael@0: * to mThread. Currently only happens when the thread is shutting down. michael@0: */ michael@0: bool UseRunnableQueue() { michael@0: return !!mQueuedRunnables; michael@0: } michael@0: michael@0: /** michael@0: * Protects data that is accessed on both threads. michael@0: */ michael@0: mozilla::Mutex mMutex; michael@0: michael@0: /** michael@0: * Touched on both threads but set before mThread is created. Used to direct michael@0: * timer events to the owning thread. michael@0: */ michael@0: nsCOMPtr mOwningThread; michael@0: michael@0: /** michael@0: * Only accessed on the owning thread. Set by EnsureThread(). michael@0: */ michael@0: nsCOMPtr mThread; michael@0: michael@0: /** michael@0: * Protected by mMutex. Created when mThread has no pending events and fired michael@0: * at mOwningThread. Any thread that dispatches to mThread will take ownership michael@0: * of the timer and fire a separate cancel event to the owning thread. michael@0: */ michael@0: nsCOMPtr mIdleTimer; michael@0: michael@0: /** michael@0: * Idle observer. Called when the thread is about to be shut down. Released michael@0: * only when Shutdown() is called. michael@0: */ michael@0: nsIObserver* mIdleObserver; michael@0: michael@0: /** michael@0: * Temporary storage for events that happen to be dispatched while we're in michael@0: * the process of shutting down our real thread. michael@0: */ michael@0: nsTArray >* mQueuedRunnables; michael@0: michael@0: /** michael@0: * The number of milliseconds a thread should be idle before dying. michael@0: */ michael@0: const uint32_t mIdleTimeoutMS; michael@0: michael@0: /** michael@0: * The number of events that are pending on mThread. A nonzero value means michael@0: * that the thread cannot be cleaned up. michael@0: */ michael@0: uint32_t mPendingEventCount; michael@0: michael@0: /** michael@0: * The number of times that mThread has dispatched an idle notification. Any michael@0: * timer that fires while this count is nonzero can safely be ignored as michael@0: * another timer will be on the way. michael@0: */ michael@0: uint32_t mIdleNotificationCount; michael@0: michael@0: /** michael@0: * Whether or not the thread should automatically shutdown. If the owner michael@0: * specified ManualShutdown at construction time then the owner should take michael@0: * care to call Shutdown() manually when appropriate. michael@0: */ michael@0: ShutdownMethod mShutdownMethod; michael@0: michael@0: /** michael@0: * Only accessed on the owning thread. Set to true when Shutdown() has been michael@0: * called and prevents EnsureThread() from recreating mThread. michael@0: */ michael@0: bool mShutdown; michael@0: michael@0: /** michael@0: * Set from CleanupThread and lasting until the thread has shut down. Prevents michael@0: * further idle notifications during the shutdown process. michael@0: */ michael@0: bool mThreadIsShuttingDown; michael@0: michael@0: /** michael@0: * Whether or not the idle timeout is enabled. michael@0: */ michael@0: bool mIdleTimeoutEnabled; michael@0: michael@0: /** michael@0: * Name of the thread, set on the actual thread after it gets created. michael@0: */ michael@0: nsCString mName; michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif // mozilla_lazyidlethread_h__