1 /*
2 +----------------------------------------------------------------------+
3 | Swoole |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2012-2015 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: Tianfeng Han <mikan.tenny@gmail.com> |
16 +----------------------------------------------------------------------+
17 */
18
19 #include "php_swoole_cxx.h"
20 #include "swoole_server.h"
21 #include "swoole_signal.h"
22
23 using namespace swoole;
24 using swoole::network::Socket;
25
26 static std::unordered_map<int, Socket *> event_socket_map;
27
28 zend_class_entry *swoole_event_ce;
29 static zend_object_handlers swoole_event_handlers;
30
31 struct EventObject {
32 zval zsocket;
33 zend_fcall_info_cache fci_cache_read;
34 zend_fcall_info_cache fci_cache_write;
35 };
36
37 static int event_readable_callback(Reactor *reactor, Event *event);
38 static int event_writable_callback(Reactor *reactor, Event *event);
39 static int event_error_callback(Reactor *reactor, Event *event);
40 static void event_defer_callback(void *data);
41 static void event_end_callback(void *data);
42
43 SW_EXTERN_C_BEGIN
44 static PHP_FUNCTION(swoole_event_add);
45 static PHP_FUNCTION(swoole_event_set);
46 static PHP_FUNCTION(swoole_event_del);
47 static PHP_FUNCTION(swoole_event_write);
48 static PHP_FUNCTION(swoole_event_wait);
49 static PHP_FUNCTION(swoole_event_rshutdown);
50 static PHP_FUNCTION(swoole_event_exit);
51 static PHP_FUNCTION(swoole_event_defer);
52 static PHP_FUNCTION(swoole_event_cycle);
53 static PHP_FUNCTION(swoole_event_dispatch);
54 static PHP_FUNCTION(swoole_event_isset);
55 SW_EXTERN_C_END
56
57 // clang-format off
58 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_void, 0, 0, 0)
59 ZEND_END_ARG_INFO()
60
61 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_event_add, 0, 0, 2)
62 ZEND_ARG_INFO(0, fd)
63 ZEND_ARG_CALLABLE_INFO(0, read_callback, 1)
64 ZEND_ARG_CALLABLE_INFO(0, write_callback, 1)
65 ZEND_ARG_INFO(0, events)
66 ZEND_END_ARG_INFO()
67
68 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_event_set, 0, 0, 1)
69 ZEND_ARG_INFO(0, fd)
70 ZEND_ARG_CALLABLE_INFO(0, read_callback, 1)
71 ZEND_ARG_CALLABLE_INFO(0, write_callback, 1)
72 ZEND_ARG_INFO(0, events)
73 ZEND_END_ARG_INFO()
74
75 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_event_write, 0, 0, 2)
76 ZEND_ARG_INFO(0, fd)
77 ZEND_ARG_INFO(0, data)
78 ZEND_END_ARG_INFO()
79
80 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_event_defer, 0, 0, 1)
81 ZEND_ARG_CALLABLE_INFO(0, callback, 0)
82 ZEND_END_ARG_INFO()
83
84 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_event_cycle, 0, 0, 1)
85 ZEND_ARG_CALLABLE_INFO(0, callback, 1)
86 ZEND_ARG_INFO(0, before)
87 ZEND_END_ARG_INFO()
88
89 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_event_del, 0, 0, 1)
90 ZEND_ARG_INFO(0, fd)
91 ZEND_END_ARG_INFO()
92
93 ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_event_isset, 0, 0, 1)
94 ZEND_ARG_INFO(0, fd)
95 ZEND_ARG_INFO(0, events)
96 ZEND_END_ARG_INFO()
97
98 static const zend_function_entry swoole_event_methods[] =
99 {
100 ZEND_FENTRY(add, ZEND_FN(swoole_event_add), arginfo_swoole_event_add, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
101 ZEND_FENTRY(del, ZEND_FN(swoole_event_del), arginfo_swoole_event_del, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
102 ZEND_FENTRY(set, ZEND_FN(swoole_event_set), arginfo_swoole_event_set, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
103 ZEND_FENTRY(isset, ZEND_FN(swoole_event_isset), arginfo_swoole_event_isset, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
104 ZEND_FENTRY(dispatch, ZEND_FN(swoole_event_dispatch), arginfo_swoole_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
105 ZEND_FENTRY(defer, ZEND_FN(swoole_event_defer), arginfo_swoole_event_defer, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
106 ZEND_FENTRY(cycle, ZEND_FN(swoole_event_cycle), arginfo_swoole_event_cycle, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
107 ZEND_FENTRY(write, ZEND_FN(swoole_event_write), arginfo_swoole_event_write, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
108 ZEND_FENTRY(wait, ZEND_FN(swoole_event_wait), arginfo_swoole_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
109 ZEND_FENTRY(rshutdown, ZEND_FN(swoole_event_rshutdown), arginfo_swoole_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
110 ZEND_FENTRY(exit, ZEND_FN(swoole_event_exit), arginfo_swoole_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
111 PHP_FE_END
112 };
113 // clang-format on
114
php_swoole_event_minit(int module_number)115 void php_swoole_event_minit(int module_number) {
116 SW_INIT_CLASS_ENTRY(swoole_event, "Swoole\\Event", "swoole_event", nullptr, swoole_event_methods);
117 SW_SET_CLASS_CREATE(swoole_event, sw_zend_create_object_deny);
118
119 SW_FUNCTION_ALIAS(&swoole_event_ce->function_table, "add", CG(function_table), "swoole_event_add");
120 SW_FUNCTION_ALIAS(&swoole_event_ce->function_table, "del", CG(function_table), "swoole_event_del");
121 SW_FUNCTION_ALIAS(&swoole_event_ce->function_table, "set", CG(function_table), "swoole_event_set");
122 SW_FUNCTION_ALIAS(&swoole_event_ce->function_table, "isset", CG(function_table), "swoole_event_isset");
123 SW_FUNCTION_ALIAS(&swoole_event_ce->function_table, "dispatch", CG(function_table), "swoole_event_dispatch");
124 SW_FUNCTION_ALIAS(&swoole_event_ce->function_table, "defer", CG(function_table), "swoole_event_defer");
125 SW_FUNCTION_ALIAS(&swoole_event_ce->function_table, "cycle", CG(function_table), "swoole_event_cycle");
126 SW_FUNCTION_ALIAS(&swoole_event_ce->function_table, "write", CG(function_table), "swoole_event_write");
127 SW_FUNCTION_ALIAS(&swoole_event_ce->function_table, "wait", CG(function_table), "swoole_event_wait");
128 SW_FUNCTION_ALIAS(&swoole_event_ce->function_table, "exit", CG(function_table), "swoole_event_exit");
129 }
130
event_object_free(void * data)131 static void event_object_free(void *data) {
132 EventObject *peo = (EventObject *) data;
133 if (peo->fci_cache_read.function_handler) {
134 sw_zend_fci_cache_discard(&peo->fci_cache_read);
135 }
136 if (peo->fci_cache_write.function_handler) {
137 sw_zend_fci_cache_discard(&peo->fci_cache_write);
138 }
139 zval_ptr_dtor((&peo->zsocket));
140 efree(peo);
141 }
142
event_readable_callback(Reactor * reactor,swEvent * event)143 static int event_readable_callback(Reactor *reactor, swEvent *event) {
144 EventObject *peo = (EventObject *) event->socket->object;
145
146 zval argv[1];
147 argv[0] = peo->zsocket;
148
149 if (UNEXPECTED(!zend::function::call(&peo->fci_cache_read, 1, argv, nullptr, php_swoole_is_enable_coroutine()))) {
150 php_swoole_fatal_error(E_WARNING,
151 "%s: onRead callback handler error, fd [%d] will be removed from reactor",
152 ZSTR_VAL(swoole_event_ce->name),
153 php_swoole_convert_to_fd(&peo->zsocket));
154 event->socket->object = nullptr;
155 swoole_event_defer(event_object_free, peo);
156 swoole_event_del(event->socket);
157 return SW_ERR;
158 }
159
160 return SW_OK;
161 }
162
event_writable_callback(Reactor * reactor,Event * event)163 static int event_writable_callback(Reactor *reactor, Event *event) {
164 EventObject *peo = (EventObject *) event->socket->object;
165
166 zval argv[1];
167 argv[0] = peo->zsocket;
168
169 if (UNEXPECTED(!zend::function::call(&peo->fci_cache_write, 1, argv, nullptr, php_swoole_is_enable_coroutine()))) {
170 php_swoole_fatal_error(E_WARNING,
171 "%s: onWrite callback handler error, fd [%d] will be removed from reactor",
172 ZSTR_VAL(swoole_event_ce->name),
173 php_swoole_convert_to_fd(&peo->zsocket));
174 event->socket->object = nullptr;
175 swoole_event_defer(event_object_free, peo);
176 swoole_event_del(event->socket);
177 return SW_ERR;
178 }
179
180 return SW_OK;
181 }
182
event_error_callback(Reactor * reactor,swEvent * event)183 static int event_error_callback(Reactor *reactor, swEvent *event) {
184 if (!(event->socket->events & SW_EVENT_ERROR)) {
185 if (event->socket->events & SW_EVENT_READ) {
186 return reactor->get_handler(SW_EVENT_READ, event->socket->fd_type)(reactor, event);
187 } else {
188 return reactor->get_handler(SW_EVENT_WRITE, event->socket->fd_type)(reactor, event);
189 }
190 }
191
192 int error;
193 if (event->socket->get_option(SOL_SOCKET, SO_ERROR, &error) < 0) {
194 php_swoole_sys_error(E_WARNING, "swoole_event->onError[1]: getsockopt[sock=%d] failed", event->fd);
195 }
196
197 if (error != 0) {
198 php_swoole_fatal_error(
199 E_WARNING, "swoole_event->onError[1]: socket error. Error: %s [%d]", strerror(error), error);
200 }
201
202 event_object_free(event->socket->object);
203 swoole_event_del(event->socket);
204
205 return SW_OK;
206 }
207
event_defer_callback(void * data)208 static void event_defer_callback(void *data) {
209 zend_fcall_info_cache *fci_cache = (zend_fcall_info_cache *) data;
210
211 if (UNEXPECTED(!zend::function::call(fci_cache, 0, nullptr, nullptr, php_swoole_is_enable_coroutine()))) {
212 php_swoole_error(E_WARNING, "%s::defer callback handler error", ZSTR_VAL(swoole_event_ce->name));
213 }
214
215 sw_zend_fci_cache_discard(fci_cache);
216 efree(fci_cache);
217 }
218
event_end_callback(void * data)219 static void event_end_callback(void *data) {
220 zend_fcall_info_cache *fci_cache = (zend_fcall_info_cache *) data;
221 if (UNEXPECTED(!zend::function::call(fci_cache, 0, nullptr, nullptr, php_swoole_is_enable_coroutine()))) {
222 php_swoole_error(E_WARNING, "%s::end callback handler error", ZSTR_VAL(swoole_event_ce->name));
223 }
224 }
225
php_swoole_reactor_init()226 int php_swoole_reactor_init() {
227 if (!SWOOLE_G(cli)) {
228 php_swoole_fatal_error(E_ERROR, "async-io must be used in PHP CLI mode");
229 return SW_ERR;
230 }
231
232 if (sw_server()) {
233 if (sw_server()->is_task_worker() && !sw_server()->task_enable_coroutine) {
234 php_swoole_fatal_error(
235 E_ERROR, "Unable to use async-io in task processes, please set `task_enable_coroutine` to true");
236 return SW_ERR;
237 }
238 if (sw_server()->is_manager()) {
239 php_swoole_fatal_error(E_ERROR, "Unable to use async-io in manager process");
240 return SW_ERR;
241 }
242 }
243 if (!sw_reactor()) {
244 swoole_trace_log(SW_TRACE_PHP, "init reactor");
245
246 if (swoole_event_init(SW_EVENTLOOP_WAIT_EXIT) < 0) {
247 php_swoole_fatal_error(E_ERROR, "Unable to create event-loop reactor");
248 return SW_ERR;
249 }
250
251 php_swoole_register_shutdown_function("Swoole\\Event::rshutdown");
252 }
253
254 if (sw_reactor() && SwooleG.user_exit_condition &&
255 !sw_reactor()->isset_exit_condition(Reactor::EXIT_CONDITION_USER_AFTER_DEFAULT)) {
256 sw_reactor()->set_exit_condition(Reactor::EXIT_CONDITION_USER_AFTER_DEFAULT, SwooleG.user_exit_condition);
257 }
258
259 return SW_OK;
260 }
261
php_swoole_event_wait()262 void php_swoole_event_wait() {
263 if (php_swoole_is_fatal_error() || !sw_reactor()) {
264 return;
265 }
266 #ifdef HAVE_SIGNALFD
267 if (sw_reactor()->check_signalfd) {
268 swoole_signalfd_setup(sw_reactor());
269 }
270 #endif
271 if (!sw_reactor()->if_exit() && !sw_reactor()->bailout) {
272 // Don't disable object slot reuse while running shutdown functions:
273 // https://github.com/php/php-src/commit/bd6eabd6591ae5a7c9ad75dfbe7cc575fa907eac
274 #if defined(EG_FLAGS_IN_SHUTDOWN) && !defined(EG_FLAGS_OBJECT_STORE_NO_REUSE)
275 zend_bool in_shutdown = EG(flags) & EG_FLAGS_IN_SHUTDOWN;
276 EG(flags) &= ~EG_FLAGS_IN_SHUTDOWN;
277 #endif
278 if (sw_reactor()->wait(nullptr) < 0) {
279 php_swoole_sys_error(E_ERROR, "reactor wait failed");
280 }
281 #if defined(EG_FLAGS_IN_SHUTDOWN) && !defined(EG_FLAGS_OBJECT_STORE_NO_REUSE)
282 if (in_shutdown) {
283 EG(flags) |= EG_FLAGS_IN_SHUTDOWN;
284 }
285 #endif
286 }
287 swoole_event_free();
288 }
289
php_swoole_event_exit()290 void php_swoole_event_exit() {
291 if (sw_reactor()) {
292 php_swoole_timer_clear_all();
293 sw_reactor()->running = false;
294 }
295 }
296
php_swoole_convert_to_fd(zval * zsocket)297 int php_swoole_convert_to_fd(zval *zsocket) {
298 int fd = -1;
299
300 switch (Z_TYPE_P(zsocket)) {
301 case IS_RESOURCE: {
302 php_stream *stream;
303 if ((php_stream_from_zval_no_verify(stream, zsocket))) {
304 if (php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void **) &fd, 1) ==
305 SUCCESS &&
306 fd >= 0) {
307 return fd;
308 }
309 }
310 #ifdef SWOOLE_SOCKETS_SUPPORT
311 else {
312 php_socket *php_sock;
313 if ((php_sock = SW_Z_SOCKET_P(zsocket))) {
314 fd = php_sock->bsd_socket;
315 return fd;
316 }
317 }
318 #endif
319 php_swoole_fatal_error(E_WARNING, "fd argument must be either valid PHP stream or valid PHP socket resource");
320 return SW_ERR;
321 }
322 case IS_LONG: {
323 fd = Z_LVAL_P(zsocket);
324 if (fd < 0) {
325 php_swoole_fatal_error(E_WARNING, "invalid file descriptor#%d passed", fd);
326 return SW_ERR;
327 }
328 return fd;
329 }
330 case IS_OBJECT: {
331 zval *zfd = nullptr;
332 if (instanceof_function(Z_OBJCE_P(zsocket), swoole_socket_coro_ce)) {
333 zfd = sw_zend_read_property_ex(Z_OBJCE_P(zsocket), zsocket, SW_ZSTR_KNOWN(SW_ZEND_STR_FD), 0);
334 } else if (instanceof_function(Z_OBJCE_P(zsocket), swoole_client_ce)) {
335 zfd = sw_zend_read_property_ex(Z_OBJCE_P(zsocket), zsocket, SW_ZSTR_KNOWN(SW_ZEND_STR_SOCK), 0);
336 } else if (instanceof_function(Z_OBJCE_P(zsocket), swoole_process_ce)) {
337 zfd = sw_zend_read_property_ex(Z_OBJCE_P(zsocket), zsocket, SW_ZSTR_KNOWN(SW_ZEND_STR_PIPE), 0);
338 }
339 if (zfd == nullptr || Z_TYPE_P(zfd) != IS_LONG) {
340 return SW_ERR;
341 }
342 return Z_LVAL_P(zfd);
343 }
344 default:
345 php_swoole_fatal_error(E_WARNING, "invalid file descriptor passed");
346 return SW_ERR;
347 }
348 }
349
php_swoole_convert_to_fd_ex(zval * zsocket,int * async)350 int php_swoole_convert_to_fd_ex(zval *zsocket, int *async) {
351 int fd;
352
353 *async = 0;
354 if (Z_TYPE_P(zsocket) == IS_RESOURCE) {
355 php_stream *stream;
356 if ((php_stream_from_zval_no_verify(stream, zsocket))) {
357 if (php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void **) &fd, 1) ==
358 SUCCESS &&
359 fd >= 0) {
360 *async = (stream->wrapper && (stream->wrapper->wops == php_plain_files_wrapper.wops)) ? 0 : 1;
361 return fd;
362 }
363 }
364 #ifdef SWOOLE_SOCKETS_SUPPORT
365 else {
366 php_socket *php_sock;
367 if ((php_sock = SW_Z_SOCKET_P(zsocket))) {
368 fd = php_sock->bsd_socket;
369 *async = 1;
370 return fd;
371 }
372 }
373 #endif
374 }
375 php_swoole_fatal_error(E_WARNING, "fd argument must be either valid PHP stream or valid PHP socket resource");
376 return SW_ERR;
377 }
378
379 #ifdef SWOOLE_SOCKETS_SUPPORT
php_swoole_convert_to_socket(int sock)380 php_socket *php_swoole_convert_to_socket(int sock) {
381 php_socket *socket_object;
382 #if PHP_VERSION_ID < 80000
383 socket_object = (php_socket *) emalloc(sizeof *socket_object);
384 sw_memset_zero(socket_object, sizeof(*socket_object));
385 socket_object->bsd_socket = sock;
386 socket_object->blocking = 1;
387
388 struct sockaddr_storage addr;
389 socklen_t addr_len = sizeof(addr);
390
391 if (getsockname(sock, (struct sockaddr *) &addr, &addr_len) == 0) {
392 socket_object->type = addr.ss_family;
393 } else {
394 php_swoole_sys_error(E_WARNING, "unable to obtain socket family");
395 _error:
396 efree(socket_object);
397 return nullptr;
398 }
399
400 int t = fcntl(sock, F_GETFL);
401 if (t == -1) {
402 php_swoole_sys_error(E_WARNING, "unable to obtain blocking state");
403 goto _error;
404 } else {
405 socket_object->blocking = !(t & O_NONBLOCK);
406 }
407 #else
408 zval zsocket;
409 object_init_ex(&zsocket, socket_ce);
410 socket_object = Z_SOCKET_P(&zsocket);
411 socket_import_file_descriptor(sock, socket_object);
412 #endif
413 return socket_object;
414 }
415 #endif
416
event_check_reactor()417 static void event_check_reactor() {
418 php_swoole_check_reactor();
419
420 if (!swoole_event_isset_handler(SW_FD_USER)) {
421 swoole_event_set_handler(SW_FD_USER | SW_EVENT_READ, event_readable_callback);
422 swoole_event_set_handler(SW_FD_USER | SW_EVENT_WRITE, event_writable_callback);
423 swoole_event_set_handler(SW_FD_USER | SW_EVENT_ERROR, event_error_callback);
424 }
425 }
426
event_get_socket(int socket_fd)427 static Socket *event_get_socket(int socket_fd) {
428 auto i = event_socket_map.find(socket_fd);
429 if (i == event_socket_map.end()) {
430 return nullptr;
431 }
432 return i->second;
433 }
434
PHP_FUNCTION(swoole_event_add)435 static PHP_FUNCTION(swoole_event_add) {
436 zval *zfd;
437 zend_fcall_info fci_read = empty_fcall_info;
438 zend_fcall_info_cache fci_cache_read = empty_fcall_info_cache;
439 zend_fcall_info fci_write = empty_fcall_info;
440 zend_fcall_info_cache fci_cache_write = empty_fcall_info_cache;
441 zend_long events = SW_EVENT_READ;
442
443 ZEND_PARSE_PARAMETERS_START(1, 4)
444 Z_PARAM_ZVAL(zfd)
445 Z_PARAM_OPTIONAL
446 Z_PARAM_FUNC_EX(fci_read, fci_cache_read, 1, 0)
447 Z_PARAM_FUNC_EX(fci_write, fci_cache_write, 1, 0)
448 Z_PARAM_LONG(events)
449 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
450
451 if (fci_read.size == 0 && fci_write.size == 0) {
452 php_swoole_fatal_error(E_WARNING, "both read and write callbacks are empty");
453 RETURN_FALSE;
454 }
455
456 int socket_fd = php_swoole_convert_to_fd(zfd);
457 if (socket_fd < 0) {
458 php_swoole_fatal_error(E_WARNING, "unknown fd type");
459 RETURN_FALSE;
460 }
461 if (socket_fd == 0 && (events & SW_EVENT_WRITE)) {
462 php_swoole_fatal_error(E_WARNING, "invalid socket fd [%d]", socket_fd);
463 RETURN_FALSE;
464 }
465 if (event_socket_map.find(socket_fd) != event_socket_map.end()) {
466 php_swoole_fatal_error(E_WARNING, "already exist");
467 RETURN_FALSE;
468 }
469 if (!(events & (SW_EVENT_WRITE | SW_EVENT_READ))) {
470 php_swoole_fatal_error(E_WARNING, "invalid events");
471 RETURN_FALSE;
472 }
473
474 EventObject *peo = (EventObject *) ecalloc(1, sizeof(*peo));
475
476 Z_TRY_ADDREF_P(zfd);
477 peo->zsocket = *zfd;
478
479 if (fci_read.size != 0) {
480 sw_zend_fci_cache_persist(&fci_cache_read);
481 peo->fci_cache_read = fci_cache_read;
482 }
483 if (fci_write.size != 0) {
484 sw_zend_fci_cache_persist(&fci_cache_write);
485 peo->fci_cache_write = fci_cache_write;
486 }
487
488 event_check_reactor();
489
490 Socket *socket = swoole::make_socket(socket_fd, SW_FD_USER);
491 if (!socket) {
492 RETURN_FALSE;
493 }
494
495 socket->set_nonblock();
496 socket->object = peo;
497
498 if (swoole_event_add(socket, events) < 0) {
499 php_swoole_fatal_error(E_WARNING, "swoole_event_add failed");
500 socket->free();
501 event_object_free(peo);
502 RETURN_FALSE;
503 }
504
505 event_socket_map[socket_fd] = socket;
506
507 RETURN_LONG(socket_fd);
508 }
509
PHP_FUNCTION(swoole_event_write)510 static PHP_FUNCTION(swoole_event_write) {
511 zval *zfd;
512 char *data;
513 size_t len;
514
515 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs", &zfd, &data, &len) == FAILURE) {
516 RETURN_FALSE;
517 }
518
519 if (len == 0) {
520 php_swoole_fatal_error(E_WARNING, "data empty");
521 RETURN_FALSE;
522 }
523
524 int socket_fd = php_swoole_convert_to_fd(zfd);
525 if (socket_fd < 0) {
526 php_swoole_fatal_error(E_WARNING, "unknown type");
527 RETURN_FALSE;
528 }
529
530 Socket *socket = event_get_socket(socket_fd);
531 if (socket == nullptr) {
532 php_swoole_fatal_error(E_WARNING, "socket[%d] is not found in the reactor", socket_fd);
533 RETURN_FALSE;
534 }
535
536 event_check_reactor();
537 if (swoole_event_write(socket, data, len) < 0) {
538 RETURN_FALSE;
539 } else {
540 RETURN_TRUE;
541 }
542 }
543
PHP_FUNCTION(swoole_event_set)544 static PHP_FUNCTION(swoole_event_set) {
545 if (!sw_reactor()) {
546 php_swoole_fatal_error(E_WARNING, "reactor is not ready, cannot call swoole_event_set");
547 RETURN_FALSE;
548 }
549
550 zval *zfd;
551 zend_fcall_info fci_read = empty_fcall_info;
552 zend_fcall_info_cache fci_cache_read = empty_fcall_info_cache;
553 zend_fcall_info fci_write = empty_fcall_info;
554 zend_fcall_info_cache fci_cache_write = empty_fcall_info_cache;
555 zend_long events = 0;
556
557 ZEND_PARSE_PARAMETERS_START(1, 4)
558 Z_PARAM_ZVAL(zfd)
559 Z_PARAM_OPTIONAL
560 Z_PARAM_FUNC_EX(fci_read, fci_cache_read, 1, 0)
561 Z_PARAM_FUNC_EX(fci_write, fci_cache_write, 1, 0)
562 Z_PARAM_LONG(events)
563 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
564
565 int socket_fd = php_swoole_convert_to_fd(zfd);
566 if (socket_fd < 0) {
567 php_swoole_fatal_error(E_WARNING, "unknown type");
568 RETURN_FALSE;
569 }
570
571 Socket *socket = event_get_socket(socket_fd);
572 if (socket == nullptr) {
573 php_swoole_fatal_error(E_WARNING, "socket[%d] is not found in the reactor", socket_fd);
574 RETURN_FALSE;
575 }
576
577 EventObject *reactor_fd = (EventObject *) socket->object;
578 if (fci_read.size != 0) {
579 if (reactor_fd->fci_cache_read.function_handler) {
580 sw_zend_fci_cache_discard(&reactor_fd->fci_cache_read);
581 }
582 sw_zend_fci_cache_persist(&fci_cache_read);
583 reactor_fd->fci_cache_read = fci_cache_read;
584 }
585 if (fci_write.size != 0) {
586 if (reactor_fd->fci_cache_write.function_handler) {
587 sw_zend_fci_cache_discard(&reactor_fd->fci_cache_write);
588 }
589 sw_zend_fci_cache_persist(&fci_cache_write);
590 reactor_fd->fci_cache_write = fci_cache_write;
591 }
592
593 if ((events & SW_EVENT_READ) && reactor_fd->fci_cache_read.function_handler == nullptr) {
594 php_swoole_fatal_error(
595 E_WARNING, "%s: unable to find read callback of fd [%d]", ZSTR_VAL(swoole_event_ce->name), socket_fd);
596 RETURN_FALSE;
597 }
598 if ((events & SW_EVENT_WRITE) && reactor_fd->fci_cache_write.function_handler == nullptr) {
599 php_swoole_fatal_error(
600 E_WARNING, "%s: unable to find write callback of fd [%d]", ZSTR_VAL(swoole_event_ce->name), socket_fd);
601 RETURN_FALSE;
602 }
603 if (swoole_event_set(socket, events) < 0) {
604 php_swoole_fatal_error(E_WARNING, "%s::set failed", ZSTR_VAL(swoole_event_ce->name));
605 RETURN_FALSE;
606 }
607
608 RETURN_TRUE;
609 }
610
PHP_FUNCTION(swoole_event_del)611 static PHP_FUNCTION(swoole_event_del) {
612 zval *zfd;
613
614 if (!sw_reactor()) {
615 php_swoole_fatal_error(E_WARNING, "reactor is not ready, cannot call swoole_event_del");
616 RETURN_FALSE;
617 }
618
619 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zfd) == FAILURE) {
620 RETURN_FALSE;
621 }
622
623 int socket_fd = php_swoole_convert_to_fd(zfd);
624 if (socket_fd < 0) {
625 php_swoole_fatal_error(E_WARNING, "unknown type");
626 RETURN_FALSE;
627 }
628
629 Socket *socket = event_get_socket(socket_fd);
630 if (!socket) {
631 RETURN_FALSE;
632 }
633 swoole_event_defer(event_object_free, socket->object);
634 int retval = swoole_event_del(socket);
635 event_socket_map.erase(socket_fd);
636 socket->fd = -1;
637 socket->free();
638 RETURN_BOOL(retval == SW_OK);
639 }
640
PHP_FUNCTION(swoole_event_defer)641 static PHP_FUNCTION(swoole_event_defer) {
642 zend_fcall_info fci = empty_fcall_info;
643 zend_fcall_info_cache *fci_cache = (zend_fcall_info_cache *) ecalloc(1, sizeof(zend_fcall_info_cache));
644
645 ZEND_PARSE_PARAMETERS_START(1, 1)
646 Z_PARAM_FUNC(fci, *fci_cache)
647 ZEND_PARSE_PARAMETERS_END_EX(efree(fci_cache); RETURN_FALSE);
648
649 php_swoole_check_reactor();
650
651 sw_zend_fci_cache_persist(fci_cache);
652 swoole_event_defer(event_defer_callback, fci_cache);
653
654 RETURN_TRUE;
655 }
656
PHP_FUNCTION(swoole_event_cycle)657 static PHP_FUNCTION(swoole_event_cycle) {
658 if (!sw_reactor()) {
659 php_swoole_fatal_error(E_WARNING, "reactor is not ready, cannot call %s", ZSTR_VAL(swoole_event_ce->name));
660 RETURN_FALSE;
661 }
662
663 zend_fcall_info _fci = empty_fcall_info;
664 zend_fcall_info_cache _fci_cache = empty_fcall_info_cache;
665 zend_bool before = 0;
666
667 ZEND_PARSE_PARAMETERS_START(1, 2)
668 Z_PARAM_FUNC_EX(_fci, _fci_cache, 1, 0)
669 Z_PARAM_OPTIONAL
670 Z_PARAM_BOOL(before)
671 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
672
673 if (_fci.size == 0) {
674 if (sw_reactor()->idle_task.callback == nullptr) {
675 RETURN_FALSE;
676 } else {
677 swoole_event_defer(sw_zend_fci_cache_free, sw_reactor()->idle_task.data);
678 sw_reactor()->idle_task.callback = nullptr;
679 sw_reactor()->idle_task.data = nullptr;
680 RETURN_TRUE;
681 }
682 }
683
684 zend_fcall_info_cache *fci_cache = (zend_fcall_info_cache *) emalloc(sizeof(zend_fcall_info_cache));
685
686 *fci_cache = _fci_cache;
687 sw_zend_fci_cache_persist(fci_cache);
688
689 if (!before) {
690 if (sw_reactor()->idle_task.data != nullptr) {
691 swoole_event_defer(sw_zend_fci_cache_free, sw_reactor()->idle_task.data);
692 }
693
694 sw_reactor()->idle_task.callback = event_end_callback;
695 sw_reactor()->idle_task.data = fci_cache;
696 } else {
697 if (sw_reactor()->future_task.data != nullptr) {
698 swoole_event_defer(sw_zend_fci_cache_free, sw_reactor()->future_task.data);
699 }
700
701 sw_reactor()->future_task.callback = event_end_callback;
702 sw_reactor()->future_task.data = fci_cache;
703 // Registration onBegin callback function
704 sw_reactor()->activate_future_task();
705 }
706
707 RETURN_TRUE;
708 }
709
PHP_FUNCTION(swoole_event_exit)710 static PHP_FUNCTION(swoole_event_exit) {
711 php_swoole_event_exit();
712 }
713
PHP_FUNCTION(swoole_event_wait)714 static PHP_FUNCTION(swoole_event_wait) {
715 if (!sw_reactor()) {
716 return;
717 }
718 php_swoole_event_wait();
719 }
720
PHP_FUNCTION(swoole_event_rshutdown)721 static PHP_FUNCTION(swoole_event_rshutdown) {
722 /* prevent the program from jumping out of the rshutdown */
723 zend_try {
724 if (!sw_reactor()) {
725 return;
726 }
727 // when throw Exception, do not show the info
728 if (!sw_reactor()->bailout) {
729 php_swoole_fatal_error(E_DEPRECATED, "Event::wait() in shutdown function is deprecated");
730 }
731 php_swoole_event_wait();
732 }
733 zend_end_try();
734 }
735
PHP_FUNCTION(swoole_event_dispatch)736 static PHP_FUNCTION(swoole_event_dispatch) {
737 if (!sw_reactor()) {
738 RETURN_FALSE;
739 }
740 sw_reactor()->once = true;
741
742 #ifdef HAVE_SIGNALFD
743 if (sw_reactor()->check_signalfd) {
744 swoole_signalfd_setup(sw_reactor());
745 }
746 #endif
747
748 if (sw_reactor()->wait(nullptr) < 0) {
749 php_swoole_sys_error(E_ERROR, "reactor wait failed");
750 }
751
752 sw_reactor()->once = false;
753 RETURN_TRUE;
754 }
755
PHP_FUNCTION(swoole_event_isset)756 static PHP_FUNCTION(swoole_event_isset) {
757 if (!sw_reactor()) {
758 RETURN_FALSE;
759 }
760
761 zval *zfd;
762 zend_long events = SW_EVENT_READ | SW_EVENT_WRITE;
763
764 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &zfd, &events) == FAILURE) {
765 RETURN_FALSE;
766 }
767
768 int socket_fd = php_swoole_convert_to_fd(zfd);
769 if (socket_fd < 0) {
770 php_swoole_fatal_error(E_WARNING, "unknown type");
771 RETURN_FALSE;
772 }
773
774 Socket *_socket = event_get_socket(socket_fd);
775 if (_socket == nullptr || _socket->removed) {
776 RETURN_FALSE;
777 }
778 if (_socket->events & events) {
779 RETURN_TRUE;
780 } else {
781 RETURN_FALSE;
782 }
783 }
784