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
54namespace WTF {
55
56class AbstractLocker;
57class ThreadMessageData;
58
59enum class ThreadGroupAddResult;
60
61class ThreadGroup;
62class PrintStream;
63
64// This function can be called from any threads.
65WTF_EXPORT_PRIVATE void initializeThreading();
66
67#if USE(PTHREADS)
68
69// We use SIGUSR1 to suspend and resume machine threads in JavaScriptCore.
70constexpr const int SigThreadSuspendResume = SIGUSR1;
71
72#endif
73
74enum class GCThreadType : uint8_t {
75 None = 0,
76 Main,
77 Helper,
78};
79
80class Thread : public ThreadSafeRefCounted<Thread> {
81public:
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*);
207protected:
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;
312public:
313 void* m_apiData { nullptr };
314};
315
316inline 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
325inline 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
335inline 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
358using WTF::Thread;
359using WTF::GCThreadType;
360