2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 #ifndef incl_HPHP_EXT_ASIO_WAIT_HANDLE_H_
19 #define incl_HPHP_EXT_ASIO_WAIT_HANDLE_H_
21 #include "hphp/runtime/ext/extension.h"
22 #include "hphp/runtime/ext/asio/asio-blockable.h"
25 ///////////////////////////////////////////////////////////////////////////////
28 void HHVM_STATIC_METHOD(WaitHandle
, setOnIoWaitEnterCallback
,
29 const Variant
& callback
);
30 void HHVM_STATIC_METHOD(WaitHandle
, setOnIoWaitExitCallback
,
31 const Variant
& callback
);
32 void HHVM_STATIC_METHOD(WaitHandle
, setOnJoinCallback
,
33 const Variant
& callback
);
34 bool HHVM_METHOD(WaitHandle
, isFinished
);
35 bool HHVM_METHOD(WaitHandle
, isSucceeded
);
36 bool HHVM_METHOD(WaitHandle
, isFailed
);
37 String
HHVM_METHOD(WaitHandle
, getName
);
40 * A wait handle is an object that describes operation that is potentially
41 * asynchronous. A WaitHandle class is a base class of all such objects. There
42 * are multiple types of wait handles, this is their hierarchy:
44 * WaitHandle - abstract wait handle
45 * StaticWaitHandle - statically finished wait handle
46 * WaitableWaitHandle - wait handle that can be waited for
47 * ResumableWaitHandle - wait handle that can resume PHP execution
48 * AsyncFunctionWaitHandle - async function-based async execution
49 * AsyncGeneratorWaitHandle - async generator-based async execution
50 * AwaitAllWaitHandle - wait handle representing a collection of
51 * WHs, does not propagate results
52 * ConditionWaitHandle - wait handle implementing condition variable
53 * RescheduleWaitHandle - wait handle that reschedules execution
54 * SleepWaitHandle - wait handle that finishes after a timeout
55 * ExternalThreadEventWaitHandle - thread-powered asynchronous execution
57 * A wait handle can be either synchronously joined (waited for the operation
58 * to finish) or passed in various contexts as a dependency and waited for
59 * asynchronously (such as using await mechanism of async function or
60 * passed to AwaitAllWaitHandle).
63 struct c_AsyncFunctionWaitHandle
;
64 struct c_AsyncGeneratorWaitHandle
;
65 struct c_AwaitAllWaitHandle
;
66 struct c_ConditionWaitHandle
;
67 struct c_RescheduleWaitHandle
;
68 struct c_SleepWaitHandle
;
69 struct c_ExternalThreadEventWaitHandle
;
71 #define WAITHANDLE_CLASSOF(cn) \
72 static Class* classof() { \
73 static Class* cls = Unit::lookupClass(makeStaticString("HH\\" #cn)); \
77 #define WAITHANDLE_DTOR(cn) \
78 static void instanceDtor(ObjectData* obj, const Class*) { \
79 auto wh = wait_handle<c_##cn>(obj); \
81 MM().objFree(obj, sizeof(c_##cn)); \
85 T
* wait_handle(const ObjectData
* obj
) {
86 assert(obj
->instanceof(T::classof()));
87 assert(obj
->getAttribute(ObjectData::IsWaitHandle
));
88 return static_cast<T
*>(const_cast<ObjectData
*>(obj
));
91 struct c_WaitHandle
: ObjectData
{
92 WAITHANDLE_CLASSOF(WaitHandle
);
93 WAITHANDLE_DTOR(WaitHandle
);
95 enum class Kind
: uint8_t {
106 explicit c_WaitHandle(Class
* cls
, HeaderKind kind
,
107 type_scan::Index tyindex
) noexcept
108 : ObjectData(cls
, NoInit
{},
109 ObjectData::IsWaitHandle
| ObjectData::NoDestructor
,
113 assert(type_scan::isKnownType(tyindex
));
120 static constexpr ptrdiff_t stateOff() {
121 return offsetof(c_WaitHandle
, m_kind_state
);
123 static constexpr ptrdiff_t resultOff() {
124 return offsetof(c_WaitHandle
, m_resultOrException
);
127 static c_WaitHandle
* fromCell(Cell cell
) {
129 cell
.m_type
== KindOfObject
&&
130 cell
.m_data
.pobj
->getAttribute(ObjectData::IsWaitHandle
)
131 ) ? static_cast<c_WaitHandle
*>(cell
.m_data
.pobj
) : nullptr;
133 static c_WaitHandle
* fromCellAssert(Cell cell
) {
134 assert(cell
.m_type
== KindOfObject
);
135 assert(cell
.m_data
.pobj
->getAttribute(ObjectData::IsWaitHandle
));
136 return static_cast<c_WaitHandle
*>(cell
.m_data
.pobj
);
138 bool isFinished() const { return getState() <= STATE_FAILED
; }
139 bool isSucceeded() const { return getState() == STATE_SUCCEEDED
; }
140 bool isFailed() const { return getState() == STATE_FAILED
; }
141 Cell
getResult() const {
142 assert(isSucceeded());
143 return m_resultOrException
;
145 ObjectData
* getException() const {
147 return m_resultOrException
.m_data
.pobj
;
150 Kind
getKind() const { return static_cast<Kind
>(m_kind_state
>> 4); }
151 uint8_t getState() const { return m_kind_state
& 0x0F; }
152 static uint8_t toKindState(Kind kind
, uint8_t state
) {
153 assert((uint8_t)kind
< 0x10 && state
< 0x10);
154 return ((uint8_t)kind
<< 4) | state
;
156 void setKindState(Kind kind
, uint8_t state
) {
157 m_kind_state
= toKindState(kind
, state
);
159 void setContextVectorIndex(uint32_t idx
) {
163 c_AsyncFunctionWaitHandle
* asAsyncFunction();
164 c_AsyncGeneratorWaitHandle
* asAsyncGenerator();
165 c_AwaitAllWaitHandle
* asAwaitAll();
166 c_ConditionWaitHandle
* asCondition();
167 c_RescheduleWaitHandle
* asReschedule();
168 c_ResumableWaitHandle
* asResumable();
169 c_SleepWaitHandle
* asSleep();
170 c_ExternalThreadEventWaitHandle
* asExternalThreadEvent();
172 // The code in the TC will depend on the values of these constants.
174 static const int8_t STATE_SUCCEEDED
= 0; // completed with result
175 static const int8_t STATE_FAILED
= 1; // completed with exception
177 void scan(type_scan::Scanner
&) const;
179 private: // layout, ignoring ObjectData fields.
181 // [parentChain ][contextIdx][kind_state][tyindex][ctxVecIndex]
182 // [resultOrException.m_data][m_type] [aux]
183 static void checkLayout() {
184 constexpr auto data
= offsetof(c_WaitHandle
, m_resultOrException
);
185 constexpr auto type
= data
+ offsetof(TypedValue
, m_type
);
186 constexpr auto aux
= data
+ offsetof(TypedValue
, m_aux
);
187 static_assert(offsetof(c_WaitHandle
, m_parentChain
) == data
, "");
188 static_assert(offsetof(c_WaitHandle
, m_contextIdx
) == type
, "");
189 static_assert(offsetof(c_WaitHandle
, m_kind_state
) < aux
, "");
190 static_assert(offsetof(c_WaitHandle
, m_ctxVecIndex
) == aux
, "");
195 // STATE_SUCCEEDED || STATE_FAILED
196 Cell m_resultOrException
;
198 // !STATE_SUCCEEDED && !STATE_FAILED
200 // WaitableWaitHandle: !STATE_SUCCEEDED && !STATE_FAILED
201 AsioBlockableChain m_parentChain
;
203 // WaitableWaitHandle: !STATE_SUCCEEDED && !STATE_FAILED
204 context_idx_t m_contextIdx
;
206 // valid in any WaitHandle state. doesn't overlap Cell fields.
207 uint8_t m_kind_state
;
209 // type index of concrete waithandle for gc-scanning
210 type_scan::Index m_tyindex
;
213 // ExternalThreadEventWaitHandle: STATE_WAITING
214 // SleepWaitHandle: STATE_WAITING
215 uint32_t m_ctxVecIndex
;
222 scanner
.scan(m_resultOrException
);
224 scanner
.scan(m_parentChain
);
229 ///////////////////////////////////////////////////////////////////////////////
232 #endif // incl_HPHP_EXT_ASIO_WAIT_HANDLE_H_