|
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/. */ |
|
6 |
|
7 #ifndef nsThread_h__ |
|
8 #define nsThread_h__ |
|
9 |
|
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" |
|
19 |
|
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 |
|
30 |
|
31 enum MainThreadFlag { |
|
32 MAIN_THREAD, |
|
33 NOT_MAIN_THREAD |
|
34 }; |
|
35 |
|
36 nsThread(MainThreadFlag aMainThread, uint32_t aStackSize); |
|
37 |
|
38 // Initialize this as a wrapper for a new PRThread. |
|
39 nsresult Init(); |
|
40 |
|
41 // Initialize this as a wrapper for the current PRThread. |
|
42 nsresult InitCurrentThread(); |
|
43 |
|
44 // The PRThread corresponding to this thread. |
|
45 PRThread *GetPRThread() { return mThread; } |
|
46 |
|
47 // If this flag is true, then the nsThread was created using |
|
48 // nsIThreadManager::NewThread. |
|
49 bool ShutdownRequired() { return mShutdownRequired; } |
|
50 |
|
51 // Clear the observer list. |
|
52 void ClearObservers() { mEventObservers.Clear(); } |
|
53 |
|
54 static nsresult |
|
55 SetMainThreadObserver(nsIThreadObserver* aObserver); |
|
56 |
|
57 protected: |
|
58 static nsIThreadObserver* sMainThreadObserver; |
|
59 |
|
60 class nsChainedEventQueue; |
|
61 |
|
62 class nsNestedEventTarget; |
|
63 friend class nsNestedEventTarget; |
|
64 |
|
65 friend class nsThreadShutdownEvent; |
|
66 |
|
67 virtual ~nsThread(); |
|
68 |
|
69 bool ShuttingDown() { return mShutdownContext != nullptr; } |
|
70 |
|
71 static void ThreadFunc(void *arg); |
|
72 |
|
73 // Helper |
|
74 already_AddRefed<nsIThreadObserver> GetObserver() { |
|
75 nsIThreadObserver *obs; |
|
76 nsThread::GetObserver(&obs); |
|
77 return already_AddRefed<nsIThreadObserver>(obs); |
|
78 } |
|
79 |
|
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); |
|
85 |
|
86 nsresult DispatchInternal(nsIRunnable *event, uint32_t flags, |
|
87 nsNestedEventTarget *target); |
|
88 |
|
89 // Wrapper for nsEventQueue that supports chaining. |
|
90 class nsChainedEventQueue { |
|
91 public: |
|
92 nsChainedEventQueue() |
|
93 : mNext(nullptr) { |
|
94 } |
|
95 |
|
96 bool GetEvent(bool mayWait, nsIRunnable **event) { |
|
97 return mQueue.GetEvent(mayWait, event); |
|
98 } |
|
99 |
|
100 bool PutEvent(nsIRunnable *event) { |
|
101 return mQueue.PutEvent(event); |
|
102 } |
|
103 |
|
104 bool HasPendingEvent() { |
|
105 return mQueue.HasPendingEvent(); |
|
106 } |
|
107 |
|
108 nsChainedEventQueue *mNext; |
|
109 nsRefPtr<nsNestedEventTarget> mEventTarget; |
|
110 |
|
111 private: |
|
112 nsEventQueue mQueue; |
|
113 }; |
|
114 |
|
115 class nsNestedEventTarget MOZ_FINAL : public nsIEventTarget { |
|
116 public: |
|
117 NS_DECL_THREADSAFE_ISUPPORTS |
|
118 NS_DECL_NSIEVENTTARGET |
|
119 |
|
120 nsNestedEventTarget(nsThread *thread, nsChainedEventQueue *queue) |
|
121 : mThread(thread), mQueue(queue) { |
|
122 } |
|
123 |
|
124 nsRefPtr<nsThread> mThread; |
|
125 |
|
126 // This is protected by mThread->mLock. |
|
127 nsChainedEventQueue* mQueue; |
|
128 |
|
129 private: |
|
130 ~nsNestedEventTarget() {} |
|
131 }; |
|
132 |
|
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; |
|
139 |
|
140 nsCOMPtr<nsIThreadObserver> mObserver; |
|
141 |
|
142 // Only accessed on the target thread. |
|
143 nsAutoTObserverArray<nsCOMPtr<nsIThreadObserver>, 2> mEventObservers; |
|
144 |
|
145 nsChainedEventQueue *mEvents; // never null |
|
146 nsChainedEventQueue mEventsRoot; |
|
147 |
|
148 int32_t mPriority; |
|
149 PRThread *mThread; |
|
150 uint32_t mRunningEvent; // counter |
|
151 uint32_t mStackSize; |
|
152 |
|
153 struct nsThreadShutdownContext *mShutdownContext; |
|
154 |
|
155 bool mShutdownRequired; |
|
156 // Set to true when events posted to this thread will never run. |
|
157 bool mEventsAreDoomed; |
|
158 MainThreadFlag mIsMainThread; |
|
159 }; |
|
160 |
|
161 //----------------------------------------------------------------------------- |
|
162 |
|
163 class nsThreadSyncDispatch : public nsRunnable { |
|
164 public: |
|
165 nsThreadSyncDispatch(nsIThread *origin, nsIRunnable *task) |
|
166 : mOrigin(origin), mSyncTask(task), mResult(NS_ERROR_NOT_INITIALIZED) { |
|
167 } |
|
168 |
|
169 bool IsPending() { |
|
170 return mSyncTask != nullptr; |
|
171 } |
|
172 |
|
173 nsresult Result() { |
|
174 return mResult; |
|
175 } |
|
176 |
|
177 private: |
|
178 NS_DECL_NSIRUNNABLE |
|
179 |
|
180 nsCOMPtr<nsIThread> mOrigin; |
|
181 nsCOMPtr<nsIRunnable> mSyncTask; |
|
182 nsresult mResult; |
|
183 }; |
|
184 |
|
185 #if defined(XP_UNIX) && !defined(ANDROID) && !defined(DEBUG) && HAVE_UALARM \ |
|
186 && defined(_GNU_SOURCE) |
|
187 # define MOZ_CANARY |
|
188 |
|
189 extern int sCanaryOutputFD; |
|
190 #endif |
|
191 |
|
192 #endif // nsThread_h__ |