summaryrefslogtreecommitdiff
path: root/Source/WTF/wtf/MainThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WTF/wtf/MainThread.cpp')
-rw-r--r--Source/WTF/wtf/MainThread.cpp180
1 files changed, 65 insertions, 115 deletions
diff --git a/Source/WTF/wtf/MainThread.cpp b/Source/WTF/wtf/MainThread.cpp
index b3d63d49e..eea0b36cd 100644
--- a/Source/WTF/wtf/MainThread.cpp
+++ b/Source/WTF/wtf/MainThread.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -31,82 +31,36 @@
#include "CurrentTime.h"
#include "Deque.h"
-#include "Functional.h"
#include "StdLibExtras.h"
+#include "Threading.h"
#include <mutex>
+#include <wtf/Lock.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/ThreadSpecific.h>
namespace WTF {
-struct FunctionWithContext {
- MainThreadFunction* function;
- void* context;
-
- FunctionWithContext(MainThreadFunction* function = nullptr, void* context = nullptr)
- : function(function)
- , context(context)
- {
- }
- bool operator == (const FunctionWithContext& o)
- {
- return function == o.function && context == o.context;
- }
-};
-
-class FunctionWithContextFinder {
-public:
- FunctionWithContextFinder(const FunctionWithContext& m) : m(m) {}
- bool operator() (FunctionWithContext& o) { return o == m; }
- FunctionWithContext m;
-};
-
-
-typedef Deque<FunctionWithContext> FunctionQueue;
-
static bool callbacksPaused; // This global variable is only accessed from main thread.
-#if !PLATFORM(MAC)
+#if !OS(DARWIN) && !PLATFORM(GTK)
static ThreadIdentifier mainThreadIdentifier;
#endif
-static std::mutex& mainThreadFunctionQueueMutex()
-{
- static NeverDestroyed<std::mutex> mutex;
-
- return mutex;
-}
+static StaticLock mainThreadFunctionQueueMutex;
-static FunctionQueue& functionQueue()
+static Deque<Function<void ()>>& functionQueue()
{
- static NeverDestroyed<FunctionQueue> functionQueue;
+ static NeverDestroyed<Deque<Function<void ()>>> functionQueue;
return functionQueue;
}
-
-#if !PLATFORM(MAC)
-
-void initializeMainThread()
-{
- static bool initializedMainThread;
- if (initializedMainThread)
- return;
- initializedMainThread = true;
-
- mainThreadIdentifier = currentThread();
-
- mainThreadFunctionQueueMutex();
- initializeMainThreadPlatform();
- initializeGCThreads();
-}
-
-#else
-
+#if OS(DARWIN) || PLATFORM(GTK)
static pthread_once_t initializeMainThreadKeyOnce = PTHREAD_ONCE_INIT;
static void initializeMainThreadOnce()
{
- mainThreadFunctionQueueMutex();
+ initializeThreading();
initializeMainThreadPlatform();
+ initializeGCThreads();
}
void initializeMainThread()
@@ -114,18 +68,19 @@ void initializeMainThread()
pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadOnce);
}
-#if !USE(WEB_THREAD)
+#if !USE(WEB_THREAD) && !PLATFORM(GTK)
static void initializeMainThreadToProcessMainThreadOnce()
{
- mainThreadFunctionQueueMutex();
+ initializeThreading();
initializeMainThreadToProcessMainThreadPlatform();
+ initializeGCThreads();
}
void initializeMainThreadToProcessMainThread()
{
pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadToProcessMainThreadOnce);
}
-#else
+#elif !PLATFORM(GTK)
static pthread_once_t initializeWebThreadKeyOnce = PTHREAD_ONCE_INIT;
static void initializeWebThreadOnce()
@@ -139,10 +94,24 @@ void initializeWebThread()
}
#endif // !USE(WEB_THREAD)
+#else
+void initializeMainThread()
+{
+ static bool initializedMainThread;
+ if (initializedMainThread)
+ return;
+ initializedMainThread = true;
+
+ initializeThreading();
+ mainThreadIdentifier = currentThread();
+
+ initializeMainThreadPlatform();
+ initializeGCThreads();
+}
#endif
// 0.1 sec delays in UI is approximate threshold when they become noticeable. Have a limit that's half of that.
-static const double maxRunLoopSuspensionTime = 0.05;
+static const auto maxRunLoopSuspensionTime = std::chrono::milliseconds(50);
void dispatchFunctionsFromMainThread()
{
@@ -151,72 +120,51 @@ void dispatchFunctionsFromMainThread()
if (callbacksPaused)
return;
- double startTime = monotonicallyIncreasingTime();
+ auto startTime = std::chrono::steady_clock::now();
+
+ Function<void ()> function;
- FunctionWithContext invocation;
while (true) {
{
- std::lock_guard<std::mutex> lock(mainThreadFunctionQueueMutex());
+ std::lock_guard<StaticLock> lock(mainThreadFunctionQueueMutex);
if (!functionQueue().size())
break;
- invocation = functionQueue().takeFirst();
+
+ function = functionQueue().takeFirst();
}
- invocation.function(invocation.context);
+ function();
+
+ // Clearing the function can have side effects, so do so outside of the lock above.
+ function = nullptr;
// If we are running accumulated functions for too long so UI may become unresponsive, we need to
// yield so the user input can be processed. Otherwise user may not be able to even close the window.
// This code has effect only in case the scheduleDispatchFunctionsOnMainThread() is implemented in a way that
// allows input events to be processed before we are back here.
- if (monotonicallyIncreasingTime() - startTime > maxRunLoopSuspensionTime) {
+ if (std::chrono::steady_clock::now() - startTime > maxRunLoopSuspensionTime) {
scheduleDispatchFunctionsOnMainThread();
break;
}
}
}
-void callOnMainThread(MainThreadFunction* function, void* context)
+void callOnMainThread(Function<void ()>&& function)
{
ASSERT(function);
+
bool needToSchedule = false;
+
{
- std::lock_guard<std::mutex> lock(mainThreadFunctionQueueMutex());
+ std::lock_guard<StaticLock> lock(mainThreadFunctionQueueMutex);
needToSchedule = functionQueue().size() == 0;
- functionQueue().append(FunctionWithContext(function, context));
+ functionQueue().append(WTFMove(function));
}
+
if (needToSchedule)
scheduleDispatchFunctionsOnMainThread();
}
-void cancelCallOnMainThread(MainThreadFunction* function, void* context)
-{
- ASSERT(function);
-
- std::lock_guard<std::mutex> lock(mainThreadFunctionQueueMutex());
-
- FunctionWithContextFinder pred(FunctionWithContext(function, context));
-
- while (true) {
- // We must redefine 'i' each pass, because the itererator's operator=
- // requires 'this' to be valid, and remove() invalidates all iterators
- FunctionQueue::iterator i(functionQueue().findIf(pred));
- if (i == functionQueue().end())
- break;
- functionQueue().remove(i);
- }
-}
-
-static void callFunctionObject(void* context)
-{
- auto function = std::unique_ptr<std::function<void ()>>(static_cast<std::function<void ()>*>(context));
- (*function)();
-}
-
-void callOnMainThread(std::function<void ()> function)
-{
- callOnMainThread(callFunctionObject, std::make_unique<std::function<void ()>>(std::move(function)).release());
-}
-
void setMainThreadCallbacksPaused(bool paused)
{
ASSERT(isMainThread());
@@ -230,7 +178,7 @@ void setMainThreadCallbacksPaused(bool paused)
scheduleDispatchFunctionsOnMainThread();
}
-#if !PLATFORM(MAC)
+#if !OS(DARWIN) && !PLATFORM(GTK)
bool isMainThread()
{
return currentThread() == mainThreadIdentifier;
@@ -244,19 +192,19 @@ bool canAccessThreadLocalDataForThread(ThreadIdentifier threadId)
}
#endif
-#if ENABLE(PARALLEL_GC)
-static ThreadSpecific<bool>* isGCThread;
-#endif
+static ThreadSpecific<std::optional<GCThreadType>, CanBeGCThread::True>* isGCThread;
void initializeGCThreads()
{
-#if ENABLE(PARALLEL_GC)
- isGCThread = new ThreadSpecific<bool>();
-#endif
+ static std::once_flag flag;
+ std::call_once(
+ flag,
+ [] {
+ isGCThread = new ThreadSpecific<std::optional<GCThreadType>, CanBeGCThread::True>();
+ });
}
-#if ENABLE(PARALLEL_GC)
-void registerGCThread()
+void registerGCThread(GCThreadType type)
{
if (!isGCThread) {
// This happens if we're running in a process that doesn't care about
@@ -264,22 +212,24 @@ void registerGCThread()
return;
}
- **isGCThread = true;
+ **isGCThread = type;
}
bool isMainThreadOrGCThread()
{
- if (isGCThread->isSet() && **isGCThread)
+ if (mayBeGCThread())
return true;
return isMainThread();
}
-#elif PLATFORM(MAC)
-// This is necessary because JavaScriptCore.exp doesn't support preprocessor macros.
-bool isMainThreadOrGCThread()
+
+std::optional<GCThreadType> mayBeGCThread()
{
- return isMainThread();
+ if (!isGCThread)
+ return std::nullopt;
+ if (!isGCThread->isSet())
+ return std::nullopt;
+ return **isGCThread;
}
-#endif
} // namespace WTF