Arquivos
hhvm/hphp/runtime/ext/asio/external_thread_event_wait_handle.cpp
T
Jordan DeLong d709f1c6b1 Make fooIsPlausible functions take args by value
Also, checkTv is redundant now, since I added the refcount
assertions to tvIsPlausible earlier.
2013-07-24 10:32:26 -07:00

178 linhas
5.3 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 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 "hphp/runtime/ext/ext_asio.h"
#include "hphp/runtime/ext/asio/asio_external_thread_event.h"
#include "hphp/runtime/ext/asio/asio_external_thread_event_queue.h"
#include "hphp/runtime/ext/asio/asio_session.h"
#include "hphp/system/systemlib.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
namespace {
StaticString s_externalThreadEvent("<external-thread-event>");
}
c_ExternalThreadEventWaitHandle::c_ExternalThreadEventWaitHandle(Class *cb)
: c_WaitableWaitHandle(cb) {
}
c_ExternalThreadEventWaitHandle::~c_ExternalThreadEventWaitHandle() {
}
void c_ExternalThreadEventWaitHandle::sweep() {
assert(getState() == STATE_WAITING);
if (m_event->cancel()) {
// canceled; the processing thread will take care of cleanup
return;
}
// event has finished, but process() was not called yet
auto queue = AsioSession::Get()->getExternalThreadEventQueue();
bool done = queue->hasReceived() && queue->abandonAllReceived(this);
while (!done) {
queue->receiveSome();
done = queue->abandonAllReceived(this);
}
}
void c_ExternalThreadEventWaitHandle::t___construct() {
Object e(SystemLib::AllocInvalidOperationExceptionObject(
"ExternalThreadEventWaitHandle can be constructed only from extension"));
throw e;
}
c_ExternalThreadEventWaitHandle* c_ExternalThreadEventWaitHandle::Create(AsioExternalThreadEvent* event, ObjectData* priv_data) {
c_ExternalThreadEventWaitHandle* wh = NEWOBJ(c_ExternalThreadEventWaitHandle);
wh->initialize(event, priv_data);
return wh;
}
void c_ExternalThreadEventWaitHandle::initialize(AsioExternalThreadEvent* event, ObjectData* priv_data) {
// this wait handle is owned by existence of unprocessed event
incRefCount();
m_event = event;
m_privData = priv_data;
setState(STATE_WAITING);
if (isInContext()) {
m_index = getContext()->registerExternalThreadEvent(this);
}
}
void c_ExternalThreadEventWaitHandle::destroyEvent() {
// destroy event and its private data
m_event->release();
m_event = nullptr;
m_privData = nullptr;
// unregister from sweep()
unregister();
// drop ownership by pending event (see initialize())
decRefObj(this);
}
void c_ExternalThreadEventWaitHandle::abandon(bool sweeping) {
assert(getState() == STATE_WAITING);
assert(getCount() == 1 || sweeping);
if (isInContext()) {
getContext()->unregisterExternalThreadEvent(m_index);
}
// clean up
destroyEvent();
}
void c_ExternalThreadEventWaitHandle::process() {
assert(getState() == STATE_WAITING);
if (isInContext()) {
getContext()->unregisterExternalThreadEvent(m_index);
}
// clean up once event is processed
auto exit_guard = folly::makeGuard([&] { destroyEvent(); });
Cell result;
try {
m_event->unserialize(result);
} catch (const Object& exception) {
setException(exception.get());
return;
} catch (...) {
setException(AsioSession::Get()->getAbruptInterruptException().get());
throw;
}
assert(cellIsPlausible(result));
setResult(result);
tvRefcountedDecRefCell(&result);
}
String c_ExternalThreadEventWaitHandle::getName() {
return s_externalThreadEvent;
}
void c_ExternalThreadEventWaitHandle::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_WAITING);
if (isInContext()) {
getContext()->unregisterExternalThreadEvent(m_index);
}
setContextIdx(ctx_idx);
m_index = getContext()->registerExternalThreadEvent(this);
}
void c_ExternalThreadEventWaitHandle::exitContext(context_idx_t ctx_idx) {
assert(AsioSession::Get()->getContext(ctx_idx));
assert(getContextIdx() == ctx_idx);
assert(getState() == STATE_WAITING);
// move us to the parent context
setContextIdx(getContextIdx() - 1);
// re-register if still in a context
if (isInContext()) {
getContext()->registerExternalThreadEvent(this);
}
// recursively move all wait handles blocked by us
for (auto pwh = getFirstParent(); pwh; pwh = pwh->getNextParent()) {
pwh->exitContextBlocked(ctx_idx);
}
}
///////////////////////////////////////////////////////////////////////////////
}