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