Add support for external thread events

Add support for external thread events.

See asio_external_thread_event.h for details about usage.

This is the first version that compiled, the code was not executed even
once, but wanted to get it out early to unblock @hannesr. Thus the [RFC]
flag.

My next step is to implement asio-compatible equivalent of
fb_call_user_func_async() that will make it possible to easily test the
new functonality by simulating async stuff with sleep(), etc. on the PHP
side.

There are 2 major mostly lockless synchronization points that needs
careful review:

- queue of ready external thread events (asio_session.{cpp.h})
- shutdown cleanup (asio_external_thread_event.{cpp,h})
Esse commit está contido em:
Jan Oravec
2013-04-21 20:38:27 -07:00
commit de Sara Golemon
commit 88687ba6f7
10 arquivos alterados com 696 adições e 7 exclusões
+26
Ver Arquivo
@@ -651,6 +651,32 @@
"desc": "A queue that is run only once there is no pending I\/O operation"
}
]
},
{
"name": "ExternalThreadEventWaitHandle",
"parent": "WaitableWaitHandle",
"desc": "A wait handle that synchronizes against C++ operation in external thread",
"bases": [
"Sweepable"
],
"flags": [
"HasDocComment",
"NoDefaultSweep"
],
"funcs": [
{
"name": "__construct",
"flags": [
"IsPrivate",
"HasDocComment"
],
"return": {
"type": null
},
"args": [
]
}
]
}
]
}
+49 -6
Ver Arquivo
@@ -48,6 +48,12 @@ void AsioContext::exit(context_idx_t ctx_idx) {
for (auto it : m_priorityQueueNoPendingIO) {
exitContextQueue(ctx_idx, it.second);
}
while (!m_externalThreadEvents.empty()) {
auto ete_wh = m_externalThreadEvents.back();
m_externalThreadEvents.pop_back();
ete_wh->exitContext(ctx_idx);
}
}
void AsioContext::schedule(c_ContinuationWaitHandle* wait_handle) {
@@ -68,24 +74,49 @@ void AsioContext::schedule(c_RescheduleWaitHandle* wait_handle, uint32_t queue,
wait_handle->incRefCount();
}
uint32_t AsioContext::registerExternalThreadEvent(c_ExternalThreadEventWaitHandle* wait_handle) {
m_externalThreadEvents.push_back(wait_handle);
return m_externalThreadEvents.size() - 1;
}
void AsioContext::unregisterExternalThreadEvent(uint32_t ete_idx) {
assert(ete_idx < m_externalThreadEvents.size());
if (ete_idx != m_externalThreadEvents.size() - 1) {
m_externalThreadEvents[ete_idx] = m_externalThreadEvents.back();
m_externalThreadEvents[ete_idx]->setIndex(ete_idx);
}
m_externalThreadEvents.pop_back();
}
void AsioContext::runUntil(c_WaitableWaitHandle* wait_handle) {
assert(!m_current);
assert(wait_handle);
assert(wait_handle->getContext() == this);
auto session = AsioSession::Get();
uint8_t check_ete_counter = 0;
while (!wait_handle->isFinished()) {
// run queue of ready continuations
while (!m_runnableQueue.empty()) {
// process ready external thread events once per 256 other events
// (when 8-bit check_ete_counter overflows)
if (!++check_ete_counter) {
auto ete_wh = session->getReadyExternalThreadEvents();
while (ete_wh) {
auto next_wh = ete_wh->getNextToProcess();
ete_wh->process();
ete_wh = next_wh;
}
}
// run queue of ready continuations once
if (!m_runnableQueue.empty()) {
auto current = m_runnableQueue.front();
m_runnableQueue.pop();
m_current = current;
m_current->run();
m_current = nullptr;
decRefObj(current);
if (wait_handle->isFinished()) {
return;
}
continue;
}
// run default priority queue once
@@ -93,6 +124,18 @@ void AsioContext::runUntil(c_WaitableWaitHandle* wait_handle) {
continue;
}
// pending external thread events? wait for at least one to become ready
if (!m_externalThreadEvents.empty()) {
// all your wait time are belong to us
auto ete_wh = session->waitForExternalThreadEvents();
while (ete_wh) {
auto next_wh = ete_wh->getNextToProcess();
ete_wh->process();
ete_wh = next_wh;
}
continue;
}
// run no-pending-io priority queue once
if (runSingle(m_priorityQueueNoPendingIO)) {
continue;
+6
Ver Arquivo
@@ -28,6 +28,7 @@ namespace HPHP {
FORWARD_DECLARE_CLASS_BUILTIN(WaitableWaitHandle);
FORWARD_DECLARE_CLASS_BUILTIN(ContinuationWaitHandle);
FORWARD_DECLARE_CLASS_BUILTIN(RescheduleWaitHandle);
FORWARD_DECLARE_CLASS_BUILTIN(ExternalThreadEventWaitHandle);
typedef uint8_t context_idx_t;
@@ -44,6 +45,8 @@ class AsioContext {
void schedule(c_ContinuationWaitHandle* wait_handle);
void schedule(c_RescheduleWaitHandle* wait_handle, uint32_t queue, uint32_t priority);
uint32_t registerExternalThreadEvent(c_ExternalThreadEventWaitHandle* wait_handle);
void unregisterExternalThreadEvent(uint32_t ete_idx);
void runUntil(c_WaitableWaitHandle* wait_handle);
static const uint32_t QUEUE_DEFAULT = 0;
@@ -65,6 +68,9 @@ class AsioContext {
// queue of RescheduleWaitHandles scheduled to be run once there is no pending I/O
reschedule_priority_queue_t m_priorityQueueNoPendingIO;
// list of all pending ExternalThreadEventWaitHandles
smart::vector<c_ExternalThreadEventWaitHandle*> m_externalThreadEvents;
};
///////////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,61 @@
/*
+----------------------------------------------------------------------+
| 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 <thread>
#include <runtime/ext/ext_asio.h>
#include <runtime/ext/asio/asio_external_thread_event.h>
#include <runtime/ext/asio/asio_session.h>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
AsioExternalThreadEvent::AsioExternalThreadEvent()
: m_session(AsioSession::Get()),
m_state(Waiting) {
m_waitHandle = c_ExternalThreadEventWaitHandle::Create(this);
}
void AsioExternalThreadEvent::abandon() {
assert(m_state.load() == Waiting);
assert(m_waitHandle->getCount() == 1);
m_waitHandle->abandon(false);
}
bool AsioExternalThreadEvent::cancel() {
uint32_t/*state_t*/ expected(Waiting);
if (m_state.compare_exchange_strong(expected, Canceled)) {
return true;
}
assert(expected == Finished);
return false;
}
void AsioExternalThreadEvent::markAsFinished() {
uint32_t/*state_t*/ expected(Waiting);
if (m_state.compare_exchange_strong(expected, Finished)) {
// transfer ownership
m_session->enqueueExternalThreadEvent(m_waitHandle);
} else {
// web request died, destroy object
assert(expected == Canceled);
release();
}
}
///////////////////////////////////////////////////////////////////////////////
}
@@ -0,0 +1,260 @@
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
*/
#ifndef incl_EXT_ASIO_EXTERNAL_THREAD_EVENT_H_
#define incl_EXT_ASIO_EXTERNAL_THREAD_EVENT_H_
#include <atomic>
#include <runtime/base/base_includes.h>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
class AsioSession;
FORWARD_DECLARE_CLASS_BUILTIN(ExternalThreadEventWaitHandle);
/**
* An asynchronous external thread event.
*
* A root class of all classes of objects representing events external to
* the web request thread that synchronizes on them using ASIO framework.
*
* This is the preferred mechanism of I/O integration with ASIO framework.
*
* To implement a new class of such events, define a subclass that stores
* information needed to unserialize result and provides a memory for storing
* raw result. Then define a method that populates the result and marks
* the event as finished, override unserialize method that will produce
* result in the format understood by HHVM and implement destructor that
* will clean up the stored data.
*
* Example:
*
* class FooEvent : public AsioExternalThreadEvent {
* public:
* FooEvent(int max_value) : m_maxValue(max_value), m_failed(false) {}
* ~FooEvent() {}
* void setResult(int value) {
* m_value = value;
* markAsFinished();
* }
* void setException(const FooException& exception) {
* m_failed = true;
* markAsFinished();
* }
* protected:
* void unserialize(TypedValue* result) const {
* if (UNLIKELY(m_failed)) {
* Object e(SystemLib::AllocInvalidOperationExceptionObject(
* "An error has occurred while scheduling the operation"));
* throw e;
* }
*
* if (UNLIKELY(m_value > m_maxValue)) {
* Object e(SystemLib::AllocInvalidOperationExceptionObject(
* "Invalid response returned by Foo backend"));
* throw e;
* }
*
* result->m_type = KindOfInt64;
* result->m_data.num = m_value;
* }
* private:
* int m_value, m_maxValue;
* bool m_failed;
* };
*
* To use this mechanism from your extension, create an instance of the class,
* schedule an asynchronous operation and return the wait handle to the caller.
*
* Example:
*
* Object f_gen_foo(int max_value) {
* // validate user input early
* if (max_value < 0) {
* Object e(SystemLib::AllocInvalidArgumentExceptionObject(
* "Expected max_value to be non-negative"));
* throw e;
* }
*
* FooEvent* event = new FooEvent(max_value);
* try {
* // make foo run asynchronously and eventually call event->setResult()
* foo_async_schedule(event);
* } catch (const FooException& exception) {
* // handle error while trying to schedule requested operation
* event->setException(exception);
* } catch (...) {
* // unknown exception; should be never reached
* assert(false);
* event->abandon();
* Object e(SystemLib::AllocInvalidOperationExceptionObject(
* "Encountered unexpected exception"));
* throw e;
* }
* return event->getWaitHandle();
* }
*
* Caveats:
* - web request may die before the event is finished; never store pointers
* to any data owned by PHP as the PHP thread may die at any time
*/
class AsioExternalThreadEvent {
public:
/**
* Get wait handle representing this external thread event.
*
* This function may be called only from the web request thread between
* construction of this object and return of the control back to the VM.
* Do not try to call this after any PHP code got executed; the asynchronous
* operation may have finished and this object could have been already
* destroyed.
*
* The caller is responsible for obtaining a reference count immediately
* after obtaining the pointer (e.g. by type casting this into Object,
* populating a TypedValue using tvWriteObject, or setting an array
* element). If any PHP code is executed, a bad things may happen.
*
* It is okay to call this after asynchronous operation was scheduled.
* Even if the operation has finished, the object is not destroyed until
* ASIO main loop is executed.
*/
c_ExternalThreadEventWaitHandle* getWaitHandle() {
return m_waitHandle;
}
/**
* Abandon this external thread event.
*
* Abandons this event and frees all associated resources before any action
* is taken. Useful if a caller changed its mind after this event was
* constructed (e.g. due to failed transfer of ownership to the processing
* thread).
*
* This function may be called only from the web request thread between
* construction of this object and return of the control back to the VM,
* assuming that no other methods of this object were called prior to this
* call (except for constructor). Once this function is called, all
* associated resources are reclaimed and it is illegal to perform any
* further operation on this object.
*/
void abandon();
/**
* Cancel waiting for the event. INTERNAL USE ONLY. DO NOT CALL.
*
* Returns true iff we transitioned from Waiting to Canceled; otherwise,
* this function waits until processing thread completed its transition
* to the Finished state.
*
* This function is called internally from the web request thread to signal
* that the result will not be retrieved by the web request thread.
*
* This is used in rare case when the web request thread is dying without
* waiting for the asynchronous operation to finish.
*/
bool cancel();
/**
* Destroy the object. INTERNAL USE ONLY. DO NOT CALL.
*
* The purpose of this function is to make destructor protected so that
* this object is not accidentally used in conjunction with shared pointers.
*/
void release() { delete this; }
/**
* Unserialize result. Implemented by subclasses.
*
* Unserializes result and writes it to the provided uninitialized
* TypedValue variable.
*
* This function is optionally called internally from the web request thread
* to retrieve result of the operation after markAsFinished() was called
* to signal the result is ready.
*
* A failed operation may be signaled by throwing a PHP exception instead
* of populating result variable. Result variable will be ignored.
* If a result was already initialized, it must be uninitialized (decref
* if needed) prior to throwing an exception.
*/
virtual void unserialize(TypedValue* result) const = 0;
protected:
AsioExternalThreadEvent();
/**
* Destruct AsioExternalThreadEvent
*
* Object lifetime and ownership is managed internally. Do not try to
* destruct this object yourself. Instead, make sure markAsFinished()
* is eventually called.
*/
virtual ~AsioExternalThreadEvent() {
assert(m_state.load() == Finished || m_state.load() == Canceled);
};
/**
* Mark the event as finished.
*
* Marks event as finished and transfers ownership of this object to
* the web request thread.
*
* This function may be called only from the processing thread to signal
* that the result is ready to be unserialized. Once this function is
* called, unserialize() function or object destructor may be called
* at any time and the processing thread should not do any further
* operations on this object.
*/
void markAsFinished();
private:
enum state_t : uint32_t {
/**
* Web request thread waiting for processing thread to finish.
*
* This object is owned by processing thread, which is responsible for
* eventually calling markAsFinished().
*/
Waiting,
/**
* Web request thread scheduled to unserialize result.
*
* This object is owned by web request thread, which is responsible for
* destruction of this object after optional unserialization.
*/
Finished,
/**
* Web request thread died before processing thread finished.
*
* This object is owned by processing thread, which is responsible for
* eventually calling markAsFinished() that will destruct this object.
*/
Canceled,
};
AsioSession* m_session;
c_ExternalThreadEventWaitHandle* m_waitHandle;
std::atomic<uint32_t/*state_t*/> m_state;
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_EXT_ASIO_EXTERNAL_THREAD_EVENT_H_
+51 -1
Ver Arquivo
@@ -33,7 +33,10 @@ void AsioSession::Init() {
}
AsioSession::AsioSession()
: m_contexts(), m_onFailedCallback(nullptr), m_onStartedCallback(nullptr) {
: m_contexts(), m_readyExternalThreadEvents(nullptr),
m_readyExternalThreadEventsMutex(),
m_readyExternalThreadEventsCondition(),
m_onFailedCallback(nullptr), m_onStartedCallback(nullptr) {
}
void AsioSession::enterContext() {
@@ -68,6 +71,53 @@ uint16_t AsioSession::getCurrentWaitHandleDepth() {
return isInContext() ? getCurrentWaitHandle()->getDepth() : 0;
}
c_ExternalThreadEventWaitHandle* AsioSession::waitForExternalThreadEvents() {
// try check for ready external thread events without grabbing lock
auto ready = m_readyExternalThreadEvents.exchange(nullptr);
if (ready != nullptr) {
assert(ready != k_waitingForExternalThreadEvents);
return ready;
}
// no ready external thread events available, synchronization needed
std::unique_lock<std::mutex> lock(m_readyExternalThreadEventsMutex);
// transition from empty to WAITING
if (m_readyExternalThreadEvents.compare_exchange_strong(ready, k_waitingForExternalThreadEvents)) {
// wait for transition from WAITING to non-empty
do {
m_readyExternalThreadEventsCondition.wait(lock);
} while (m_readyExternalThreadEvents.load() == k_waitingForExternalThreadEvents);
} else {
// external thread transitioned from empty to non-empty while grabbing lock
}
ready = m_readyExternalThreadEvents.exchange(nullptr);
assert(ready != nullptr);
assert(ready != k_waitingForExternalThreadEvents);
return ready;
}
void AsioSession::enqueueExternalThreadEvent(c_ExternalThreadEventWaitHandle* wait_handle) {
auto next = m_readyExternalThreadEvents.load();
while (true) {
while (next != k_waitingForExternalThreadEvents) {
wait_handle->setNextToProcess(next);
if (m_readyExternalThreadEvents.compare_exchange_weak(next, wait_handle)) {
return;
}
}
// try to transition from WAITING to non-empty
wait_handle->setNextToProcess(nullptr);
if (m_readyExternalThreadEvents.compare_exchange_weak(next, wait_handle)) {
// succeeded, notify condition
m_readyExternalThreadEventsCondition.notify_one();
return;
}
}
}
void AsioSession::setOnFailedCallback(ObjectData* on_failed_callback) {
if (on_failed_callback) {
on_failed_callback->incRefCount();
+21
Ver Arquivo
@@ -18,6 +18,9 @@
#ifndef incl_HPHP_EXT_ASIO_SESSION_H_
#define incl_HPHP_EXT_ASIO_SESSION_H_
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <runtime/base/base_includes.h>
#include <runtime/ext/asio/asio_context.h>
@@ -25,6 +28,7 @@ namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
FORWARD_DECLARE_CLASS_BUILTIN(ContinuationWaitHandle);
FORWARD_DECLARE_CLASS_BUILTIN(ExternalThreadEventWaitHandle);
class AsioSession {
public:
@@ -64,6 +68,16 @@ class AsioSession {
uint16_t getCurrentWaitHandleDepth();
// external thread event
c_ExternalThreadEventWaitHandle* getReadyExternalThreadEvents() {
auto ready = m_readyExternalThreadEvents.exchange(nullptr);
assert(ready != k_waitingForExternalThreadEvents);
return ready;
}
c_ExternalThreadEventWaitHandle* waitForExternalThreadEvents();
void enqueueExternalThreadEvent(c_ExternalThreadEventWaitHandle* wait_handle);
// callback: on failed
void setOnFailedCallback(ObjectData* on_failed_callback);
void onFailed(CObjRef exception);
@@ -76,9 +90,16 @@ class AsioSession {
private:
static DECLARE_THREAD_LOCAL_PROXY(AsioSession, false, s_current);
static constexpr c_ExternalThreadEventWaitHandle* k_waitingForExternalThreadEvents = static_cast<c_ExternalThreadEventWaitHandle*>((void*)1L);
AsioSession();
smart::vector<AsioContext*> m_contexts;
std::atomic<c_ExternalThreadEventWaitHandle*> m_readyExternalThreadEvents;
std::mutex m_readyExternalThreadEventsMutex;
std::condition_variable m_readyExternalThreadEventsCondition;
ObjectData* m_onFailedCallback;
ObjectData* m_onStartedCallback;
};
@@ -0,0 +1,168 @@
/*
+----------------------------------------------------------------------+
| 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_external_thread_event.h>
#include <runtime/ext/asio/asio_session.h>
#include <system/lib/systemlib.h>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
namespace {
StaticString s_externalThreadEvent("<external-thread-event>");
}
c_ExternalThreadEventWaitHandle::c_ExternalThreadEventWaitHandle(VM::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 session = AsioSession::Get();
bool done = false;
do {
auto ete_wh = session->waitForExternalThreadEvents();
while (ete_wh) {
done |= ete_wh == this;
auto next_wh = ete_wh->getNextToProcess();
ete_wh->abandon(true);
ete_wh = next_wh;
}
} while (!done);
}
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) {
c_ExternalThreadEventWaitHandle* wh = NEWOBJ(c_ExternalThreadEventWaitHandle);
wh->initialize(event);
return wh;
}
void c_ExternalThreadEventWaitHandle::initialize(AsioExternalThreadEvent* event) {
// this wait handle is owned by existence of unprocessed event
incRefCount();
m_event = event;
setState(STATE_WAITING);
if (isInContext()) {
m_index = getContext()->registerExternalThreadEvent(this);
}
}
void c_ExternalThreadEventWaitHandle::abandon(bool sweeping) {
assert(getState() == STATE_WAITING);
assert(getCount() == 1 || sweeping);
if (isInContext()) {
getContext()->unregisterExternalThreadEvent(m_index);
}
// event is abandoned, destroy it, unregister sweepable and decref ownership
m_event->release();
m_event = nullptr;
unregister();
decRefObj(this);
}
void c_ExternalThreadEventWaitHandle::process() {
assert(getState() == STATE_WAITING);
if (isInContext()) {
getContext()->unregisterExternalThreadEvent(m_index);
}
try {
TypedValue result;
m_event->unserialize(&result);
assert(tvIsPlausible(&result));
setResult(&result);
tvRefcountedDecRefCell(&result);
} catch (const Object& exception) {
setException(exception.get());
}
// event is processed, destroy it, unregister sweepable and decref ownership
m_event->release();
m_event = nullptr;
unregister();
decRefObj(this);
}
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);
}
}
///////////////////////////////////////////////////////////////////////////////
}
+42
Ver Arquivo
@@ -433,6 +433,48 @@ class c_RescheduleWaitHandle : public c_WaitableWaitHandle {
static const int8_t STATE_SCHEDULED = 3;
};
///////////////////////////////////////////////////////////////////////////////
// class ExternalThreadEventWaitHandle
/**
* A wait handle that synchronizes against C++ operation in external thread.
*
* See asio_external_thread_event.h for more details.
*/
class AsioExternalThreadEvent;
FORWARD_DECLARE_CLASS_BUILTIN(ExternalThreadEventWaitHandle);
class c_ExternalThreadEventWaitHandle : public c_WaitableWaitHandle, public Sweepable {
public:
DECLARE_CLASS(ExternalThreadEventWaitHandle, ExternalThreadEventWaitHandle, WaitableWaitHandle)
// need to implement
public: c_ExternalThreadEventWaitHandle(VM::Class* cls = c_ExternalThreadEventWaitHandle::s_cls);
public: ~c_ExternalThreadEventWaitHandle();
public: void t___construct();
public:
static c_ExternalThreadEventWaitHandle* Create(AsioExternalThreadEvent* event);
c_ExternalThreadEventWaitHandle* getNextToProcess() { assert(getState() == STATE_WAITING); return m_nextToProcess; }
void setNextToProcess(c_ExternalThreadEventWaitHandle* next) { assert(getState() == STATE_WAITING); m_nextToProcess = next; }
void setIndex(uint32_t ete_idx) { assert(getState() == STATE_WAITING); m_index = ete_idx; }
void abandon(bool sweeping);
void process();
String getName();
void enterContext(context_idx_t ctx_idx);
void exitContext(context_idx_t ctx_idx);
private:
void initialize(AsioExternalThreadEvent* event);
c_ExternalThreadEventWaitHandle* m_nextToProcess;
AsioExternalThreadEvent* m_event;
uint32_t m_index;
static const uint8_t STATE_WAITING = 3;
};
///////////////////////////////////////////////////////////////////////////////
}
+12
Ver Arquivo
@@ -24931,6 +24931,18 @@ const char *g_class_map[] = {
"QUEUE_NO_PENDING_IO", (const char*)&q_RescheduleWaitHandle$$QUEUE_NO_PENDING_IO, (const char *)0xc /* KindOfInt64 */,
NULL,
NULL,
(const char *)0x18006000, "ExternalThreadEventWaitHandle", "waitablewaithandle", "", (const char *)0, (const char *)0,
"/**\n * ( excerpt from\n * http://php.net/manual/en/class.externalthreadeventwaithandle.php )\n *\n * A wait handle that synchronizes against C++ operation in external\n * thread\n *\n */",
NULL,
(const char *)0x10006100, "__construct", "", (const char*)0, (const char*)0,
"/**\n * ( excerpt from\n * http://php.net/manual/en/externalthreadeventwaithandle.construct.php )\n *\n *\n */",
(const char *)0x8 /* KindOfNull */, NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
(const char *)0x10006000, "UConverter", "", "", (const char *)0, (const char *)0,
"/**\n * ( excerpt from http://php.net/manual/en/class.uconverter.php )\n *\n * ICU UConverter class\n *\n */",
NULL,