Arquivos
hhvm/hphp/runtime/ext/asio/blockable_wait_handle.cpp
T
Paul Tarjan fef62f03a2 kill VM namespace
Now that HHVM is the default runtime, this namespace doesn't mean anything.
2013-05-15 13:05:05 -07:00

128 linhas
4.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 <system/lib/systemlib.h>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
c_BlockableWaitHandle::c_BlockableWaitHandle(Class* cb)
: c_WaitableWaitHandle(cb), m_nextParent(nullptr) {
}
c_BlockableWaitHandle::~c_BlockableWaitHandle() {
}
void c_BlockableWaitHandle::t___construct() {
throw NotSupportedException(__func__, "WTF? This is an abstract class");
}
// throws on cycle
void c_BlockableWaitHandle::blockOn(c_WaitableWaitHandle* child) {
setState(STATE_BLOCKED);
assert(getChild() == child);
// detect complete cycles
if (UNLIKELY(hasCycle(child))) {
reportCycle(child);
assert(false);
}
// make sure the child is going to do some work
// throws if cross-context cycle found
if (isInContext()) {
child->enterContext(getContextIdx());
}
// extend the linked list of parents
m_nextParent = child->addParent(this);
// increment ref count so that we won't deallocated before child calls back
incRefCount();
}
c_BlockableWaitHandle* c_BlockableWaitHandle::getNextParent() {
return m_nextParent;
}
c_BlockableWaitHandle* c_BlockableWaitHandle::unblock() {
c_BlockableWaitHandle* next = m_nextParent;
// notify subclass that we are no longer blocked
onUnblocked();
// decrement ref count, we can't be called by child anymore
decRefObj(this);
return next;
}
void c_BlockableWaitHandle::exitContextBlocked(context_idx_t ctx_idx) {
assert(getState() == STATE_BLOCKED);
assert(AsioSession::Get()->getContext(ctx_idx));
// not in a context being exited
assert(getContextIdx() <= ctx_idx);
if (getContextIdx() != ctx_idx) {
return;
}
// move us to the parent context
setContextIdx(getContextIdx() - 1);
// recursively move all wait handles blocked by us
for (auto pwh = getFirstParent(); pwh; pwh = pwh->getNextParent()) {
pwh->exitContextBlocked(ctx_idx);
}
}
// always throws
void c_BlockableWaitHandle::reportCycle(c_WaitableWaitHandle* start) {
assert(getState() == STATE_BLOCKED);
assert(getChild() == start);
smart::vector<std::string> exception_msg_items;
exception_msg_items.push_back("Encountered dependency cycle.\n");
exception_msg_items.push_back("Existing stack:\n");
assert(dynamic_cast<c_BlockableWaitHandle*>(start));
auto current = static_cast<c_BlockableWaitHandle*>(start);
assert(current->getState() == STATE_BLOCKED);
do {
exception_msg_items.push_back(folly::stringPrintf(
" %s (%" PRId64 ")\n", current->getName()->data(), current->t_getid()));
auto next = current->getChild();
assert(dynamic_cast<c_BlockableWaitHandle*>(next));
current = static_cast<c_BlockableWaitHandle*>(next);
assert(current->getState() == STATE_BLOCKED);
} while (current != start);
exception_msg_items.push_back("Trying to introduce dependency on:\n");
exception_msg_items.push_back(folly::stringPrintf(
" %s (%" PRId64 ") (dupe)\n", start->getName()->data(), start->t_getid()));
Object e(SystemLib::AllocInvalidOperationExceptionObject(
folly::join("", exception_msg_items)));
throw e;
}
///////////////////////////////////////////////////////////////////////////////
}