1 /*
2 +----------------------------------------------------------------------+
3 | Swoole |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2012-2018 The Swoole Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.0 of the Apache license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.apache.org/licenses/LICENSE-2.0.html |
11 | If you did not receive a copy of the Apache2.0 license and are unable|
12 | to obtain it through the world-wide-web, please send a note to |
13 | license@swoole.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Xinyu Zhu <xyzhu1120@gmail.com> |
16 | Tianfeng Han <rango@swoole.com> |
17 +----------------------------------------------------------------------+
18 */
19
20 #include "php_swoole_cxx.h"
21
22 #include "swoole_coroutine_channel.h"
23
24 using swoole::coroutine::Channel;
25
26 static zend_class_entry *swoole_channel_coro_ce;
27 static zend_object_handlers swoole_channel_coro_handlers;
28
29 struct ChannelObject {
30 Channel *chan;
31 zend_object std;
32 };
33
34 SW_EXTERN_C_BEGIN
35 static PHP_METHOD(swoole_channel_coro, __construct);
36 static PHP_METHOD(swoole_channel_coro, push);
37 static PHP_METHOD(swoole_channel_coro, pop);
38 static PHP_METHOD(swoole_channel_coro, close);
39 static PHP_METHOD(swoole_channel_coro, stats);
40 static PHP_METHOD(swoole_channel_coro, length);
41 static PHP_METHOD(swoole_channel_coro, isEmpty);
42 static PHP_METHOD(swoole_channel_coro, isFull);
43 SW_EXTERN_C_END
44
45 // clang-format off
46 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_construct, 0, 0, 0)
47 ZEND_ARG_INFO(0, size)
48 ZEND_END_ARG_INFO()
49
50 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_push, 0, 0, 1)
51 ZEND_ARG_INFO(0, data)
52 ZEND_ARG_INFO(0, timeout)
53 ZEND_END_ARG_INFO()
54
55 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_channel_coro_pop, 0, 0, 0)
56 ZEND_ARG_INFO(0, timeout)
57 ZEND_END_ARG_INFO()
58
59 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_void, 0, 0, 0)
60 ZEND_END_ARG_INFO()
61
62 static const zend_function_entry swoole_channel_coro_methods[] =
63 {
64 PHP_ME(swoole_channel_coro, __construct, arginfo_swoole_channel_coro_construct, ZEND_ACC_PUBLIC)
65 PHP_ME(swoole_channel_coro, push, arginfo_swoole_channel_coro_push, ZEND_ACC_PUBLIC)
66 PHP_ME(swoole_channel_coro, pop, arginfo_swoole_channel_coro_pop, ZEND_ACC_PUBLIC)
67 PHP_ME(swoole_channel_coro, isEmpty, arginfo_swoole_void, ZEND_ACC_PUBLIC)
68 PHP_ME(swoole_channel_coro, isFull, arginfo_swoole_void, ZEND_ACC_PUBLIC)
69 PHP_ME(swoole_channel_coro, close, arginfo_swoole_void, ZEND_ACC_PUBLIC)
70 PHP_ME(swoole_channel_coro, stats, arginfo_swoole_void, ZEND_ACC_PUBLIC)
71 PHP_ME(swoole_channel_coro, length, arginfo_swoole_void, ZEND_ACC_PUBLIC)
72 PHP_FE_END
73 };
74 // clang-format on
75
php_swoole_channel_coro_fetch_object(zend_object * obj)76 static sw_inline ChannelObject *php_swoole_channel_coro_fetch_object(zend_object *obj) {
77 return (ChannelObject *) ((char *) obj - swoole_channel_coro_handlers.offset);
78 }
79
php_swoole_get_channel(zval * zobject)80 static sw_inline Channel *php_swoole_get_channel(zval *zobject) {
81 Channel *chan = php_swoole_channel_coro_fetch_object(Z_OBJ_P(zobject))->chan;
82 if (UNEXPECTED(!chan)) {
83 php_swoole_fatal_error(E_ERROR, "you must call Channel constructor first");
84 }
85 return chan;
86 }
87
php_swoole_channel_coro_dtor_object(zend_object * object)88 static void php_swoole_channel_coro_dtor_object(zend_object *object) {
89 zend_objects_destroy_object(object);
90
91 ChannelObject *chan_object = php_swoole_channel_coro_fetch_object(object);
92 Channel *chan = chan_object->chan;
93 if (chan) {
94 zval *data;
95 while ((data = (zval *) chan->pop_data())) {
96 sw_zval_free(data);
97 }
98 delete chan;
99 chan_object->chan = nullptr;
100 }
101 }
102
php_swoole_channel_coro_free_object(zend_object * object)103 static void php_swoole_channel_coro_free_object(zend_object *object) {
104 ChannelObject *chan_object = php_swoole_channel_coro_fetch_object(object);
105 Channel *chan = chan_object->chan;
106 if (chan) {
107 delete chan;
108 }
109 zend_object_std_dtor(object);
110 }
111
php_swoole_channel_coro_create_object(zend_class_entry * ce)112 static zend_object *php_swoole_channel_coro_create_object(zend_class_entry *ce) {
113 ChannelObject *chan_object = (ChannelObject *) zend_object_alloc(sizeof(ChannelObject), ce);
114 zend_object_std_init(&chan_object->std, ce);
115 object_properties_init(&chan_object->std, ce);
116 chan_object->std.handlers = &swoole_channel_coro_handlers;
117 return &chan_object->std;
118 }
119
php_swoole_channel_coro_minit(int module_number)120 void php_swoole_channel_coro_minit(int module_number) {
121 SW_INIT_CLASS_ENTRY(
122 swoole_channel_coro, "Swoole\\Coroutine\\Channel", nullptr, "Co\\Channel", swoole_channel_coro_methods);
123 SW_SET_CLASS_NOT_SERIALIZABLE(swoole_channel_coro);
124 SW_SET_CLASS_CLONEABLE(swoole_channel_coro, sw_zend_class_clone_deny);
125 SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_channel_coro, sw_zend_class_unset_property_deny);
126 SW_SET_CLASS_CUSTOM_OBJECT(swoole_channel_coro,
127 php_swoole_channel_coro_create_object,
128 php_swoole_channel_coro_free_object,
129 ChannelObject,
130 std);
131 SW_SET_CLASS_DTOR(swoole_channel_coro, php_swoole_channel_coro_dtor_object);
132 if (SWOOLE_G(use_shortname)) {
133 SW_CLASS_ALIAS("Chan", swoole_channel_coro);
134 }
135
136 zend_declare_property_long(swoole_channel_coro_ce, ZEND_STRL("capacity"), 0, ZEND_ACC_PUBLIC);
137 zend_declare_property_long(swoole_channel_coro_ce, ZEND_STRL("errCode"), 0, ZEND_ACC_PUBLIC);
138
139 SW_REGISTER_LONG_CONSTANT("SWOOLE_CHANNEL_OK", Channel::ERROR_OK);
140 SW_REGISTER_LONG_CONSTANT("SWOOLE_CHANNEL_TIMEOUT", Channel::ERROR_TIMEOUT);
141 SW_REGISTER_LONG_CONSTANT("SWOOLE_CHANNEL_CLOSED", Channel::ERROR_CLOSED);
142 SW_REGISTER_LONG_CONSTANT("SWOOLE_CHANNEL_CANCELED", Channel::ERROR_CANCELED);
143 }
144
PHP_METHOD(swoole_channel_coro,__construct)145 static PHP_METHOD(swoole_channel_coro, __construct) {
146 zend_long capacity = 1;
147
148 ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1)
149 Z_PARAM_OPTIONAL
150 Z_PARAM_LONG(capacity)
151 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
152
153 if (capacity <= 0) {
154 capacity = 1;
155 }
156
157 ChannelObject *chan_t = php_swoole_channel_coro_fetch_object(Z_OBJ_P(ZEND_THIS));
158 chan_t->chan = new Channel(capacity);
159 zend_update_property_long(swoole_channel_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("capacity"), capacity);
160 }
161
PHP_METHOD(swoole_channel_coro,push)162 static PHP_METHOD(swoole_channel_coro, push) {
163 Channel *chan = php_swoole_get_channel(ZEND_THIS);
164 zval *zdata;
165 double timeout = -1;
166
167 ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 2)
168 Z_PARAM_ZVAL(zdata)
169 Z_PARAM_OPTIONAL
170 Z_PARAM_DOUBLE(timeout)
171 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
172
173 Z_TRY_ADDREF_P(zdata);
174 zdata = sw_zval_dup(zdata);
175 if (chan->push(zdata, timeout)) {
176 zend_update_property_long(
177 swoole_channel_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errCode"), Channel::ERROR_OK);
178 RETURN_TRUE;
179 } else {
180 zend_update_property_long(
181 swoole_channel_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errCode"), chan->get_error());
182 Z_TRY_DELREF_P(zdata);
183 efree(zdata);
184 RETURN_FALSE;
185 }
186 }
187
PHP_METHOD(swoole_channel_coro,pop)188 static PHP_METHOD(swoole_channel_coro, pop) {
189 Channel *chan = php_swoole_get_channel(ZEND_THIS);
190 double timeout = -1;
191
192 ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1)
193 Z_PARAM_OPTIONAL
194 Z_PARAM_DOUBLE(timeout)
195 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
196
197 zval *zdata = (zval *) chan->pop(timeout);
198 if (zdata) {
199 RETVAL_ZVAL(zdata, 0, 0);
200 efree(zdata);
201 zend_update_property_long(
202 swoole_channel_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errCode"), Channel::ERROR_OK);
203 } else {
204 zend_update_property_long(
205 swoole_channel_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errCode"), chan->get_error());
206 RETURN_FALSE;
207 }
208 }
209
PHP_METHOD(swoole_channel_coro,close)210 static PHP_METHOD(swoole_channel_coro, close) {
211 Channel *chan = php_swoole_get_channel(ZEND_THIS);
212 RETURN_BOOL(chan->close());
213 }
214
PHP_METHOD(swoole_channel_coro,length)215 static PHP_METHOD(swoole_channel_coro, length) {
216 Channel *chan = php_swoole_get_channel(ZEND_THIS);
217 RETURN_LONG(chan->length());
218 }
219
PHP_METHOD(swoole_channel_coro,isEmpty)220 static PHP_METHOD(swoole_channel_coro, isEmpty) {
221 Channel *chan = php_swoole_get_channel(ZEND_THIS);
222 RETURN_BOOL(chan->is_empty());
223 }
224
PHP_METHOD(swoole_channel_coro,isFull)225 static PHP_METHOD(swoole_channel_coro, isFull) {
226 Channel *chan = php_swoole_get_channel(ZEND_THIS);
227 RETURN_BOOL(chan->is_full());
228 }
229
PHP_METHOD(swoole_channel_coro,stats)230 static PHP_METHOD(swoole_channel_coro, stats) {
231 Channel *chan = php_swoole_get_channel(ZEND_THIS);
232 array_init(return_value);
233 add_assoc_long_ex(return_value, ZEND_STRL("consumer_num"), chan->consumer_num());
234 add_assoc_long_ex(return_value, ZEND_STRL("producer_num"), chan->producer_num());
235 add_assoc_long_ex(return_value, ZEND_STRL("queue_num"), chan->length());
236 }
237