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
59namespace WTF {
60
61class AbstractLocker;
62class ThreadMessageData;
63
64enum class ThreadGroupAddResult;
65
66class ThreadGroup;
67class PrintStream;
68
69// This function can be called from any threads.
70WTF_EXPORT_PRIVATE void initializeThreading();
71
72#if USE(PTHREADS)
73
74// We use SIGUSR1 to suspend and resume machine threads in JavaScriptCore.
75constexpr const int SigThreadSuspendResume = SIGUSR1;
76
77#endif
78
79enum class GCThreadType : uint8_t {
80 None = 0,
81 Main,
82 Helper,
83};
84
85class Thread : public ThreadSafeRefCounted<Thread> {
86public:
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*);
230protected:
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;
334public:
335 void* m_apiData { nullptr };
336};
337
338inline 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
347inline 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
357inline 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
376using WTF::Thread;
377using WTF::GCThreadType;
378