Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef nsThread_h__
8 #define nsThread_h__
10 #include "mozilla/Mutex.h"
11 #include "nsIThreadInternal.h"
12 #include "nsISupportsPriority.h"
13 #include "nsEventQueue.h"
14 #include "nsThreadUtils.h"
15 #include "nsString.h"
16 #include "nsTObserverArray.h"
17 #include "mozilla/Attributes.h"
18 #include "nsAutoPtr.h"
20 // A native thread
21 class nsThread : public nsIThreadInternal,
22 public nsISupportsPriority
23 {
24 public:
25 NS_DECL_THREADSAFE_ISUPPORTS
26 NS_DECL_NSIEVENTTARGET
27 NS_DECL_NSITHREAD
28 NS_DECL_NSITHREADINTERNAL
29 NS_DECL_NSISUPPORTSPRIORITY
31 enum MainThreadFlag {
32 MAIN_THREAD,
33 NOT_MAIN_THREAD
34 };
36 nsThread(MainThreadFlag aMainThread, uint32_t aStackSize);
38 // Initialize this as a wrapper for a new PRThread.
39 nsresult Init();
41 // Initialize this as a wrapper for the current PRThread.
42 nsresult InitCurrentThread();
44 // The PRThread corresponding to this thread.
45 PRThread *GetPRThread() { return mThread; }
47 // If this flag is true, then the nsThread was created using
48 // nsIThreadManager::NewThread.
49 bool ShutdownRequired() { return mShutdownRequired; }
51 // Clear the observer list.
52 void ClearObservers() { mEventObservers.Clear(); }
54 static nsresult
55 SetMainThreadObserver(nsIThreadObserver* aObserver);
57 protected:
58 static nsIThreadObserver* sMainThreadObserver;
60 class nsChainedEventQueue;
62 class nsNestedEventTarget;
63 friend class nsNestedEventTarget;
65 friend class nsThreadShutdownEvent;
67 virtual ~nsThread();
69 bool ShuttingDown() { return mShutdownContext != nullptr; }
71 static void ThreadFunc(void *arg);
73 // Helper
74 already_AddRefed<nsIThreadObserver> GetObserver() {
75 nsIThreadObserver *obs;
76 nsThread::GetObserver(&obs);
77 return already_AddRefed<nsIThreadObserver>(obs);
78 }
80 // Wrappers for event queue methods:
81 bool GetEvent(bool mayWait, nsIRunnable **event) {
82 return mEvents->GetEvent(mayWait, event);
83 }
84 nsresult PutEvent(nsIRunnable *event, nsNestedEventTarget *target);
86 nsresult DispatchInternal(nsIRunnable *event, uint32_t flags,
87 nsNestedEventTarget *target);
89 // Wrapper for nsEventQueue that supports chaining.
90 class nsChainedEventQueue {
91 public:
92 nsChainedEventQueue()
93 : mNext(nullptr) {
94 }
96 bool GetEvent(bool mayWait, nsIRunnable **event) {
97 return mQueue.GetEvent(mayWait, event);
98 }
100 bool PutEvent(nsIRunnable *event) {
101 return mQueue.PutEvent(event);
102 }
104 bool HasPendingEvent() {
105 return mQueue.HasPendingEvent();
106 }
108 nsChainedEventQueue *mNext;
109 nsRefPtr<nsNestedEventTarget> mEventTarget;
111 private:
112 nsEventQueue mQueue;
113 };
115 class nsNestedEventTarget MOZ_FINAL : public nsIEventTarget {
116 public:
117 NS_DECL_THREADSAFE_ISUPPORTS
118 NS_DECL_NSIEVENTTARGET
120 nsNestedEventTarget(nsThread *thread, nsChainedEventQueue *queue)
121 : mThread(thread), mQueue(queue) {
122 }
124 nsRefPtr<nsThread> mThread;
126 // This is protected by mThread->mLock.
127 nsChainedEventQueue* mQueue;
129 private:
130 ~nsNestedEventTarget() {}
131 };
133 // This lock protects access to mObserver, mEvents and mEventsAreDoomed.
134 // All of those fields are only modified on the thread itself (never from
135 // another thread). This means that we can avoid holding the lock while
136 // using mObserver and mEvents on the thread itself. When calling PutEvent
137 // on mEvents, we have to hold the lock to synchronize with PopEventQueue.
138 mozilla::Mutex mLock;
140 nsCOMPtr<nsIThreadObserver> mObserver;
142 // Only accessed on the target thread.
143 nsAutoTObserverArray<nsCOMPtr<nsIThreadObserver>, 2> mEventObservers;
145 nsChainedEventQueue *mEvents; // never null
146 nsChainedEventQueue mEventsRoot;
148 int32_t mPriority;
149 PRThread *mThread;
150 uint32_t mRunningEvent; // counter
151 uint32_t mStackSize;
153 struct nsThreadShutdownContext *mShutdownContext;
155 bool mShutdownRequired;
156 // Set to true when events posted to this thread will never run.
157 bool mEventsAreDoomed;
158 MainThreadFlag mIsMainThread;
159 };
161 //-----------------------------------------------------------------------------
163 class nsThreadSyncDispatch : public nsRunnable {
164 public:
165 nsThreadSyncDispatch(nsIThread *origin, nsIRunnable *task)
166 : mOrigin(origin), mSyncTask(task), mResult(NS_ERROR_NOT_INITIALIZED) {
167 }
169 bool IsPending() {
170 return mSyncTask != nullptr;
171 }
173 nsresult Result() {
174 return mResult;
175 }
177 private:
178 NS_DECL_NSIRUNNABLE
180 nsCOMPtr<nsIThread> mOrigin;
181 nsCOMPtr<nsIRunnable> mSyncTask;
182 nsresult mResult;
183 };
185 #if defined(XP_UNIX) && !defined(ANDROID) && !defined(DEBUG) && HAVE_UALARM \
186 && defined(_GNU_SOURCE)
187 # define MOZ_CANARY
189 extern int sCanaryOutputFD;
190 #endif
192 #endif // nsThread_h__