a9d46a9b9614ae8aab8321e6f660b4199221219c
[WebKit-https.git] / Source / WTF / wtf / MainThread.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2015 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 "StdLibExtras.h"
35 #include "Threading.h"
36 #include <mutex>
37 #include <wtf/Lock.h>
38 #include <wtf/NeverDestroyed.h>
39 #include <wtf/ThreadSpecific.h>
40
41 namespace WTF {
42
43 static bool callbacksPaused; // This global variable is only accessed from main thread.
44 #if !OS(DARWIN) || PLATFORM(EFL) || PLATFORM(GTK)
45 static ThreadIdentifier mainThreadIdentifier;
46 #endif
47
48 static StaticLock mainThreadFunctionQueueMutex;
49
50 static Deque<Function<void ()>>& functionQueue()
51 {
52     static NeverDestroyed<Deque<Function<void ()>>> functionQueue;
53     return functionQueue;
54 }
55
56 #if !OS(DARWIN) || PLATFORM(EFL) || PLATFORM(GTK)
57
58 void initializeMainThread()
59 {
60     static bool initializedMainThread;
61     if (initializedMainThread)
62         return;
63     initializedMainThread = true;
64
65     mainThreadIdentifier = currentThread();
66
67     initializeMainThreadPlatform();
68     initializeGCThreads();
69 }
70
71 #else
72
73 static pthread_once_t initializeMainThreadKeyOnce = PTHREAD_ONCE_INIT;
74
75 static void initializeMainThreadOnce()
76 {
77     initializeMainThreadPlatform();
78 }
79
80 void initializeMainThread()
81 {
82     pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadOnce);
83 }
84
85 #if !USE(WEB_THREAD)
86 static void initializeMainThreadToProcessMainThreadOnce()
87 {
88     initializeMainThreadToProcessMainThreadPlatform();
89 }
90
91 void initializeMainThreadToProcessMainThread()
92 {
93     pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadToProcessMainThreadOnce);
94 }
95 #else
96 static pthread_once_t initializeWebThreadKeyOnce = PTHREAD_ONCE_INIT;
97
98 static void initializeWebThreadOnce()
99 {
100     initializeWebThreadPlatform();
101 }
102
103 void initializeWebThread()
104 {
105     pthread_once(&initializeWebThreadKeyOnce, initializeWebThreadOnce);
106 }
107 #endif // !USE(WEB_THREAD)
108
109 #endif
110
111 // 0.1 sec delays in UI is approximate threshold when they become noticeable. Have a limit that's half of that.
112 static const auto maxRunLoopSuspensionTime = std::chrono::milliseconds(50);
113
114 void dispatchFunctionsFromMainThread()
115 {
116     ASSERT(isMainThread());
117
118     if (callbacksPaused)
119         return;
120
121     auto startTime = std::chrono::steady_clock::now();
122
123     Function<void ()> function;
124
125     while (true) {
126         {
127             std::lock_guard<StaticLock> lock(mainThreadFunctionQueueMutex);
128             if (!functionQueue().size())
129                 break;
130
131             function = functionQueue().takeFirst();
132         }
133
134         function();
135
136         // Clearing the function can have side effects, so do so outside of the lock above.
137         function = nullptr;
138
139         // If we are running accumulated functions for too long so UI may become unresponsive, we need to
140         // yield so the user input can be processed. Otherwise user may not be able to even close the window.
141         // This code has effect only in case the scheduleDispatchFunctionsOnMainThread() is implemented in a way that
142         // allows input events to be processed before we are back here.
143         if (std::chrono::steady_clock::now() - startTime > maxRunLoopSuspensionTime) {
144             scheduleDispatchFunctionsOnMainThread();
145             break;
146         }
147     }
148 }
149
150 void callOnMainThread(Function<void ()>&& function)
151 {
152     ASSERT(function);
153
154     bool needToSchedule = false;
155
156     {
157         std::lock_guard<StaticLock> lock(mainThreadFunctionQueueMutex);
158         needToSchedule = functionQueue().size() == 0;
159         functionQueue().append(WTFMove(function));
160     }
161
162     if (needToSchedule)
163         scheduleDispatchFunctionsOnMainThread();
164 }
165
166 void setMainThreadCallbacksPaused(bool paused)
167 {
168     ASSERT(isMainThread());
169
170     if (callbacksPaused == paused)
171         return;
172
173     callbacksPaused = paused;
174
175     if (!callbacksPaused)
176         scheduleDispatchFunctionsOnMainThread();
177 }
178
179 #if !OS(DARWIN) || PLATFORM(EFL) || PLATFORM(GTK)
180 bool isMainThread()
181 {
182     return currentThread() == mainThreadIdentifier;
183 }
184 #endif
185
186 #if !USE(WEB_THREAD)
187 bool canAccessThreadLocalDataForThread(ThreadIdentifier threadId)
188 {
189     return threadId == currentThread();
190 }
191 #endif
192
193 static ThreadSpecific<bool>* isGCThread;
194
195 void initializeGCThreads()
196 {
197     isGCThread = new ThreadSpecific<bool>();
198 }
199
200 void registerGCThread()
201 {
202     if (!isGCThread) {
203         // This happens if we're running in a process that doesn't care about
204         // MainThread.
205         return;
206     }
207
208     **isGCThread = true;
209 }
210
211 bool isMainThreadOrGCThread()
212 {
213     if (isGCThread->isSet() && **isGCThread)
214         return true;
215
216     return isMainThread();
217 }
218
219 } // namespace WTF