blob: 8ef165718861b70d75a65245d214fe13e3c82f64 [file] [log] [blame]
/*
* Copyright (C) 2010, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "WebCoreThreadRun.h"
#if PLATFORM(IOS_FAMILY)
#include "WebCoreThreadInternal.h"
#include <mutex>
#include <wtf/Condition.h>
#include <wtf/Lock.h>
#include <wtf/Vector.h>
namespace {
class WebThreadBlockState {
public:
WebThreadBlockState()
: m_completed(false)
{
}
void waitForCompletion()
{
std::unique_lock<Lock> lock(m_stateMutex);
m_completionConditionVariable.wait(lock, [this] { return m_completed; });
}
void setCompleted()
{
std::lock_guard<Lock> lock(m_stateMutex);
ASSERT(!m_completed);
m_completed = true;
m_completionConditionVariable.notifyOne();
}
private:
Lock m_stateMutex;
Condition m_completionConditionVariable;
bool m_completed;
};
class WebThreadBlock {
public:
WebThreadBlock(void (^block)(void), WebThreadBlockState* state)
: m_block(Block_copy(block))
, m_state(state)
{
}
WebThreadBlock(const WebThreadBlock& other)
: m_block(Block_copy(other.m_block))
, m_state(other.m_state)
{
}
WebThreadBlock& operator=(const WebThreadBlock& other)
{
void (^oldBlock)() = m_block;
m_block = Block_copy(other.m_block);
Block_release(oldBlock);
m_state = other.m_state;
return *this;
}
~WebThreadBlock()
{
Block_release(m_block);
}
void operator()() const
{
m_block();
if (m_state)
m_state->setCompleted();
}
private:
void (^m_block)(void);
WebThreadBlockState* m_state;
};
}
extern "C" {
typedef WTF::Vector<WebThreadBlock> WebThreadRunQueue;
static Lock runQueueMutex;
static CFRunLoopSourceRef runSource;
static WebThreadRunQueue* runQueue;
static void HandleRunSource(void *info)
{
UNUSED_PARAM(info);
ASSERT(WebThreadIsCurrent());
ASSERT(runSource);
ASSERT(runQueue);
WebThreadRunQueue queueCopy;
{
std::lock_guard<Lock> lock(runQueueMutex);
queueCopy = *runQueue;
runQueue->clear();
}
for (const auto& block : queueCopy)
block();
}
static void _WebThreadRun(void (^block)(void), bool synchronous)
{
if (WebThreadIsCurrent() || !WebThreadIsEnabled()) {
block();
return;
}
ASSERT(runSource);
ASSERT(runQueue);
WebThreadBlockState* state = 0;
if (synchronous)
state = new WebThreadBlockState;
{
std::lock_guard<Lock> lock(runQueueMutex);
runQueue->append(WebThreadBlock(block, state));
}
CFRunLoopSourceSignal(runSource);
CFRunLoopWakeUp(WebThreadRunLoop());
if (synchronous) {
state->waitForCompletion();
delete state;
}
}
void WebThreadRun(void (^block)(void))
{
_WebThreadRun(block, false);
}
void WebThreadInitRunQueue()
{
ASSERT(!runQueue);
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);
});
}
}
#endif // PLATFORM(IOS_FAMILY)