1 | /* |
2 | * Copyright (C) 2007-2018 Apple Inc. All rights reserved. |
3 | * Copyright (C) 2007 Justin Haygood <[email protected]> |
4 | * Copyright (C) 2017 Yusuke Suzuki <[email protected]> |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
16 | * its contributors may be used to endorse or promote products derived |
17 | * from this software without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
20 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
22 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
23 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
26 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | */ |
30 | |
31 | #pragma once |
32 | |
33 | #include <mutex> |
34 | #include <stdint.h> |
35 | #include <wtf/Atomics.h> |
36 | #include <wtf/Expected.h> |
37 | #include <wtf/FastTLS.h> |
38 | #include <wtf/Function.h> |
39 | #include <wtf/HashSet.h> |
40 | #include <wtf/PlatformRegisters.h> |
41 | #include <wtf/Ref.h> |
42 | #include <wtf/RefPtr.h> |
43 | #include <wtf/StackBounds.h> |
44 | #include <wtf/StackStats.h> |
45 | #include <wtf/ThreadSafeRefCounted.h> |
46 | #include <wtf/Vector.h> |
47 | #include <wtf/WordLock.h> |
48 | #include <wtf/text/AtomStringTable.h> |
49 | |
50 | #if USE(PTHREADS) && !OS(DARWIN) |
51 | #include <signal.h> |
52 | #endif |
53 | |
54 | namespace WTF { |
55 | |
56 | class AbstractLocker; |
57 | class ThreadMessageData; |
58 | |
59 | enum class ThreadGroupAddResult; |
60 | |
61 | class ThreadGroup; |
62 | class PrintStream; |
63 | |
64 | // This function can be called from any threads. |
65 | WTF_EXPORT_PRIVATE void initializeThreading(); |
66 | |
67 | #if USE(PTHREADS) |
68 | |
69 | // We use SIGUSR1 to suspend and resume machine threads in JavaScriptCore. |
70 | constexpr const int SigThreadSuspendResume = SIGUSR1; |
71 | |
72 | #endif |
73 | |
74 | enum class GCThreadType : uint8_t { |
75 | None = 0, |
76 | Main, |
77 | Helper, |
78 | }; |
79 | |
80 | class Thread : public ThreadSafeRefCounted<Thread> { |
81 | public: |
82 | friend class ThreadGroup; |
83 | friend WTF_EXPORT_PRIVATE void initializeThreading(); |
84 | |
85 | WTF_EXPORT_PRIVATE ~Thread(); |
86 | |
87 | // Returns nullptr if thread creation failed. |
88 | // The thread name must be a literal since on some platforms it's passed in to the thread. |
89 | WTF_EXPORT_PRIVATE static Ref<Thread> create(const char* threadName, Function<void()>&&); |
90 | |
91 | // Returns Thread object. |
92 | static Thread& current(); |
93 | |
94 | // Set of all WTF::Thread created threads. |
95 | WTF_EXPORT_PRIVATE static HashSet<Thread*>& allThreads(const LockHolder&); |
96 | WTF_EXPORT_PRIVATE static Lock& allThreadsMutex(); |
97 | |
98 | #if OS(WINDOWS) |
99 | // Returns ThreadIdentifier directly. It is useful if the user only cares about identity |
100 | // of threads. At that time, users should know that holding this ThreadIdentifier does not ensure |
101 | // that the thread information is alive. While Thread::current() is not safe if it is called |
102 | // from the destructor of the other TLS data, currentID() always returns meaningful thread ID. |
103 | WTF_EXPORT_PRIVATE static ThreadIdentifier currentID(); |
104 | |
105 | ThreadIdentifier id() const { return m_id; } |
106 | #endif |
107 | |
108 | WTF_EXPORT_PRIVATE void changePriority(int); |
109 | WTF_EXPORT_PRIVATE int waitForCompletion(); |
110 | WTF_EXPORT_PRIVATE void detach(); |
111 | |
112 | #if OS(DARWIN) |
113 | using PlatformSuspendError = kern_return_t; |
114 | #elif USE(PTHREADS) |
115 | using PlatformSuspendError = int; |
116 | #elif OS(WINDOWS) |
117 | using PlatformSuspendError = DWORD; |
118 | #endif |
119 | |
120 | WTF_EXPORT_PRIVATE Expected<void, PlatformSuspendError> suspend(); |
121 | WTF_EXPORT_PRIVATE void resume(); |
122 | WTF_EXPORT_PRIVATE size_t getRegisters(PlatformRegisters&); |
123 | |
124 | #if USE(PTHREADS) |
125 | WTF_EXPORT_PRIVATE bool signal(int signalNumber); |
126 | #endif |
127 | |
128 | // Mark the current thread as requiring UI responsiveness. |
129 | // relativePriority is a value in the range [-15, 0] where a lower value indicates a lower priority. |
130 | WTF_EXPORT_PRIVATE static void setCurrentThreadIsUserInteractive(int relativePriority = 0); |
131 | WTF_EXPORT_PRIVATE static void setCurrentThreadIsUserInitiated(int relativePriority = 0); |
132 | |
133 | #if HAVE(QOS_CLASSES) |
134 | WTF_EXPORT_PRIVATE static void setGlobalMaxQOSClass(qos_class_t); |
135 | WTF_EXPORT_PRIVATE static qos_class_t adjustedQOSClass(qos_class_t); |
136 | #endif |
137 | |
138 | // Called in the thread during initialization. |
139 | // Helpful for platforms where the thread name must be set from within the thread. |
140 | static void initializeCurrentThreadInternal(const char* threadName); |
141 | static void initializeCurrentThreadEvenIfNonWTFCreated(); |
142 | |
143 | WTF_EXPORT_PRIVATE static const unsigned lockSpinLimit; |
144 | WTF_EXPORT_PRIVATE static void yield(); |
145 | |
146 | WTF_EXPORT_PRIVATE static bool exchangeIsCompilationThread(bool newValue); |
147 | WTF_EXPORT_PRIVATE static void registerGCThread(GCThreadType); |
148 | WTF_EXPORT_PRIVATE static bool mayBeGCThread(); |
149 | |
150 | WTF_EXPORT_PRIVATE void dump(PrintStream& out) const; |
151 | |
152 | static void initializePlatformThreading(); |
153 | |
154 | const StackBounds& stack() const |
155 | { |
156 | return m_stack; |
157 | } |
158 | |
159 | AtomStringTable* atomStringTable() |
160 | { |
161 | return m_currentAtomStringTable; |
162 | } |
163 | |
164 | AtomStringTable* setCurrentAtomStringTable(AtomStringTable* atomStringTable) |
165 | { |
166 | AtomStringTable* oldAtomStringTable = m_currentAtomStringTable; |
167 | m_currentAtomStringTable = atomStringTable; |
168 | return oldAtomStringTable; |
169 | } |
170 | |
171 | #if ENABLE(STACK_STATS) |
172 | StackStats::PerThreadStats& stackStats() |
173 | { |
174 | return m_stackStats; |
175 | } |
176 | #endif |
177 | |
178 | void* savedStackPointerAtVMEntry() |
179 | { |
180 | return m_savedStackPointerAtVMEntry; |
181 | } |
182 | |
183 | void setSavedStackPointerAtVMEntry(void* stackPointerAtVMEntry) |
184 | { |
185 | m_savedStackPointerAtVMEntry = stackPointerAtVMEntry; |
186 | } |
187 | |
188 | void* savedLastStackTop() |
189 | { |
190 | return m_savedLastStackTop; |
191 | } |
192 | |
193 | void setSavedLastStackTop(void* lastStackTop) |
194 | { |
195 | m_savedLastStackTop = lastStackTop; |
196 | } |
197 | |
198 | #if OS(DARWIN) |
199 | mach_port_t machThread() { return m_platformThread; } |
200 | #endif |
201 | |
202 | bool isCompilationThread() const { return m_isCompilationThread; } |
203 | GCThreadType gcThreadType() const { return static_cast<GCThreadType>(m_gcThreadType); } |
204 | |
205 | struct NewThreadContext; |
206 | static void entryPoint(NewThreadContext*); |
207 | protected: |
208 | Thread(); |
209 | |
210 | void initializeInThread(); |
211 | |
212 | // Internal platform-specific Thread establishment implementation. |
213 | bool establishHandle(NewThreadContext*); |
214 | |
215 | #if USE(PTHREADS) |
216 | void establishPlatformSpecificHandle(PlatformThreadHandle); |
217 | #else |
218 | void establishPlatformSpecificHandle(PlatformThreadHandle, ThreadIdentifier); |
219 | #endif |
220 | |
221 | #if USE(PTHREADS) && !OS(DARWIN) |
222 | static void signalHandlerSuspendResume(int, siginfo_t*, void* ucontext); |
223 | #endif |
224 | |
225 | static const char* normalizeThreadName(const char* threadName); |
226 | |
227 | enum JoinableState : uint8_t { |
228 | // The default thread state. The thread can be joined on. |
229 | Joinable, |
230 | |
231 | // Somebody waited on this thread to exit and this thread finally exited. This state is here because there can be a |
232 | // period of time between when the thread exits (which causes pthread_join to return and the remainder of waitOnThreadCompletion to run) |
233 | // and when threadDidExit is called. We need threadDidExit to take charge and delete the thread data since there's |
234 | // nobody else to pick up the slack in this case (since waitOnThreadCompletion has already returned). |
235 | Joined, |
236 | |
237 | // The thread has been detached and can no longer be joined on. At this point, the thread must take care of cleaning up after itself. |
238 | Detached, |
239 | }; |
240 | |
241 | JoinableState joinableState() const { return m_joinableState; } |
242 | void didBecomeDetached() { m_joinableState = Detached; } |
243 | void didExit(); |
244 | void didJoin() { m_joinableState = Joined; } |
245 | bool hasExited() const { return m_didExit; } |
246 | |
247 | // These functions are only called from ThreadGroup. |
248 | ThreadGroupAddResult addToThreadGroup(const AbstractLocker& threadGroupLocker, ThreadGroup&); |
249 | void removeFromThreadGroup(const AbstractLocker& threadGroupLocker, ThreadGroup&); |
250 | |
251 | // The Thread instance is ref'ed and held in thread-specific storage. It will be deref'ed by destructTLS at thread destruction time. |
252 | // For pthread, it employs pthreads-specific 2-pass destruction to reliably remove Thread. |
253 | // For Windows, we use thread_local to defer thread TLS destruction. It assumes regular ThreadSpecific |
254 | // types don't use multiple-pass destruction. |
255 | |
256 | #if !HAVE(FAST_TLS) |
257 | static WTF_EXPORT_PRIVATE ThreadSpecificKey s_key; |
258 | // One time initialization for this class as a whole. |
259 | // This method must be called before initializeTLS() and it is not thread-safe. |
260 | static void initializeTLSKey(); |
261 | #endif |
262 | |
263 | // Creates and puts an instance of Thread into thread-specific storage. |
264 | static Thread& initializeTLS(Ref<Thread>&&); |
265 | WTF_EXPORT_PRIVATE static Thread& initializeCurrentTLS(); |
266 | |
267 | // Returns nullptr if thread-specific storage was not initialized. |
268 | static Thread* currentMayBeNull(); |
269 | |
270 | #if OS(WINDOWS) |
271 | WTF_EXPORT_PRIVATE static Thread* currentDying(); |
272 | static RefPtr<Thread> get(ThreadIdentifier); |
273 | #endif |
274 | |
275 | // This thread-specific destructor is called 2 times when thread terminates: |
276 | // - first, when all the other thread-specific destructors are called, it simply remembers it was 'destroyed once' |
277 | // and (1) re-sets itself into the thread-specific slot or (2) constructs thread local value to call it again later. |
278 | // - second, after all thread-specific destructors were invoked, it gets called again - this time, we remove the |
279 | // Thread from the threadMap, completing the cleanup. |
280 | static void THREAD_SPECIFIC_CALL destructTLS(void* data); |
281 | |
282 | JoinableState m_joinableState { Joinable }; |
283 | bool m_isShuttingDown : 1; |
284 | bool m_didExit : 1; |
285 | bool m_isDestroyedOnce : 1; |
286 | bool m_isCompilationThread: 1; |
287 | unsigned m_gcThreadType : 2; |
288 | |
289 | // Lock & ParkingLot rely on ThreadSpecific. But Thread object can be destroyed even after ThreadSpecific things are destroyed. |
290 | // Use WordLock since WordLock does not depend on ThreadSpecific and this "Thread". |
291 | WordLock m_mutex; |
292 | StackBounds m_stack { StackBounds::emptyBounds() }; |
293 | Vector<std::weak_ptr<ThreadGroup>> m_threadGroups; |
294 | PlatformThreadHandle m_handle; |
295 | #if OS(WINDOWS) |
296 | ThreadIdentifier m_id { 0 }; |
297 | #elif OS(DARWIN) |
298 | mach_port_t m_platformThread { MACH_PORT_NULL }; |
299 | #elif USE(PTHREADS) |
300 | PlatformRegisters* m_platformRegisters { nullptr }; |
301 | unsigned m_suspendCount { 0 }; |
302 | #endif |
303 | |
304 | AtomStringTable* m_currentAtomStringTable { nullptr }; |
305 | AtomStringTable m_defaultAtomStringTable; |
306 | |
307 | #if ENABLE(STACK_STATS) |
308 | StackStats::PerThreadStats m_stackStats; |
309 | #endif |
310 | void* m_savedStackPointerAtVMEntry { nullptr }; |
311 | void* m_savedLastStackTop; |
312 | public: |
313 | void* m_apiData { nullptr }; |
314 | }; |
315 | |
316 | inline Thread::Thread() |
317 | : m_isShuttingDown(false) |
318 | , m_didExit(false) |
319 | , m_isDestroyedOnce(false) |
320 | , m_isCompilationThread(false) |
321 | , m_gcThreadType(static_cast<unsigned>(GCThreadType::None)) |
322 | { |
323 | } |
324 | |
325 | inline Thread* Thread::currentMayBeNull() |
326 | { |
327 | #if !HAVE(FAST_TLS) |
328 | ASSERT(s_key != InvalidThreadSpecificKey); |
329 | return static_cast<Thread*>(threadSpecificGet(s_key)); |
330 | #else |
331 | return static_cast<Thread*>(_pthread_getspecific_direct(WTF_THREAD_DATA_KEY)); |
332 | #endif |
333 | } |
334 | |
335 | inline Thread& Thread::current() |
336 | { |
337 | // WRT WebCore: |
338 | // Thread::current() is used on main thread before it could possibly be used |
339 | // on secondary ones, so there is no need for synchronization here. |
340 | // WRT JavaScriptCore: |
341 | // Thread::initializeTLSKey() is initially called from initializeThreading(), ensuring |
342 | // this is initially called in a std::call_once locked context. |
343 | #if !HAVE(FAST_TLS) |
344 | if (UNLIKELY(Thread::s_key == InvalidThreadSpecificKey)) |
345 | WTF::initializeThreading(); |
346 | #endif |
347 | if (auto* thread = currentMayBeNull()) |
348 | return *thread; |
349 | #if OS(WINDOWS) |
350 | if (auto* thread = currentDying()) |
351 | return *thread; |
352 | #endif |
353 | return initializeCurrentTLS(); |
354 | } |
355 | |
356 | } // namespace WTF |
357 | |
358 | using WTF::Thread; |
359 | using WTF::GCThreadType; |
360 | |