2c41627d6e7940d48c95dc73ace3fbb261386bd3
[WebKit.git] / Source / WTF / wtf / MainThread.cpp
1 /*
2  * Copyright (C) 2007-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  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "MainThread.h"
31
32 #include "CurrentTime.h"
33 #include "Deque.h"
34 #include "MonotonicTime.h"
35 #include "StdLibExtras.h"
36 #include "Threading.h"
37 #include <mutex>
38 #include <wtf/Condition.h>
39 #include <wtf/Lock.h>
40 #include <wtf/NeverDestroyed.h>
41 #include <wtf/ThreadSpecific.h>
42
43 namespace WTF {
44
45 static bool callbacksPaused; // This global variable is only accessed from main thread.
46 #if !PLATFORM(COCOA)
47 static ThreadIdentifier mainThreadIdentifier;
48 #endif
49
50 static StaticLock mainThreadFunctionQueueMutex;
51
52 static Deque<Function<void ()>>& functionQueue()
53 {
54     static NeverDestroyed<Deque<Function<void ()>>> functionQueue;
55     return functionQueue;
56 }
57
58 // Share this initializeKey with initializeMainThread and initializeMainThreadToProcessMainThread.
59 static std::once_flag initializeKey;
60 void initializeMainThread()
61 {
62     std::call_once(initializeKey, [] {
63         initializeThreading();
64 #if !PLATFORM(COCOA)
65         mainThreadIdentifier = currentThread();
66 #endif
67         initializeMainThreadPlatform();
68         initializeGCThreads();
69     });
70 }
71
72 #if !PLATFORM(COCOA)
73 bool isMainThread()
74 {
75     return currentThread() == mainThreadIdentifier;
76 }
77 #endif
78
79 #if PLATFORM(COCOA)
80 #if !USE(WEB_THREAD)
81 void initializeMainThreadToProcessMainThread()
82 {
83     std::call_once(initializeKey, [] {
84         initializeThreading();
85         initializeMainThreadToProcessMainThreadPlatform();
86         initializeGCThreads();
87     });
88 }
89 #else
90 void initializeWebThread()
91 {
92     static std::once_flag initializeKey;
93     std::call_once(initializeKey, [] {
94         initializeWebThreadPlatform();
95     });
96 }
97 #endif // !USE(WEB_THREAD)
98 #endif // PLATFORM(COCOA)
99
100 #if !USE(WEB_THREAD)
101 bool canAccessThreadLocalDataForThread(ThreadIdentifier threadId)
102 {
103     return threadId == currentThread();
104 }
105 #endif
106
107 // 0.1 sec delays in UI is approximate threshold when they become noticeable. Have a limit that's half of that.
108 static const auto maxRunLoopSuspensionTime = 50_ms;
109
110 void dispatchFunctionsFromMainThread()
111 {
112     ASSERT(isMainThread());
113
114     if (callbacksPaused)
115         return;
116
117     auto startTime = MonotonicTime::now();
118
119     Function<void ()> function;
120
121     while (true) {
122         {
123             std::lock_guard<StaticLock> lock(mainThreadFunctionQueueMutex);
124             if (!functionQueue().size())
125                 break;
126
127             function = functionQueue().takeFirst();
128         }
129
130         function();
131
132         // Clearing the function can have side effects, so do so outside of the lock above.
133         function = nullptr;
134
135         // If we are running accumulated functions for too long so UI may become unresponsive, we need to
136         // yield so the user input can be processed. Otherwise user may not be able to even close the window.
137         // This code has effect only in case the scheduleDispatchFunctionsOnMainThread() is implemented in a way that
138         // allows input events to be processed before we are back here.
139         if (MonotonicTime::now() - startTime > maxRunLoopSuspensionTime) {
140             scheduleDispatchFunctionsOnMainThread();
141             break;
142         }
143     }
144 }
145
146 void callOnMainThread(Function<void()>&& function)
147 {
148     ASSERT(function);
149
150     bool needToSchedule = false;
151
152     {
153         std::lock_guard<StaticLock> lock(mainThreadFunctionQueueMutex);
154         needToSchedule = functionQueue().size() == 0;
155         functionQueue().append(WTFMove(function));
156     }
157
158     if (needToSchedule)
159         scheduleDispatchFunctionsOnMainThread();
160 }
161
162 void setMainThreadCallbacksPaused(bool paused)
163 {
164     ASSERT(isMainThread());
165
166     if (callbacksPaused == paused)
167         return;
168
169     callbacksPaused = paused;
170
171     if (!callbacksPaused)
172         scheduleDispatchFunctionsOnMainThread();
173 }
174
175 static ThreadSpecific<std::optional<GCThreadType>, CanBeGCThread::True>* isGCThread;
176
177 void initializeGCThreads()
178 {
179     static std::once_flag flag;
180     std::call_once(
181         flag,
182         [] {
183             isGCThread = new ThreadSpecific<std::optional<GCThreadType>, CanBeGCThread::True>();
184         });
185 }
186
187 void registerGCThread(GCThreadType type)
188 {
189     if (!isGCThread) {
190         // This happens if we're running in a process that doesn't care about
191         // MainThread.
192         return;
193     }
194
195     **isGCThread = type;
196 }
197
198 bool isMainThreadOrGCThread()
199 {
200     if (mayBeGCThread())
201         return true;
202
203     return isMainThread();
204 }
205
206 std::optional<GCThreadType> mayBeGCThread()
207 {
208     if (!isGCThread)
209         return std::nullopt;
210     if (!isGCThread->isSet())
211         return std::nullopt;
212     return **isGCThread;
213 }
214
215 void callOnMainThreadAndWait(WTF::Function<void()>&& function)
216 {
217     if (isMainThread()) {
218         function();
219         return;
220     }
221
222     Lock mutex;
223     Condition conditionVariable;
224
225     bool isFinished = false;
226
227     callOnMainThread([&, function = WTFMove(function)] {
228         function();
229
230         std::lock_guard<Lock> lock(mutex);
231         isFinished = true;
232         conditionVariable.notifyOne();
233     });
234
235     std::unique_lock<Lock> lock(mutex);
236     conditionVariable.wait(lock, [&] {
237         return isFinished;
238     });
239 }
240
241 } // namespace WTF