Arquivos
hhvm/hphp/runtime/ext/asio/gen_array_wait_handle.cpp
T
jan 4a2dc584f8 GenArrayWaitHandle: verify input array in advance
Verify sanity of input array of dependencies in advance. Callers get the
error earlier and it also makes it easier to work with the array outside
of the main loop.
2013-03-27 17:39:19 -07:00

201 linhas
6.2 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 1997-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include <runtime/ext/ext_asio.h>
#include <runtime/ext/asio/asio_context.h>
#include <runtime/ext/asio/asio_session.h>
#include <system/lib/systemlib.h>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
namespace {
StaticString s_genArray("<gen-array>");
void putException(Object& exception_field, ObjectData* new_exception) {
assert(new_exception);
assert(new_exception->instanceof(SystemLib::s_ExceptionClass));
if (exception_field.isNull()) {
exception_field = new_exception;
}
}
}
c_GenArrayWaitHandle::c_GenArrayWaitHandle(VM::Class* cb)
: c_BlockableWaitHandle(cb), m_exception() {
}
c_GenArrayWaitHandle::~c_GenArrayWaitHandle() {
}
void c_GenArrayWaitHandle::t___construct() {
Object e(SystemLib::AllocInvalidOperationExceptionObject(
"Use GenArrayWaitHandle::create() instead of constructor"));
throw e;
}
Object c_GenArrayWaitHandle::ti_create(const char* cls, CArrRef dependencies) {
Array deps = dependencies->copy();
for (ssize_t iter_pos = deps->iter_begin();
iter_pos != ArrayData::invalid_index;
iter_pos = deps->iter_advance(iter_pos)) {
TypedValue* current = deps->nvGetValueRef(iter_pos);
if (UNLIKELY(current->m_type == KindOfRef)) {
tvUnbox(current);
}
if (!c_WaitHandle::fromTypedValue(current) &&
!IS_NULL_TYPE(current->m_type)) {
Object e(SystemLib::AllocInvalidArgumentExceptionObject(
"Expected dependencies to be an array of WaitHandle instances"));
throw e;
}
}
Object exception;
for (ssize_t iter_pos = deps->iter_begin();
iter_pos != ArrayData::invalid_index;
iter_pos = deps->iter_advance(iter_pos)) {
TypedValue* current = deps->nvGetValueRef(iter_pos);
if (IS_NULL_TYPE(current->m_type)) {
// {uninit,null} yields null
tvWriteNull(current);
continue;
}
assert(current->m_type == KindOfObject);
assert(dynamic_cast<c_WaitHandle*>(current->m_data.pobj));
auto child = static_cast<c_WaitHandle*>(current->m_data.pobj);
if (child->isSucceeded()) {
tvSetIgnoreRef(child->getResult(), current);
} else if (child->isFailed()) {
putException(exception, child->getException());
} else {
assert(dynamic_cast<c_WaitableWaitHandle*>(child));
auto child_wh = static_cast<c_WaitableWaitHandle*>(child);
c_GenArrayWaitHandle* my_wh = NEWOBJ(c_GenArrayWaitHandle)();
my_wh->initialize(exception, deps, iter_pos, child_wh);
return my_wh;
}
}
if (exception.isNull()) {
return c_StaticResultWaitHandle::t_create(deps);
} else {
return c_StaticExceptionWaitHandle::t_create(exception);
}
}
void c_GenArrayWaitHandle::initialize(CObjRef exception, CArrRef deps, ssize_t iter_pos, c_WaitableWaitHandle* child) {
m_exception = exception;
m_deps = deps;
m_iterPos = iter_pos;
try {
blockOn(child);
} catch (Object cycle_exception) {
putException(m_exception, cycle_exception.get());
m_iterPos = m_deps->iter_advance(m_iterPos);
onUnblocked();
}
}
void c_GenArrayWaitHandle::onUnblocked() {
for (;
m_iterPos != ArrayData::invalid_index;
m_iterPos = m_deps->iter_advance(m_iterPos)) {
TypedValue* current = m_deps->nvGetValueRef(m_iterPos);
if (IS_NULL_TYPE(current->m_type)) {
// {uninit,null} yields null
tvWriteNull(current);
continue;
}
assert(current->m_type == KindOfObject);
assert(dynamic_cast<c_WaitHandle*>(current->m_data.pobj));
auto child = static_cast<c_WaitHandle*>(current->m_data.pobj);
if (child->isSucceeded()) {
tvSetIgnoreRef(child->getResult(), current);
} else if (child->isFailed()) {
putException(m_exception, child->getException());
} else {
assert(dynamic_cast<c_WaitableWaitHandle*>(child));
auto child_wh = static_cast<c_WaitableWaitHandle*>(child);
try {
blockOn(child_wh);
return;
} catch (Object cycle_exception) {
putException(m_exception, cycle_exception.get());
}
}
}
if (m_exception.isNull()) {
TypedValue result;
result.m_type = KindOfArray;
result.m_data.parr = m_deps.get();
setResult(&result);
m_deps = nullptr;
} else {
setException(m_exception.get());
m_exception = nullptr;
m_deps = nullptr;
}
}
String c_GenArrayWaitHandle::getName() {
return s_genArray;
}
c_WaitableWaitHandle* c_GenArrayWaitHandle::getChild() {
assert(getState() == STATE_BLOCKED);
return static_cast<c_WaitableWaitHandle*>(
m_deps->nvGetValueRef(m_iterPos)->m_data.pobj);
}
void c_GenArrayWaitHandle::enterContext(context_idx_t ctx_idx) {
assert(AsioSession::Get()->getContext(ctx_idx));
// stop before corrupting unioned data
if (isFinished()) {
return;
}
// already in the more specific context?
if (LIKELY(getContextIdx() >= ctx_idx)) {
return;
}
assert(getState() == STATE_BLOCKED);
// TODO: enterContext() for all remaining dependencies
c_WaitableWaitHandle* wait_handle = static_cast<c_WaitableWaitHandle*>(
m_deps->nvGetValueRef(m_iterPos)->m_data.pobj);
wait_handle->enterContext(ctx_idx);
setContextIdx(ctx_idx);
}
///////////////////////////////////////////////////////////////////////////////
}