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