X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/ba379fdc102753d6be2c4d937058fe40257329fe..14957cd040308e3eeec43d26bae5d76da13fcd85:/wtf/MainThread.cpp diff --git a/wtf/MainThread.cpp b/wtf/MainThread.cpp index e999094..3229e5b 100644 --- a/wtf/MainThread.cpp +++ b/wtf/MainThread.cpp @@ -29,29 +29,54 @@ #include "config.h" #include "MainThread.h" -#include "StdLibExtras.h" #include "CurrentTime.h" #include "Deque.h" +#include "StdLibExtras.h" #include "Threading.h" +#include + +#if PLATFORM(CHROMIUM) +#error Chromium uses a different main thread implementation +#endif + namespace WTF { struct FunctionWithContext { MainThreadFunction* function; void* context; + ThreadCondition* syncFlag; - FunctionWithContext(MainThreadFunction* function = 0, void* context = 0) + FunctionWithContext(MainThreadFunction* function = 0, void* context = 0, ThreadCondition* syncFlag = 0) : function(function) , context(context) + , syncFlag(syncFlag) { } + bool operator == (const FunctionWithContext& o) + { + return function == o.function + && context == o.context + && syncFlag == o.syncFlag; + } +}; + +class FunctionWithContextFinder { +public: + FunctionWithContextFinder(const FunctionWithContext& m) : m(m) {} + bool operator() (FunctionWithContext& o) { return o == m; } + FunctionWithContext m; }; + typedef Deque FunctionQueue; static bool callbacksPaused; // This global variable is only accessed from main thread. +#if !PLATFORM(MAC) && !PLATFORM(QT) +static ThreadIdentifier mainThreadIdentifier; +#endif -Mutex& mainThreadFunctionQueueMutex() +static Mutex& mainThreadFunctionQueueMutex() { DEFINE_STATIC_LOCAL(Mutex, staticMutex, ()); return staticMutex; @@ -63,12 +88,51 @@ static FunctionQueue& functionQueue() return staticFunctionQueue; } + +#if !PLATFORM(MAC) + void initializeMainThread() { + static bool initializedMainThread; + if (initializedMainThread) + return; + initializedMainThread = true; + +#if !PLATFORM(QT) + mainThreadIdentifier = currentThread(); +#endif + mainThreadFunctionQueueMutex(); initializeMainThreadPlatform(); } +#else + +static pthread_once_t initializeMainThreadKeyOnce = PTHREAD_ONCE_INIT; + +static void initializeMainThreadOnce() +{ + mainThreadFunctionQueueMutex(); + initializeMainThreadPlatform(); +} + +void initializeMainThread() +{ + pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadOnce); +} + +static void initializeMainThreadToProcessMainThreadOnce() +{ + mainThreadFunctionQueueMutex(); + initializeMainThreadToProcessMainThreadPlatform(); +} + +void initializeMainThreadToProcessMainThread() +{ + pthread_once(&initializeMainThreadKeyOnce, initializeMainThreadToProcessMainThreadOnce); +} +#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; @@ -87,11 +151,14 @@ void dispatchFunctionsFromMainThread() MutexLocker locker(mainThreadFunctionQueueMutex()); if (!functionQueue().size()) break; - invocation = functionQueue().first(); - functionQueue().removeFirst(); + invocation = functionQueue().takeFirst(); } invocation.function(invocation.context); + if (invocation.syncFlag) { + MutexLocker locker(mainThreadFunctionQueueMutex()); + invocation.syncFlag->signal(); + } // 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. @@ -117,9 +184,45 @@ void callOnMainThread(MainThreadFunction* function, void* context) scheduleDispatchFunctionsOnMainThread(); } +void callOnMainThreadAndWait(MainThreadFunction* function, void* context) +{ + ASSERT(function); + + if (isMainThread()) { + function(context); + return; + } + + ThreadCondition syncFlag; + Mutex& functionQueueMutex = mainThreadFunctionQueueMutex(); + MutexLocker locker(functionQueueMutex); + functionQueue().append(FunctionWithContext(function, context, &syncFlag)); + if (functionQueue().size() == 1) + scheduleDispatchFunctionsOnMainThread(); + syncFlag.wait(functionQueueMutex); +} + +void cancelCallOnMainThread(MainThreadFunction* function, void* context) +{ + ASSERT(function); + + MutexLocker locker(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); + } +} + void setMainThreadCallbacksPaused(bool paused) { - ASSERT(isMainThread()); + ASSERT((isMainThread() || pthread_main_np()) && WebCoreWebThreadIsLockedOrDisabled()); if (callbacksPaused == paused) return; @@ -130,4 +233,11 @@ void setMainThreadCallbacksPaused(bool paused) scheduleDispatchFunctionsOnMainThread(); } +#if !PLATFORM(MAC) && !PLATFORM(QT) && !PLATFORM(BREWMP) +bool isMainThread() +{ + return currentThread() == mainThreadIdentifier; +} +#endif + } // namespace WTF