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/HashMap.h> |
40 | #include <wtf/HashSet.h> |
41 | #include <wtf/PlatformRegisters.h> |
42 | #include <wtf/Ref.h> |
43 | #include <wtf/RefPtr.h> |
44 | #include <wtf/StackBounds.h> |
45 | #include <wtf/StackStats.h> |
46 | #include <wtf/ThreadSafeRefCounted.h> |
47 | #include <wtf/Vector.h> |
48 | #include <wtf/WordLock.h> |
49 | #include <wtf/text/AtomStringTable.h> |
50 | |
51 | #if USE(PTHREADS) && !OS(DARWIN) |
52 | #include <signal.h> |
53 | #endif |
54 | |
55 | #if OS(WINDOWS) |
56 | #include <array> |
57 | #endif |
58 | |
59 | namespace WTF { |
60 | |
61 | class AbstractLocker; |
62 | class ThreadMessageData; |
63 | |
64 | enum class ThreadGroupAddResult; |
65 | |
66 | class ThreadGroup; |
67 | class PrintStream; |
68 | |
69 | // This function can be called from any threads. |
70 | WTF_EXPORT_PRIVATE void initializeThreading(); |
71 | |
72 | #if USE(PTHREADS) |
73 | |
74 | // We use SIGUSR1 to suspend and resume machine threads in JavaScriptCore. |
75 | constexpr const int SigThreadSuspendResume = SIGUSR1; |
76 | |
77 | #endif |
78 | |
79 | enum class GCThreadType : uint8_t { |
80 | None = 0, |
81 | Main, |
82 | Helper, |
83 | }; |
84 | |
85 | class Thread : public ThreadSafeRefCounted<Thread> { |
86 | public: |
87 | friend class ThreadGroup; |
88 | friend WTF_EXPORT_PRIVATE void initializeThreading(); |
89 | |
90 | WTF_EXPORT_PRIVATE ~Thread(); |
91 | |
92 | // Returns nullptr if thread creation failed. |
93 | // The thread name must be a literal since on some platforms it's passed in to the thread. |
94 | WTF_EXPORT_PRIVATE static Ref<Thread> create(const char* threadName, Function<void()>&&); |
95 | |
96 | // Returns Thread object. |
97 | static Thread& current(); |
98 | |
99 | // Set of all WTF::Thread created threads. |
100 | WTF_EXPORT_PRIVATE static HashSet<Thread*>& allThreads(const LockHolder&); |
101 | WTF_EXPORT_PRIVATE static Lock& allThreadsMutex(); |
102 | |
103 | WTF_EXPORT_PRIVATE unsigned numberOfThreadGroups(); |
104 | |
105 | #if OS(WINDOWS) |
106 | // Returns ThreadIdentifier directly. It is useful if the user only cares about identity |
107 | // of threads. At that time, users should know that holding this ThreadIdentifier does not ensure |
108 | // that the thread information is alive. While Thread::current() is not safe if it is called |
109 | // from the destructor of the other TLS data, currentID() always returns meaningful thread ID. |
110 | WTF_EXPORT_PRIVATE static ThreadIdentifier currentID(); |
111 | |
112 | ThreadIdentifier id() const { return m_id; } |
113 | |
114 | class SpecificStorage { |
115 | public: |
116 | using DestroyFunction = void (*)(void*); |
117 | WTF_EXPORT_PRIVATE static bool allocateKey(int& key, DestroyFunction); |
118 | WTF_EXPORT_PRIVATE void* get(int key); |
119 | WTF_EXPORT_PRIVATE void set(int key, void* value); |
120 | void destroySlots(); |
121 | |
122 | private: |
123 | static constexpr size_t s_maxKeys = 32; |
124 | static Atomic<int> s_numberOfKeys; |
125 | static std::array<Atomic<DestroyFunction>, s_maxKeys> s_destroyFunctions; |
126 | std::array<void*, s_maxKeys> m_slots { }; |
127 | }; |
128 | |
129 | SpecificStorage& specificStorage() { return m_specificStorage; }; |
130 | #endif |
131 | |
132 | WTF_EXPORT_PRIVATE void changePriority(int); |
133 | WTF_EXPORT_PRIVATE int waitForCompletion(); |
134 | WTF_EXPORT_PRIVATE void detach(); |
135 | |
136 | #if OS(DARWIN) |
137 | using PlatformSuspendError = kern_return_t; |
138 | #elif USE(PTHREADS) |
139 | using PlatformSuspendError = int; |
140 | #elif OS(WINDOWS) |
141 | using PlatformSuspendError = DWORD; |
142 | #endif |
143 | |
144 | WTF_EXPORT_PRIVATE Expected<void, PlatformSuspendError> suspend(); |
145 | WTF_EXPORT_PRIVATE void resume(); |
146 | WTF_EXPORT_PRIVATE size_t getRegisters(PlatformRegisters&); |
147 | |
148 | #if USE(PTHREADS) |
149 | WTF_EXPORT_PRIVATE bool signal(int signalNumber); |
150 | #endif |
151 | |
152 | // Mark the current thread as requiring UI responsiveness. |
153 | // relativePriority is a value in the range [-15, 0] where a lower value indicates a lower priority. |
154 | WTF_EXPORT_PRIVATE static void setCurrentThreadIsUserInteractive(int relativePriority = 0); |
155 | WTF_EXPORT_PRIVATE static void setCurrentThreadIsUserInitiated(int relativePriority = 0); |
156 | |
157 | #if HAVE(QOS_CLASSES) |
158 | WTF_EXPORT_PRIVATE static void setGlobalMaxQOSClass(qos_class_t); |
159 | WTF_EXPORT_PRIVATE static qos_class_t adjustedQOSClass(qos_class_t); |
160 | #endif |
161 | |
162 | // Called in the thread during initialization. |
163 | // Helpful for platforms where the thread name must be set from within the thread. |
164 | static void initializeCurrentThreadInternal(const char* threadName); |
165 | static void initializeCurrentThreadEvenIfNonWTFCreated(); |
166 | |
167 | WTF_EXPORT_PRIVATE static void yield(); |
168 | |
169 | WTF_EXPORT_PRIVATE static bool exchangeIsCompilationThread(bool newValue); |
170 | WTF_EXPORT_PRIVATE static void registerGCThread(GCThreadType); |
171 | WTF_EXPORT_PRIVATE static bool mayBeGCThread(); |
172 | |
173 | WTF_EXPORT_PRIVATE void dump(PrintStream& out) const; |
174 | |
175 | static void initializePlatformThreading(); |
176 | |
177 | const StackBounds& stack() const |
178 | { |
179 | return m_stack; |
180 | } |
181 | |
182 | AtomStringTable* atomStringTable() |
183 | { |
184 | return m_currentAtomStringTable; |
185 | } |
186 | |
187 | AtomStringTable* setCurrentAtomStringTable(AtomStringTable* atomStringTable) |
188 | { |
189 | AtomStringTable* oldAtomStringTable = m_currentAtomStringTable; |
190 | m_currentAtomStringTable = atomStringTable; |
191 | return oldAtomStringTable; |
192 | } |
193 | |
194 | #if ENABLE(STACK_STATS) |
195 | StackStats::PerThreadStats& stackStats() |
196 | { |
197 | return m_stackStats; |
198 | } |
199 | #endif |
200 | |
201 | void* savedStackPointerAtVMEntry() |
202 | { |
203 | return m_savedStackPointerAtVMEntry; |
204 | } |
205 | |
206 | void setSavedStackPointerAtVMEntry(void* stackPointerAtVMEntry) |
207 | { |
208 | m_savedStackPointerAtVMEntry = stackPointerAtVMEntry; |
209 | } |
210 | |
211 | void* savedLastStackTop() |
212 | { |
213 | return m_savedLastStackTop; |
214 | } |
215 | |
216 | void setSavedLastStackTop(void* lastStackTop) |
217 | { |
218 | m_savedLastStackTop = lastStackTop; |
219 | } |
220 | |
221 | #if OS(DARWIN) |
222 | mach_port_t machThread() { return m_platformThread; } |
223 | #endif |
224 | |
225 | bool isCompilationThread() const { return m_isCompilationThread; } |
226 | GCThreadType gcThreadType() const { return static_cast<GCThreadType>(m_gcThreadType); } |
227 | |
228 | struct NewThreadContext; |
229 | static void entryPoint(NewThreadContext*); |
230 | protected: |
231 | Thread(); |
232 | |
233 | void initializeInThread(); |
234 | |
235 | // Internal platform-specific Thread establishment implementation. |
236 | bool establishHandle(NewThreadContext*); |
237 | |
238 | #if USE(PTHREADS) |
239 | void establishPlatformSpecificHandle(PlatformThreadHandle); |
240 | #else |
241 | void establishPlatformSpecificHandle(PlatformThreadHandle, ThreadIdentifier); |
242 | #endif |
243 | |
244 | #if USE(PTHREADS) && !OS(DARWIN) |
245 | static void signalHandlerSuspendResume(int, siginfo_t*, void* ucontext); |
246 | #endif |
247 | |
248 | static const char* normalizeThreadName(const char* threadName); |
249 | |
250 | enum JoinableState : uint8_t { |
251 | // The default thread state. The thread can be joined on. |
252 | Joinable, |
253 | |
254 | // Somebody waited on this thread to exit and this thread finally exited. This state is here because there can be a |
255 | // period of time between when the thread exits (which causes pthread_join to return and the remainder of waitOnThreadCompletion to run) |
256 | // and when threadDidExit is called. We need threadDidExit to take charge and delete the thread data since there's |
257 | // nobody else to pick up the slack in this case (since waitOnThreadCompletion has already returned). |
258 | Joined, |
259 | |
260 | // 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. |
261 | Detached, |
262 | }; |
263 | |
264 | JoinableState joinableState() const { return m_joinableState; } |
265 | void didBecomeDetached() { m_joinableState = Detached; } |
266 | void didExit(); |
267 | void didJoin() { m_joinableState = Joined; } |
268 | bool hasExited() const { return m_didExit; } |
269 | |
270 | // These functions are only called from ThreadGroup. |
271 | ThreadGroupAddResult addToThreadGroup(const AbstractLocker& threadGroupLocker, ThreadGroup&); |
272 | void removeFromThreadGroup(const AbstractLocker& threadGroupLocker, ThreadGroup&); |
273 | |
274 | // The Thread instance is ref'ed and held in thread-specific storage. It will be deref'ed by destructTLS at thread destruction time. |
275 | // For pthread, it employs pthreads-specific 2-pass destruction to reliably remove Thread. |
276 | // For Windows, we use thread_local to defer thread TLS destruction. It assumes regular ThreadSpecific |
277 | // types don't use multiple-pass destruction. |
278 | |
279 | #if !HAVE(FAST_TLS) |
280 | static WTF_EXPORT_PRIVATE ThreadSpecificKey s_key; |
281 | // One time initialization for this class as a whole. |
282 | // This method must be called before initializeTLS() and it is not thread-safe. |
283 | static void initializeTLSKey(); |
284 | #endif |
285 | |
286 | // Creates and puts an instance of Thread into thread-specific storage. |
287 | static Thread& initializeTLS(Ref<Thread>&&); |
288 | WTF_EXPORT_PRIVATE static Thread& initializeCurrentTLS(); |
289 | |
290 | // Returns nullptr if thread-specific storage was not initialized. |
291 | static Thread* currentMayBeNull(); |
292 | |
293 | // This thread-specific destructor is called 2 times when thread terminates: |
294 | // - first, when all the other thread-specific destructors are called, it simply remembers it was 'destroyed once' |
295 | // and (1) re-sets itself into the thread-specific slot or (2) constructs thread local value to call it again later. |
296 | // - second, after all thread-specific destructors were invoked, it gets called again - this time, we deref the |
297 | // Thread in the TLS, completing the cleanup. |
298 | static void THREAD_SPECIFIC_CALL destructTLS(void* data); |
299 | |
300 | JoinableState m_joinableState { Joinable }; |
301 | bool m_isShuttingDown : 1; |
302 | bool m_didExit : 1; |
303 | bool m_isDestroyedOnce : 1; |
304 | bool m_isCompilationThread: 1; |
305 | unsigned m_gcThreadType : 2; |
306 | |
307 | // Lock & ParkingLot rely on ThreadSpecific. But Thread object can be destroyed even after ThreadSpecific things are destroyed. |
308 | // Use WordLock since WordLock does not depend on ThreadSpecific and this "Thread". |
309 | WordLock m_mutex; |
310 | StackBounds m_stack { StackBounds::emptyBounds() }; |
311 | HashMap<ThreadGroup*, std::weak_ptr<ThreadGroup>> m_threadGroupMap; |
312 | PlatformThreadHandle m_handle; |
313 | #if OS(WINDOWS) |
314 | ThreadIdentifier m_id { 0 }; |
315 | #elif OS(DARWIN) |
316 | mach_port_t m_platformThread { MACH_PORT_NULL }; |
317 | #elif USE(PTHREADS) |
318 | PlatformRegisters* m_platformRegisters { nullptr }; |
319 | unsigned m_suspendCount { 0 }; |
320 | #endif |
321 | |
322 | #if OS(WINDOWS) |
323 | SpecificStorage m_specificStorage; |
324 | #endif |
325 | |
326 | AtomStringTable* m_currentAtomStringTable { nullptr }; |
327 | AtomStringTable m_defaultAtomStringTable; |
328 | |
329 | #if ENABLE(STACK_STATS) |
330 | StackStats::PerThreadStats m_stackStats; |
331 | #endif |
332 | void* m_savedStackPointerAtVMEntry { nullptr }; |
333 | void* m_savedLastStackTop; |
334 | public: |
335 | void* m_apiData { nullptr }; |
336 | }; |
337 | |
338 | inline Thread::Thread() |
339 | : m_isShuttingDown(false) |
340 | , m_didExit(false) |
341 | , m_isDestroyedOnce(false) |
342 | , m_isCompilationThread(false) |
343 | , m_gcThreadType(static_cast<unsigned>(GCThreadType::None)) |
344 | { |
345 | } |
346 | |
347 | inline Thread* Thread::currentMayBeNull() |
348 | { |
349 | #if !HAVE(FAST_TLS) |
350 | ASSERT(s_key != InvalidThreadSpecificKey); |
351 | return static_cast<Thread*>(threadSpecificGet(s_key)); |
352 | #else |
353 | return static_cast<Thread*>(_pthread_getspecific_direct(WTF_THREAD_DATA_KEY)); |
354 | #endif |
355 | } |
356 | |
357 | inline Thread& Thread::current() |
358 | { |
359 | // WRT WebCore: |
360 | // Thread::current() is used on main thread before it could possibly be used |
361 | // on secondary ones, so there is no need for synchronization here. |
362 | // WRT JavaScriptCore: |
363 | // Thread::initializeTLSKey() is initially called from initializeThreading(), ensuring |
364 | // this is initially called in a std::call_once locked context. |
365 | #if !HAVE(FAST_TLS) |
366 | if (UNLIKELY(Thread::s_key == InvalidThreadSpecificKey)) |
367 | WTF::initializeThreading(); |
368 | #endif |
369 | if (auto* thread = currentMayBeNull()) |
370 | return *thread; |
371 | return initializeCurrentTLS(); |
372 | } |
373 | |
374 | } // namespace WTF |
375 | |
376 | using WTF::Thread; |
377 | using WTF::GCThreadType; |
378 | |