Add WTF::move()
[WebKit-https.git] / Source / WTF / wtf / MainThread.cpp
1 /*
2  * Copyright (C) 2007, 2008 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 "Functional.h"
35 #include "StdLibExtras.h"
36 #include <mutex>
37 #include <wtf/NeverDestroyed.h>
38 #include <wtf/ThreadSpecific.h>
39
40 namespace WTF {
41
42 struct FunctionWithContext {
43     MainThreadFunction* function;
44     void* context;
45
46     FunctionWithContext(MainThreadFunction* function = nullptr, void* context = nullptr)
47         : function(function)
48         , context(context)
49     {
50     }
51     bool operator == (const FunctionWithContext& o)
52     {
53         return function == o.function && context == o.context;
54     }
55 };
56
57 class FunctionWithContextFinder {
58 public:
59     FunctionWithContextFinder(const FunctionWithContext& m) : m(m) {}
60     bool operator() (FunctionWithContext& o) { return o == m; }
61     FunctionWithContext m;
62 };
63
64
65 typedef Deque<FunctionWithContext> FunctionQueue;
66
67 static bool callbacksPaused; // This global variable is only accessed from main thread.
68 #if !OS(DARWIN) || PLATFORM(EFL) || PLATFORM(GTK)
69 static ThreadIdentifier mainThreadIdentifier;
70 #endif
71
72 static std::mutex& mainThreadFunctionQueueMutex()
73 {
74     static NeverDestroyed<std::mutex> mutex;
75     
76     return mutex;
77 }
78
79 static FunctionQueue& functionQueue()
80 {
81     static NeverDestroyed<FunctionQueue> functionQueue;
82     return functionQueue;
83 }
84
85
86 #if !OS(DARWIN) || PLATFORM(EFL) || PLATFORM(GTK)
87
88 void initializeMainThread()
89 {
90     static bool initializedMainThread;
91     if (initializedMainThread)
92         return;
93     initializedMainThread = true;
94
95     mainThreadIdentifier = currentThread();
96
97     mainThreadFunctionQueueMutex();
98     initializeMainThreadPlatform();
99     initializeGCThreads();
100 }
101
102 #else
103
104 static pthread_once_t initializeMainThreadKeyOnce = PTHREAD_ONCE_INIT;
105
106 static void initializeMainThreadOnce()
107 {
108     mainThreadFunctionQueueMutex();
109     initializeMainThreadPlatform();
110 }
111
112 void initializeMainThread()
113 {
114     pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadOnce);
115 }
116
117 #if !USE(WEB_THREAD)
118 static void initializeMainThreadToProcessMainThreadOnce()
119 {
120     mainThreadFunctionQueueMutex();
121     initializeMainThreadToProcessMainThreadPlatform();
122 }
123
124 void initializeMainThreadToProcessMainThread()
125 {
126     pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadToProcessMainThreadOnce);
127 }
128 #else
129 static pthread_once_t initializeWebThreadKeyOnce = PTHREAD_ONCE_INIT;
130
131 static void initializeWebThreadOnce()
132 {
133     initializeWebThreadPlatform();
134 }
135
136 void initializeWebThread()
137 {
138     pthread_once(&initializeWebThreadKeyOnce, initializeWebThreadOnce);
139 }
140 #endif // !USE(WEB_THREAD)
141
142 #endif
143
144 // 0.1 sec delays in UI is approximate threshold when they become noticeable. Have a limit that's half of that.
145 static const auto maxRunLoopSuspensionTime = std::chrono::milliseconds(50);
146
147 void dispatchFunctionsFromMainThread()
148 {
149     ASSERT(isMainThread());
150
151     if (callbacksPaused)
152         return;
153
154     auto startTime = std::chrono::steady_clock::now();
155
156     FunctionWithContext invocation;
157     while (true) {
158         {
159             std::lock_guard<std::mutex> lock(mainThreadFunctionQueueMutex());
160             if (!functionQueue().size())
161                 break;
162             invocation = functionQueue().takeFirst();
163         }
164
165         invocation.function(invocation.context);
166
167         // If we are running accumulated functions for too long so UI may become unresponsive, we need to
168         // yield so the user input can be processed. Otherwise user may not be able to even close the window.
169         // This code has effect only in case the scheduleDispatchFunctionsOnMainThread() is implemented in a way that
170         // allows input events to be processed before we are back here.
171         if (std::chrono::steady_clock::now() - startTime > maxRunLoopSuspensionTime) {
172             scheduleDispatchFunctionsOnMainThread();
173             break;
174         }
175     }
176 }
177
178 void callOnMainThread(MainThreadFunction* function, void* context)
179 {
180     ASSERT(function);
181     bool needToSchedule = false;
182     {
183         std::lock_guard<std::mutex> lock(mainThreadFunctionQueueMutex());
184         needToSchedule = functionQueue().size() == 0;
185         functionQueue().append(FunctionWithContext(function, context));
186     }
187     if (needToSchedule)
188         scheduleDispatchFunctionsOnMainThread();
189 }
190
191 void cancelCallOnMainThread(MainThreadFunction* function, void* context)
192 {
193     ASSERT(function);
194
195     std::lock_guard<std::mutex> lock(mainThreadFunctionQueueMutex());
196
197     FunctionWithContextFinder pred(FunctionWithContext(function, context));
198
199     while (true) {
200         // We must redefine 'i' each pass, because the itererator's operator= 
201         // requires 'this' to be valid, and remove() invalidates all iterators
202         FunctionQueue::iterator i(functionQueue().findIf(pred));
203         if (i == functionQueue().end())
204             break;
205         functionQueue().remove(i);
206     }
207 }
208
209 static void callFunctionObject(void* context)
210 {
211     auto function = std::unique_ptr<std::function<void ()>>(static_cast<std::function<void ()>*>(context));
212     (*function)();
213 }
214
215 void callOnMainThread(std::function<void ()> function)
216 {
217     callOnMainThread(callFunctionObject, std::make_unique<std::function<void ()>>(WTF::move(function)).release());
218 }
219
220 void setMainThreadCallbacksPaused(bool paused)
221 {
222     ASSERT(isMainThread());
223
224     if (callbacksPaused == paused)
225         return;
226
227     callbacksPaused = paused;
228
229     if (!callbacksPaused)
230         scheduleDispatchFunctionsOnMainThread();
231 }
232
233 #if !OS(DARWIN) || PLATFORM(EFL) || PLATFORM(GTK)
234 bool isMainThread()
235 {
236     return currentThread() == mainThreadIdentifier;
237 }
238 #endif
239
240 #if !USE(WEB_THREAD)
241 bool canAccessThreadLocalDataForThread(ThreadIdentifier threadId)
242 {
243     return threadId == currentThread();
244 }
245 #endif
246
247 #if ENABLE(PARALLEL_GC)
248 static ThreadSpecific<bool>* isGCThread;
249 #endif
250
251 void initializeGCThreads()
252 {
253 #if ENABLE(PARALLEL_GC)
254     isGCThread = new ThreadSpecific<bool>();
255 #endif
256 }
257
258 #if ENABLE(PARALLEL_GC)
259 void registerGCThread()
260 {
261     if (!isGCThread) {
262         // This happens if we're running in a process that doesn't care about
263         // MainThread.
264         return;
265     }
266
267     **isGCThread = true;
268 }
269
270 bool isMainThreadOrGCThread()
271 {
272     if (isGCThread->isSet() && **isGCThread)
273         return true;
274
275     return isMainThread();
276 }
277 #elif OS(DARWIN) && !PLATFORM(EFL) && !PLATFORM(GTK)
278 // This is necessary because JavaScriptCore.exp doesn't support preprocessor macros.
279 bool isMainThreadOrGCThread()
280 {
281     return isMainThread();
282 }
283 #endif
284
285 } // namespace WTF