WebCoreThreadRun.cpp [plain text]
#include "config.h"
#include "WebCoreThreadRun.h"
#if PLATFORM(IOS)
#include "WebCoreThread.h"
#include "WebCoreThreadInternal.h"
#include <condition_variable>
#include <wtf/Vector.h>
namespace {
class WebThreadBlockState {
public:
WebThreadBlockState()
: m_completed(false)
{
}
void waitForCompletion()
{
std::unique_lock<std::mutex> lock(m_stateMutex);
m_completionConditionVariable.wait(lock, [this] { return m_completed; });
}
void setCompleted()
{
std::lock_guard<std::mutex> lock(m_stateMutex);
ASSERT(!m_completed);
m_completed = true;
m_completionConditionVariable.notify_one();
}
private:
std::mutex m_stateMutex;
std::condition_variable m_completionConditionVariable;
bool m_completed;
};
class WebThreadBlock {
public:
WebThreadBlock(void (^task)(), WebThreadBlockState* state)
: m_task(Block_copy(task))
, m_state(state)
{
}
WebThreadBlock(const WebThreadBlock& other)
: m_task(Block_copy(other.m_task))
, m_state(other.m_state)
{
}
WebThreadBlock& operator=(const WebThreadBlock& other)
{
void (^oldTask)() = m_task;
m_task = Block_copy(other.m_task);
Block_release(oldTask);
m_state = other.m_state;
return *this;
}
~WebThreadBlock()
{
Block_release(m_task);
}
void operator()() const
{
m_task();
if (m_state)
m_state->setCompleted();
}
private:
void (^m_task)();
WebThreadBlockState* m_state;
};
}
extern "C" {
typedef WTF::Vector<WebThreadBlock> WebThreadRunQueue;
static std::mutex* runQueueMutex;
static CFRunLoopSourceRef runSource;
static WebThreadRunQueue* runQueue;
static void HandleRunSource(void *info)
{
UNUSED_PARAM(info);
ASSERT(WebThreadIsCurrent());
ASSERT(runQueueMutex);
ASSERT(runSource);
ASSERT(runQueue);
WebThreadRunQueue queueCopy;
{
std::lock_guard<std::mutex> lock(*runQueueMutex);
queueCopy = *runQueue;
runQueue->clear();
}
for (const auto& block : queueCopy)
block();
}
static void _WebThreadRun(void (^task)(), bool synchronous)
{
if (WebThreadIsCurrent() || !WebThreadIsEnabled()) {
task();
return;
}
ASSERT(runQueueMutex);
ASSERT(runSource);
ASSERT(runQueue);
WebThreadBlockState* state = 0;
if (synchronous)
state = new WebThreadBlockState;
{
std::lock_guard<std::mutex> lock(*runQueueMutex);
runQueue->append(WebThreadBlock(task, state));
}
CFRunLoopSourceSignal(runSource);
CFRunLoopWakeUp(WebThreadRunLoop());
if (synchronous) {
state->waitForCompletion();
delete state;
}
}
void WebThreadRun(void (^task)())
{
_WebThreadRun(task, false);
}
void WebThreadRunSync(void (^task)())
{
_WebThreadRun(task, true);
}
void WebThreadInitRunQueue()
{
ASSERT(!runQueue);
ASSERT(!runQueueMutex);
ASSERT(!runSource);
static dispatch_once_t pred;
dispatch_once(&pred, ^{
runQueue = new WebThreadRunQueue;
CFRunLoopSourceContext runSourceContext = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HandleRunSource};
runSource = CFRunLoopSourceCreate(NULL, -1, &runSourceContext);
CFRunLoopAddSource(WebThreadRunLoop(), runSource, kCFRunLoopDefaultMode);
runQueueMutex = std::make_unique<std::mutex>().release();
});
}
}
#endif // PLATFORM(IOS)