It should be easy to decide how WebKit yields
[WebKit-https.git] / Source / WTF / wtf / Threading.cpp
1 /*
2  * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "Threading.h"
28
29 #include <algorithm>
30 #include <cmath>
31 #include <cstring>
32 #include <thread>
33 #include <wtf/DateMath.h>
34 #include <wtf/PrintStream.h>
35 #include <wtf/RandomNumberSeed.h>
36 #include <wtf/ThreadGroup.h>
37 #include <wtf/ThreadHolder.h>
38 #include <wtf/ThreadMessage.h>
39 #include <wtf/ThreadingPrimitives.h>
40 #include <wtf/WTFThreadData.h>
41 #include <wtf/text/StringView.h>
42
43 #if HAVE(QOS_CLASSES)
44 #include <bmalloc/bmalloc.h>
45 #endif
46
47 namespace WTF {
48
49 enum class Stage {
50     Start, EstablishedHandle, Initialized
51 };
52
53 struct Thread::NewThreadContext {
54     const char* name;
55     Function<void()> entryPoint;
56     Stage stage;
57     Mutex mutex;
58     ThreadCondition condition;
59     Thread& thread;
60 };
61
62 const char* Thread::normalizeThreadName(const char* threadName)
63 {
64 #if HAVE(PTHREAD_SETNAME_NP)
65     return threadName;
66 #else
67     // This name can be com.apple.WebKit.ProcessLauncher or com.apple.CoreIPC.ReceiveQueue.
68     // We are using those names for the thread name, but both are longer than the limit of
69     // the platform thread name length, 32 for Windows and 16 for Linux.
70     StringView result(threadName);
71     size_t size = result.reverseFind('.');
72     if (size != notFound)
73         result = result.substring(size + 1);
74
75 #if OS(WINDOWS)
76     constexpr const size_t kVisualStudioThreadNameLimit = 32 - 1;
77     if (result.length() > kVisualStudioThreadNameLimit)
78         result = result.right(kVisualStudioThreadNameLimit);
79 #elif OS(LINUX)
80     constexpr const size_t kLinuxThreadNameLimit = 16 - 1;
81     if (result.length() > kLinuxThreadNameLimit)
82         result = result.right(kLinuxThreadNameLimit);
83 #endif
84     ASSERT(result.characters8()[result.length()] == '\0');
85     return reinterpret_cast<const char*>(result.characters8());
86 #endif
87 }
88
89 void Thread::entryPoint(NewThreadContext* context)
90 {
91     Function<void()> function;
92     {
93         // Block until our creating thread has completed any extra setup work, including establishing ThreadIdentifier.
94         MutexLocker locker(context->mutex);
95         ASSERT(context->stage == Stage::EstablishedHandle);
96
97         // Initialize thread holder with established ID.
98         ThreadHolder::initialize(context->thread);
99
100         Thread::initializeCurrentThreadInternal(context->thread, context->name);
101         function = WTFMove(context->entryPoint);
102
103         // Ack completion of initialization to the creating thread.
104         context->stage = Stage::Initialized;
105         context->condition.signal();
106     }
107     function();
108 }
109
110 RefPtr<Thread> Thread::create(const char* name, Function<void()>&& entryPoint)
111 {
112     Ref<Thread> thread = adoptRef(*new Thread());
113     NewThreadContext context { name, WTFMove(entryPoint), Stage::Start, { }, { }, thread.get() };
114     MutexLocker locker(context.mutex);
115     if (!thread->establishHandle(&context))
116         return nullptr;
117     context.stage = Stage::EstablishedHandle;
118     // After establishing Thread, release the mutex and wait for completion of initialization.
119     while (context.stage != Stage::Initialized)
120         context.condition.wait(context.mutex);
121     return WTFMove(thread);
122 }
123
124 Thread* Thread::currentMayBeNull()
125 {
126     ThreadHolder* data = ThreadHolder::current();
127     if (data)
128         return &data->thread();
129     return nullptr;
130 }
131
132 void Thread::initialize()
133 {
134     m_stack = StackBounds::currentThreadStackBounds();
135 }
136
137 static bool shouldRemoveThreadFromThreadGroup()
138 {
139 #if OS(WINDOWS)
140     // On Windows the thread specific destructor is also called when the
141     // main thread is exiting. This may lead to the main thread waiting
142     // forever for the thread group lock when exiting, if the sampling
143     // profiler thread was terminated by the system while holding the
144     // thread group lock.
145     if (WTF::isMainThread())
146         return false;
147 #endif
148     return true;
149 }
150
151 void Thread::didExit()
152 {
153     if (shouldRemoveThreadFromThreadGroup()) {
154         Vector<std::shared_ptr<ThreadGroup>> threadGroups;
155         {
156             std::lock_guard<std::mutex> locker(m_mutex);
157             for (auto& threadGroup : m_threadGroups) {
158                 // If ThreadGroup is just being destroyed,
159                 // we do not need to perform unregistering.
160                 if (auto retained = threadGroup.lock())
161                     threadGroups.append(WTFMove(retained));
162             }
163             m_isShuttingDown = true;
164         }
165         for (auto& threadGroup : threadGroups) {
166             std::lock_guard<std::mutex> threadGroupLocker(threadGroup->getLock());
167             std::lock_guard<std::mutex> locker(m_mutex);
168             threadGroup->m_threads.remove(*this);
169         }
170     }
171     // We would like to say "thread is exited" after unregistering threads from thread groups.
172     // So we need to separate m_isShuttingDown from m_didExit.
173     std::lock_guard<std::mutex> locker(m_mutex);
174     m_didExit = true;
175 }
176
177 ThreadGroupAddResult Thread::addToThreadGroup(const AbstractLocker& threadGroupLocker, ThreadGroup& threadGroup)
178 {
179     UNUSED_PARAM(threadGroupLocker);
180     std::lock_guard<std::mutex> locker(m_mutex);
181     if (m_isShuttingDown)
182         return ThreadGroupAddResult::NotAdded;
183     if (threadGroup.m_threads.add(*this).isNewEntry) {
184         m_threadGroups.append(threadGroup.weakFromThis());
185         return ThreadGroupAddResult::NewlyAdded;
186     }
187     return ThreadGroupAddResult::AlreadyAdded;
188 }
189
190 void Thread::removeFromThreadGroup(const AbstractLocker& threadGroupLocker, ThreadGroup& threadGroup)
191 {
192     UNUSED_PARAM(threadGroupLocker);
193     std::lock_guard<std::mutex> locker(m_mutex);
194     if (m_isShuttingDown)
195         return;
196     m_threadGroups.removeFirstMatching([&] (auto weakPtr) {
197         if (auto sharedPtr = weakPtr.lock())
198             return sharedPtr.get() == &threadGroup;
199         return false;
200     });
201 }
202
203 void Thread::setCurrentThreadIsUserInteractive(int relativePriority)
204 {
205 #if HAVE(QOS_CLASSES)
206     ASSERT(relativePriority <= 0);
207     ASSERT(relativePriority >= QOS_MIN_RELATIVE_PRIORITY);
208     pthread_set_qos_class_self_np(adjustedQOSClass(QOS_CLASS_USER_INTERACTIVE), relativePriority);
209 #else
210     UNUSED_PARAM(relativePriority);
211 #endif
212 }
213
214 void Thread::setCurrentThreadIsUserInitiated(int relativePriority)
215 {
216 #if HAVE(QOS_CLASSES)
217     ASSERT(relativePriority <= 0);
218     ASSERT(relativePriority >= QOS_MIN_RELATIVE_PRIORITY);
219     pthread_set_qos_class_self_np(adjustedQOSClass(QOS_CLASS_USER_INITIATED), relativePriority);
220 #else
221     UNUSED_PARAM(relativePriority);
222 #endif
223 }
224
225 #if HAVE(QOS_CLASSES)
226 static qos_class_t globalMaxQOSclass { QOS_CLASS_UNSPECIFIED };
227
228 void Thread::setGlobalMaxQOSClass(qos_class_t maxClass)
229 {
230     bmalloc::api::setScavengerThreadQOSClass(maxClass);
231     globalMaxQOSclass = maxClass;
232 }
233
234 qos_class_t Thread::adjustedQOSClass(qos_class_t originalClass)
235 {
236     if (globalMaxQOSclass != QOS_CLASS_UNSPECIFIED)
237         return std::min(originalClass, globalMaxQOSclass);
238     return originalClass;
239 }
240 #endif
241
242 void Thread::dump(PrintStream& out) const
243 {
244     out.print(m_id);
245 }
246
247 void initializeThreading()
248 {
249     static std::once_flag initializeKey;
250     std::call_once(initializeKey, [] {
251         ThreadHolder::initializeOnce();
252         initializeRandomNumberGenerator();
253         wtfThreadData();
254         initializeDates();
255         Thread::initializePlatformThreading();
256     });
257 }
258
259 } // namespace WTF