michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ 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 nsThread_h__ michael@0: #define nsThread_h__ michael@0: michael@0: #include "mozilla/Mutex.h" michael@0: #include "nsIThreadInternal.h" michael@0: #include "nsISupportsPriority.h" michael@0: #include "nsEventQueue.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsString.h" michael@0: #include "nsTObserverArray.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsAutoPtr.h" michael@0: michael@0: // A native thread michael@0: class nsThread : public nsIThreadInternal, michael@0: public nsISupportsPriority 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_NSITHREADINTERNAL michael@0: NS_DECL_NSISUPPORTSPRIORITY michael@0: michael@0: enum MainThreadFlag { michael@0: MAIN_THREAD, michael@0: NOT_MAIN_THREAD michael@0: }; michael@0: michael@0: nsThread(MainThreadFlag aMainThread, uint32_t aStackSize); michael@0: michael@0: // Initialize this as a wrapper for a new PRThread. michael@0: nsresult Init(); michael@0: michael@0: // Initialize this as a wrapper for the current PRThread. michael@0: nsresult InitCurrentThread(); michael@0: michael@0: // The PRThread corresponding to this thread. michael@0: PRThread *GetPRThread() { return mThread; } michael@0: michael@0: // If this flag is true, then the nsThread was created using michael@0: // nsIThreadManager::NewThread. michael@0: bool ShutdownRequired() { return mShutdownRequired; } michael@0: michael@0: // Clear the observer list. michael@0: void ClearObservers() { mEventObservers.Clear(); } michael@0: michael@0: static nsresult michael@0: SetMainThreadObserver(nsIThreadObserver* aObserver); michael@0: michael@0: protected: michael@0: static nsIThreadObserver* sMainThreadObserver; michael@0: michael@0: class nsChainedEventQueue; michael@0: michael@0: class nsNestedEventTarget; michael@0: friend class nsNestedEventTarget; michael@0: michael@0: friend class nsThreadShutdownEvent; michael@0: michael@0: virtual ~nsThread(); michael@0: michael@0: bool ShuttingDown() { return mShutdownContext != nullptr; } michael@0: michael@0: static void ThreadFunc(void *arg); michael@0: michael@0: // Helper michael@0: already_AddRefed GetObserver() { michael@0: nsIThreadObserver *obs; michael@0: nsThread::GetObserver(&obs); michael@0: return already_AddRefed(obs); michael@0: } michael@0: michael@0: // Wrappers for event queue methods: michael@0: bool GetEvent(bool mayWait, nsIRunnable **event) { michael@0: return mEvents->GetEvent(mayWait, event); michael@0: } michael@0: nsresult PutEvent(nsIRunnable *event, nsNestedEventTarget *target); michael@0: michael@0: nsresult DispatchInternal(nsIRunnable *event, uint32_t flags, michael@0: nsNestedEventTarget *target); michael@0: michael@0: // Wrapper for nsEventQueue that supports chaining. michael@0: class nsChainedEventQueue { michael@0: public: michael@0: nsChainedEventQueue() michael@0: : mNext(nullptr) { michael@0: } michael@0: michael@0: bool GetEvent(bool mayWait, nsIRunnable **event) { michael@0: return mQueue.GetEvent(mayWait, event); michael@0: } michael@0: michael@0: bool PutEvent(nsIRunnable *event) { michael@0: return mQueue.PutEvent(event); michael@0: } michael@0: michael@0: bool HasPendingEvent() { michael@0: return mQueue.HasPendingEvent(); michael@0: } michael@0: michael@0: nsChainedEventQueue *mNext; michael@0: nsRefPtr mEventTarget; michael@0: michael@0: private: michael@0: nsEventQueue mQueue; michael@0: }; michael@0: michael@0: class nsNestedEventTarget MOZ_FINAL : public nsIEventTarget { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIEVENTTARGET michael@0: michael@0: nsNestedEventTarget(nsThread *thread, nsChainedEventQueue *queue) michael@0: : mThread(thread), mQueue(queue) { michael@0: } michael@0: michael@0: nsRefPtr mThread; michael@0: michael@0: // This is protected by mThread->mLock. michael@0: nsChainedEventQueue* mQueue; michael@0: michael@0: private: michael@0: ~nsNestedEventTarget() {} michael@0: }; michael@0: michael@0: // This lock protects access to mObserver, mEvents and mEventsAreDoomed. michael@0: // All of those fields are only modified on the thread itself (never from michael@0: // another thread). This means that we can avoid holding the lock while michael@0: // using mObserver and mEvents on the thread itself. When calling PutEvent michael@0: // on mEvents, we have to hold the lock to synchronize with PopEventQueue. michael@0: mozilla::Mutex mLock; michael@0: michael@0: nsCOMPtr mObserver; michael@0: michael@0: // Only accessed on the target thread. michael@0: nsAutoTObserverArray, 2> mEventObservers; michael@0: michael@0: nsChainedEventQueue *mEvents; // never null michael@0: nsChainedEventQueue mEventsRoot; michael@0: michael@0: int32_t mPriority; michael@0: PRThread *mThread; michael@0: uint32_t mRunningEvent; // counter michael@0: uint32_t mStackSize; michael@0: michael@0: struct nsThreadShutdownContext *mShutdownContext; michael@0: michael@0: bool mShutdownRequired; michael@0: // Set to true when events posted to this thread will never run. michael@0: bool mEventsAreDoomed; michael@0: MainThreadFlag mIsMainThread; michael@0: }; michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class nsThreadSyncDispatch : public nsRunnable { michael@0: public: michael@0: nsThreadSyncDispatch(nsIThread *origin, nsIRunnable *task) michael@0: : mOrigin(origin), mSyncTask(task), mResult(NS_ERROR_NOT_INITIALIZED) { michael@0: } michael@0: michael@0: bool IsPending() { michael@0: return mSyncTask != nullptr; michael@0: } michael@0: michael@0: nsresult Result() { michael@0: return mResult; michael@0: } michael@0: michael@0: private: michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: nsCOMPtr mOrigin; michael@0: nsCOMPtr mSyncTask; michael@0: nsresult mResult; michael@0: }; michael@0: michael@0: #if defined(XP_UNIX) && !defined(ANDROID) && !defined(DEBUG) && HAVE_UALARM \ michael@0: && defined(_GNU_SOURCE) michael@0: # define MOZ_CANARY michael@0: michael@0: extern int sCanaryOutputFD; michael@0: #endif michael@0: michael@0: #endif // nsThread_h__