2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "MainThread.h"
32 #include "CurrentTime.h"
34 #include "Functional.h"
35 #include "StdLibExtras.h"
36 #include "Threading.h"
37 #include <wtf/ThreadSpecific.h>
41 struct FunctionWithContext {
42 MainThreadFunction* function;
45 FunctionWithContext(MainThreadFunction* function = nullptr, void* context = nullptr)
50 bool operator == (const FunctionWithContext& o)
52 return function == o.function && context == o.context;
56 class FunctionWithContextFinder {
58 FunctionWithContextFinder(const FunctionWithContext& m) : m(m) {}
59 bool operator() (FunctionWithContext& o) { return o == m; }
60 FunctionWithContext m;
64 typedef Deque<FunctionWithContext> FunctionQueue;
66 static bool callbacksPaused; // This global variable is only accessed from main thread.
68 static ThreadIdentifier mainThreadIdentifier;
71 static Mutex& mainThreadFunctionQueueMutex()
73 DEFINE_STATIC_LOCAL(Mutex, staticMutex, ());
77 static FunctionQueue& functionQueue()
79 DEFINE_STATIC_LOCAL(FunctionQueue, staticFunctionQueue, ());
80 return staticFunctionQueue;
86 void initializeMainThread()
88 static bool initializedMainThread;
89 if (initializedMainThread)
91 initializedMainThread = true;
93 mainThreadIdentifier = currentThread();
95 mainThreadFunctionQueueMutex();
96 initializeMainThreadPlatform();
97 initializeGCThreads();
102 static pthread_once_t initializeMainThreadKeyOnce = PTHREAD_ONCE_INIT;
104 static void initializeMainThreadOnce()
106 mainThreadFunctionQueueMutex();
107 initializeMainThreadPlatform();
110 void initializeMainThread()
112 pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadOnce);
116 static void initializeMainThreadToProcessMainThreadOnce()
118 mainThreadFunctionQueueMutex();
119 initializeMainThreadToProcessMainThreadPlatform();
122 void initializeMainThreadToProcessMainThread()
124 pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadToProcessMainThreadOnce);
127 static pthread_once_t initializeWebThreadKeyOnce = PTHREAD_ONCE_INIT;
129 static void initializeWebThreadOnce()
131 initializeWebThreadPlatform();
134 void initializeWebThread()
136 pthread_once(&initializeWebThreadKeyOnce, initializeWebThreadOnce);
138 #endif // !USE(WEB_THREAD)
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;
145 void dispatchFunctionsFromMainThread()
147 ASSERT(isMainThread());
152 double startTime = monotonicallyIncreasingTime();
154 FunctionWithContext invocation;
157 MutexLocker locker(mainThreadFunctionQueueMutex());
158 if (!functionQueue().size())
160 invocation = functionQueue().takeFirst();
163 invocation.function(invocation.context);
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();
176 void callOnMainThread(MainThreadFunction* function, void* context)
179 bool needToSchedule = false;
181 MutexLocker locker(mainThreadFunctionQueueMutex());
182 needToSchedule = functionQueue().size() == 0;
183 functionQueue().append(FunctionWithContext(function, context));
186 scheduleDispatchFunctionsOnMainThread();
189 void cancelCallOnMainThread(MainThreadFunction* function, void* context)
193 MutexLocker locker(mainThreadFunctionQueueMutex());
195 FunctionWithContextFinder pred(FunctionWithContext(function, context));
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())
203 functionQueue().remove(i);
207 static void callFunctionObject(void* context)
209 auto function = std::unique_ptr<std::function<void ()>>(static_cast<std::function<void ()>*>(context));
213 void callOnMainThread(std::function<void ()> function)
215 callOnMainThread(callFunctionObject, std::make_unique<std::function<void ()>>(std::move(function)).release());
218 void setMainThreadCallbacksPaused(bool paused)
220 ASSERT(isMainThread());
222 if (callbacksPaused == paused)
225 callbacksPaused = paused;
227 if (!callbacksPaused)
228 scheduleDispatchFunctionsOnMainThread();
234 return currentThread() == mainThreadIdentifier;
239 bool canAccessThreadLocalDataForThread(ThreadIdentifier threadId)
241 return threadId == currentThread();
245 #if ENABLE(PARALLEL_GC)
246 static ThreadSpecific<bool>* isGCThread;
249 void initializeGCThreads()
251 #if ENABLE(PARALLEL_GC)
252 isGCThread = new ThreadSpecific<bool>();
256 #if ENABLE(PARALLEL_GC)
257 void registerGCThread()
260 // This happens if we're running in a process that doesn't care about
268 bool isMainThreadOrGCThread()
270 if (isGCThread->isSet() && **isGCThread)
273 return isMainThread();
276 // This is necessary because JavaScriptCore.exp doesn't support preprocessor macros.
277 bool isMainThreadOrGCThread()
279 return isMainThread();