2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
18 #include <runtime/ext/ext_asio.h>
19 #include <runtime/ext/asio/asio_context.h>
20 #include <runtime/ext/asio/asio_session.h>
21 #include <system/lib/systemlib.h>
24 ///////////////////////////////////////////////////////////////////////////////
26 c_WaitableWaitHandle::c_WaitableWaitHandle(VM::Class
* cb
)
28 , m_creator(AsioSession::Get()->getCurrentWaitHandle())
29 , m_firstParent(nullptr) {
31 setContextIdx(AsioSession::Get()->getCurrentContextIdx());
35 m_creator
->incRefCount();
39 c_WaitableWaitHandle::~c_WaitableWaitHandle() {
42 tvRefcountedDecRefCell(&m_resultOrException
);
46 tvDecRefObj(&m_resultOrException
);
57 void c_WaitableWaitHandle::t___construct() {
58 throw NotSupportedException(__func__
, "WTF? This is an abstract class");
61 int c_WaitableWaitHandle::t_getcontextidx() {
62 return getContextIdx();
65 Object
c_WaitableWaitHandle::t_getcreator() {
69 Array
c_WaitableWaitHandle::t_getparents() {
70 // no parent data available if finished
72 return Array::Create();
75 Array result
= Array::Create();
76 c_BlockableWaitHandle
* curr
= m_firstParent
;
80 curr
= curr
->getNextParent();
86 c_BlockableWaitHandle
* c_WaitableWaitHandle::addParent(c_BlockableWaitHandle
* parent
) {
87 c_BlockableWaitHandle
* prev
= m_firstParent
;
88 m_firstParent
= parent
;
92 void c_WaitableWaitHandle::setResult(const TypedValue
* result
) {
94 assert(result
->m_type
!= KindOfRef
);
96 setState(STATE_SUCCEEDED
);
97 tvDupCell(result
, &m_resultOrException
);
101 decRefObj(m_creator
);
106 while (m_firstParent
) {
107 m_firstParent
= m_firstParent
->unblock();
111 void c_WaitableWaitHandle::setException(ObjectData
* exception
) {
113 assert(exception
->instanceof(SystemLib::s_ExceptionClass
));
115 setState(STATE_FAILED
);
116 tvWriteObject(exception
, &m_resultOrException
);
120 decRefObj(m_creator
);
125 while (m_firstParent
) {
126 m_firstParent
= m_firstParent
->unblock();
130 // throws on context depth level overflows and cross-context cycles
131 void c_WaitableWaitHandle::join() {
132 AsioSession
* session
= AsioSession::Get();
134 assert(!isFinished());
135 assert(!session
->isInContext() || session
->getCurrentContext()->isRunning());
137 if (UNLIKELY(session
->hasOnJoinCallback())) {
138 session
->onJoin(this);
141 // enter new asio context and set up guard that will exit once we are done
142 session
->enterContext();
144 assert(session
->isInContext());
145 assert(!session
->getCurrentContext()->isRunning());
148 // import this wait handle to the newly created context
149 // throws if cross-context cycle found
150 enterContext(session
->getCurrentContextIdx());
152 // run queues until we are finished
153 session
->getCurrentContext()->runUntil(this);
154 } catch (const Object
& exception
) {
155 // recover from PHP exceptions; HPHP internal exceptions are deliberately
156 // ignored as there is no easy way to recover from them
157 session
->exitContext();
160 session
->exitContext();
162 assert(isFinished());
165 c_WaitableWaitHandle
* c_WaitableWaitHandle::getChild() {
166 assert(!isFinished());
168 // waitable wait handle does not have any child
172 bool c_WaitableWaitHandle::hasCycle(c_WaitableWaitHandle
* start
) {
175 while (start
!= this && start
&& !start
->isFinished()) {
176 start
= start
->getChild();
179 return start
== this;
182 ///////////////////////////////////////////////////////////////////////////////