diff --git a/ext-src/php_swoole_cxx.h b/ext-src/php_swoole_cxx.h index 68503172be4..f0ce177322f 100644 --- a/ext-src/php_swoole_cxx.h +++ b/ext-src/php_swoole_cxx.h @@ -127,6 +127,7 @@ extern zend_string **sw_zend_known_strings; SW_API bool php_swoole_is_enable_coroutine(); SW_API zend_object *php_swoole_create_socket(enum swSocketType type); SW_API zend_object *php_swoole_create_socket_from_fd(int fd, enum swSocketType type); +SW_API zend_object *php_swoole_create_socket_from_fd(int fd, int _domain, int _type, int _protocol); SW_API bool php_swoole_export_socket(zval *zobject, swoole::coroutine::Socket *_socket); SW_API zend_object *php_swoole_dup_socket(int fd, enum swSocketType type); SW_API void php_swoole_init_socket_object(zval *zobject, swoole::coroutine::Socket *socket); diff --git a/ext-src/php_swoole_thread.h b/ext-src/php_swoole_thread.h index bb638b3aca1..b2c009a1bb4 100644 --- a/ext-src/php_swoole_thread.h +++ b/ext-src/php_swoole_thread.h @@ -31,8 +31,11 @@ bool php_swoole_thread_resource_free(ThreadResourceId resource_id, ThreadResourc ThreadResource *php_swoole_thread_resource_fetch(ThreadResourceId resource_id); void php_swoole_thread_start(zend_string *file, zend_string *argv); -zend_string *php_swoole_thread_serialize(zval *zdata); -bool php_swoole_thread_unserialize(zend_string *data, zval *zv); +zend_string *php_swoole_thread_argv_serialize(zval *zdata); +bool php_swoole_thread_argv_unserialize(zend_string *data, zval *zv); +zend_string *php_swoole_serialize(zval *zdata); +bool php_swoole_unserialize(zend_string *data, zval *zv); +void php_swoole_thread_argv_dtor(zval *zdata); void php_swoole_thread_bailout(void); zval *php_swoole_thread_get_arguments(); @@ -40,8 +43,11 @@ zval *php_swoole_thread_get_arguments(); #define EMSG_NO_RESOURCE "resource not found" #define ECODE_NO_RESOURCE -2 -#define IS_STREAM_SOCKET 98 -#define IS_SERIALIZED_OBJECT 99 +enum { + IS_CO_SOCKET = 97, + IS_STREAM_SOCKET = 98, + IS_SERIALIZED_OBJECT = 99, +}; struct ThreadResource { uint32_t ref_count; @@ -66,6 +72,10 @@ struct ArrayItem { zend_string *str; zend_long lval; double dval; + struct { + int fd; + swSocketType type; + } socket; zend_string *serialized_object; } value; diff --git a/ext-src/swoole_server.cc b/ext-src/swoole_server.cc index 62b75c7c38a..2d90a08b2f1 100644 --- a/ext-src/swoole_server.cc +++ b/ext-src/swoole_server.cc @@ -2651,7 +2651,7 @@ static PHP_METHOD(swoole_server, start) { if (!ZVAL_IS_NULL(&server_object->init_arguments)) { call_user_function(NULL, NULL, &server_object->init_arguments, &thread_argv, 0, NULL); - thread_argv_serialized = php_swoole_thread_serialize(&thread_argv); + thread_argv_serialized = php_swoole_thread_argv_serialize(&thread_argv); } serv->worker_thread_start = [bootstrap, thread_argv_serialized](const WorkerFn &fn) { diff --git a/ext-src/swoole_socket_coro.cc b/ext-src/swoole_socket_coro.cc index 82868a979ee..9f4843719ef 100644 --- a/ext-src/swoole_socket_coro.cc +++ b/ext-src/swoole_socket_coro.cc @@ -89,9 +89,6 @@ static PHP_METHOD(swoole_socket_coro, getsockname); static PHP_METHOD(swoole_socket_coro, getpeername); static PHP_METHOD(swoole_socket_coro, isClosed); static PHP_METHOD(swoole_socket_coro, import); -#ifdef SW_THREAD -static PHP_METHOD(swoole_socket_coro, __wakeup); -#endif SW_EXTERN_C_END // clang-format off @@ -132,9 +129,6 @@ static const zend_function_entry swoole_socket_coro_methods[] = PHP_ME(swoole_socket_coro, getsockname, arginfo_class_Swoole_Coroutine_Socket_getsockname, ZEND_ACC_PUBLIC) PHP_ME(swoole_socket_coro, isClosed, arginfo_class_Swoole_Coroutine_Socket_isClosed, ZEND_ACC_PUBLIC) PHP_ME(swoole_socket_coro, import, arginfo_class_Swoole_Coroutine_Socket_import, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) -#ifdef SW_THREAD - PHP_ME(swoole_socket_coro, __wakeup, arginfo_class_Swoole_Coroutine_Socket___wakeup, ZEND_ACC_PUBLIC) -#endif PHP_FE_END }; // clang-format on @@ -720,9 +714,7 @@ static void socket_coro_register_constants(int module_number) { void php_swoole_socket_coro_minit(int module_number) { SW_INIT_CLASS_ENTRY(swoole_socket_coro, "Swoole\\Coroutine\\Socket", "Co\\Socket", swoole_socket_coro_methods); -#ifndef SW_THREAD SW_SET_CLASS_NOT_SERIALIZABLE(swoole_socket_coro); -#endif SW_SET_CLASS_CLONEABLE(swoole_socket_coro, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_socket_coro, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT( @@ -829,12 +821,12 @@ SW_API void php_swoole_socket_set_error_properties(zval *zobject, Socket *socket php_swoole_socket_set_error_properties(zobject, socket->errCode, socket->errMsg); } -SW_API zend_object *php_swoole_create_socket_from_fd(int fd, enum swSocketType type) { +static zend_object *create_socket_object(Socket *socket) { zval zobject; zend_object *object = socket_coro_create_object(swoole_socket_coro_ce); SocketObject *sock = (SocketObject *) socket_coro_fetch_object(object); - sock->socket = new Socket(fd, type); + sock->socket = socket; if (UNEXPECTED(sock->socket->get_fd() < 0)) { php_swoole_sys_error(E_WARNING, "new Socket() failed"); delete sock->socket; @@ -848,6 +840,14 @@ SW_API zend_object *php_swoole_create_socket_from_fd(int fd, enum swSocketType t return object; } +SW_API zend_object *php_swoole_create_socket_from_fd(int fd, enum swSocketType type) { + return create_socket_object(new Socket(fd, type)); +} + +SW_API zend_object *php_swoole_create_socket_from_fd(int fd, int _domain, int _type, int _protocol) { + return create_socket_object(new Socket(fd, _domain, _type, _protocol)); +} + SW_API Socket *php_swoole_get_socket(zval *zobject) { SW_ASSERT(Z_OBJCE_P(zobject) == swoole_socket_coro_ce); SocketObject *sock = (SocketObject *) socket_coro_fetch_object(Z_OBJ_P(zobject)); @@ -2185,7 +2185,7 @@ static PHP_METHOD(swoole_socket_coro, import) { if (getsockopt(socket_fd, SOL_SOCKET, SO_DOMAIN, &sock_domain, &sock_domain_len) == 0) { } else #endif - if (getsockname(socket_fd, (struct sockaddr *) &addr, &addr_len) == 0) { + if (getsockname(socket_fd, (struct sockaddr *) &addr, &addr_len) == 0) { sock_domain = addr.ss_family; } else { php_swoole_sys_error(E_WARNING, "getsockname() failed"); @@ -2217,31 +2217,3 @@ static PHP_METHOD(swoole_socket_coro, import) { RETURN_OBJ(object); } - -#ifdef SW_THREAD -static PHP_METHOD(swoole_socket_coro, __wakeup) { - zend_long sockfd = zend::object_get_long(ZEND_THIS, ZEND_STRL("fd")); - if (sockfd < 0) { - zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE); - return; - } - - zend_long new_sockfd = dup(sockfd); - if (sockfd < 0) { - zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE); - return; - } - - SocketObject *sock = (SocketObject *) socket_coro_fetch_object(Z_OBJ_P(ZEND_THIS)); - - zend_long domain = zend::object_get_long(ZEND_THIS, ZEND_STRL("domain")); - zend_long type = zend::object_get_long(ZEND_THIS, ZEND_STRL("type")); - zend_long protocol = zend::object_get_long(ZEND_THIS, ZEND_STRL("protocol")); - - php_swoole_check_reactor(); - sock->socket = new Socket((int) new_sockfd, (int) domain, (int) type, (int) protocol); - sock->socket->set_zero_copy(true); - sock->socket->set_buffer_allocator(sw_zend_string_allocator()); - zend_update_property_long(swoole_socket_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("fd"), sock->socket->get_fd()); -} -#endif diff --git a/ext-src/swoole_thread.cc b/ext-src/swoole_thread.cc index fc20e4fedfd..756192736c2 100644 --- a/ext-src/swoole_thread.cc +++ b/ext-src/swoole_thread.cc @@ -37,6 +37,9 @@ static zend_object_handlers swoole_thread_handlers; zend_class_entry *swoole_thread_stream_ce; static zend_object_handlers swoole_thread_stream_handlers; +zend_class_entry *swoole_thread_socket_ce; +static zend_object_handlers swoole_thread_socket_handlers; + static struct { char *path_translated; zend_string *argv_serialized; @@ -157,6 +160,12 @@ void php_swoole_thread_minit(int module_number) { // only used for thread argument forwarding SW_INIT_CLASS_ENTRY_DATA_OBJECT(swoole_thread_stream, "Swoole\\Thread\\Stream"); zend_declare_property_long(swoole_thread_stream_ce, ZEND_STRL("fd"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); + + SW_INIT_CLASS_ENTRY_DATA_OBJECT(swoole_thread_socket, "Swoole\\Thread\\Socket"); + zend_declare_property_long(swoole_thread_socket_ce, ZEND_STRL("fd"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); + zend_declare_property_long(swoole_thread_socket_ce, ZEND_STRL("domain"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); + zend_declare_property_long(swoole_thread_socket_ce, ZEND_STRL("type"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); + zend_declare_property_long(swoole_thread_socket_ce, ZEND_STRL("protocol"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); } static PHP_METHOD(swoole_thread, __construct) { @@ -206,17 +215,19 @@ static PHP_METHOD(swoole_thread, getId) { RETURN_LONG((zend_long) pthread_self()); } -zend_string *php_swoole_thread_serialize(zval *zdata) { - php_serialize_data_t var_hash; - smart_str serialized_data = {0}; +zend_string *php_swoole_thread_argv_serialize(zval *zdata) { + if (!ZVAL_IS_ARRAY(zdata)) { + return nullptr; + } - if (ZVAL_IS_ARRAY(zdata)) { - zval *elem; - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zdata), elem) { - ZVAL_DEREF(elem); - if (Z_TYPE_P(elem) != IS_RESOURCE) { - continue; - } + zval zdata_copy; + array_init(&zdata_copy); + zend_hash_copy(Z_ARRVAL(zdata_copy), Z_ARRVAL_P(zdata), (copy_ctor_func_t) zval_add_ref); + + zval *elem; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL(zdata_copy), elem) { + ZVAL_DEREF(elem); + if (Z_TYPE_P(elem) == IS_RESOURCE) { int sockfd = php_swoole_thread_stream_fileno(elem); if (sockfd < 0) { continue; @@ -224,9 +235,65 @@ zend_string *php_swoole_thread_serialize(zval *zdata) { zval_ptr_dtor(elem); object_init_ex(elem, swoole_thread_stream_ce); zend_update_property_long(swoole_thread_stream_ce, SW_Z8_OBJ_P(elem), ZEND_STRL("fd"), sockfd); + } else if (Z_TYPE_P(elem) == IS_OBJECT && instanceof_function(Z_OBJCE_P(elem), swoole_socket_coro_ce)) { + zend_long domain = zend::object_get_long(elem, ZEND_STRL("domain")); + zend_long type = zend::object_get_long(elem, ZEND_STRL("type")); + zend_long protocol = zend::object_get_long(elem, ZEND_STRL("protocol")); + zend_long fd = zend::object_get_long(elem, ZEND_STRL("fd")); + int sockfd = dup(fd); + if (sockfd < 0) { + continue; + } + zval_ptr_dtor(elem); + object_init_ex(elem, swoole_thread_socket_ce); + zend_update_property_long(swoole_thread_socket_ce, SW_Z8_OBJ_P(elem), ZEND_STRL("fd"), sockfd); + zend_update_property_long(swoole_thread_socket_ce, SW_Z8_OBJ_P(elem), ZEND_STRL("domain"), domain); + zend_update_property_long(swoole_thread_socket_ce, SW_Z8_OBJ_P(elem), ZEND_STRL("type"), type); + zend_update_property_long(swoole_thread_socket_ce, SW_Z8_OBJ_P(elem), ZEND_STRL("protocol"), protocol); + } + } + ZEND_HASH_FOREACH_END(); + + auto result = php_swoole_serialize(&zdata_copy); + zval_ptr_dtor(&zdata_copy); + return result; +} + +bool php_swoole_thread_argv_unserialize(zend_string *data, zval *zv) { + bool unserialized = php_swoole_unserialize(data, zv); + if (!unserialized) { + return false; + } + + zval *elem; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zv), elem) { + ZVAL_DEREF(elem); + if (Z_TYPE_P(elem) != IS_OBJECT) { + continue; + } + if (instanceof_function(Z_OBJCE_P(elem), swoole_thread_stream_ce)) { + zend_long sockfd = zend::object_get_long(elem, ZEND_STRL("fd")); + zval_ptr_dtor(elem); + zval zstream; + php_swoole_thread_stream_restore(sockfd, &zstream); + ZVAL_COPY(elem, &zstream); + } else if (instanceof_function(Z_OBJCE_P(elem), swoole_thread_socket_ce)) { + zend_long fd = zend::object_get_long(elem, ZEND_STRL("fd")); + zend_long domain = zend::object_get_long(elem, ZEND_STRL("domain")); + zend_long type = zend::object_get_long(elem, ZEND_STRL("type")); + zend_long protocol = zend::object_get_long(elem, ZEND_STRL("protocol")); + auto sockobj = php_swoole_create_socket_from_fd(fd, domain, type, protocol); + zval_ptr_dtor(elem); + ZVAL_OBJ(elem, sockobj); } - ZEND_HASH_FOREACH_END(); } + ZEND_HASH_FOREACH_END(); + return true; +} + +zend_string *php_swoole_serialize(zval *zdata) { + php_serialize_data_t var_hash; + smart_str serialized_data = {0}; PHP_VAR_SERIALIZE_INIT(var_hash); php_var_serialize(&serialized_data, zdata, &var_hash); @@ -237,10 +304,11 @@ zend_string *php_swoole_thread_serialize(zval *zdata) { result = zend_string_init(serialized_data.s->val, serialized_data.s->len, 1); } smart_str_free(&serialized_data); + return result; } -bool php_swoole_thread_unserialize(zend_string *data, zval *zv) { +bool php_swoole_unserialize(zend_string *data, zval *zv) { php_unserialize_data_t var_hash; const char *p = ZSTR_VAL(data); size_t l = ZSTR_LEN(data); @@ -252,26 +320,27 @@ bool php_swoole_thread_unserialize(zend_string *data, zval *zv) { swoole_warning("unserialize() failed, Error at offset " ZEND_LONG_FMT " of %zd bytes", (zend_long) ((char *) p - ZSTR_VAL(data)), l); - } else { - if (ZVAL_IS_ARRAY(zv)) { - zval *elem; - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zv), elem) { - ZVAL_DEREF(elem); - if (Z_TYPE_P(elem) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(elem), swoole_thread_stream_ce)) { - continue; - } - zend_long sockfd = zend::object_get_long(elem, ZEND_STRL("fd")); - zval_ptr_dtor(elem); - zval zstream; - php_swoole_thread_stream_restore(sockfd, &zstream); - ZVAL_COPY(elem, &zstream); - } - ZEND_HASH_FOREACH_END(); - } } return unserialized; } +void php_swoole_thread_argv_dtor(zval *zdata) { + if (!ZVAL_IS_ARRAY(zdata)) { + return; + } + zval *elem; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zdata), elem) { + ZVAL_DEREF(elem); + if (Z_TYPE_P(elem) == IS_OBJECT && (instanceof_function(Z_OBJCE_P(elem), swoole_thread_stream_ce) || + instanceof_function(Z_OBJCE_P(elem), swoole_thread_socket_ce))) { + zend_long sockfd = zend::object_get_long(elem, ZEND_STRL("fd")); + close(sockfd); + } + } + ZEND_HASH_FOREACH_END(); + zval_dtor(zdata); +} + void php_swoole_thread_rinit() { if (tsrm_is_main_thread()) { if (SG(request_info).path_translated) { @@ -280,14 +349,13 @@ void php_swoole_thread_rinit() { // Return reference zval *global_argv = zend_hash_find_ind(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_ARGV)); if (global_argv) { - request_info.argv_serialized = php_swoole_thread_serialize(global_argv); + request_info.argv_serialized = php_swoole_thread_argv_serialize(global_argv); request_info.argc = SG(request_info).argc; } } } void php_swoole_thread_rshutdown() { - zval_dtor(&thread_argv); if (tsrm_is_main_thread()) { if (request_info.path_translated) { free((void *) request_info.path_translated); @@ -363,7 +431,7 @@ static void php_swoole_thread_create(INTERNAL_FUNCTION_PARAMETERS, zval *zobject for (int i = 0; i < argc; i++) { zend::array_add(&zargv, &args[i]); } - zend_string *argv = php_swoole_thread_serialize(&zargv); + zend_string *argv = php_swoole_thread_argv_serialize(&zargv); zval_dtor(&zargv); if (!argv) { @@ -417,10 +485,10 @@ void php_swoole_thread_start(zend_string *file, zend_string *argv_serialized) { if (argv_serialized == nullptr || ZSTR_LEN(argv_serialized) == 0) { array_init(&thread_argv); } else { - php_swoole_thread_unserialize(argv_serialized, &thread_argv); + php_swoole_thread_argv_unserialize(argv_serialized, &thread_argv); } if (request_info.argv_serialized) { - php_swoole_thread_unserialize(request_info.argv_serialized, &global_argv); + php_swoole_thread_argv_unserialize(request_info.argv_serialized, &global_argv); ZVAL_LONG(&global_argc, request_info.argc); zend_hash_update(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_ARGV), &global_argv); zend_hash_update(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_ARGC), &global_argc); @@ -430,6 +498,8 @@ void php_swoole_thread_start(zend_string *file, zend_string *argv_serialized) { } zend_end_try(); + php_swoole_thread_argv_dtor(&thread_argv); + php_swoole_thread_argv_dtor(&global_argv); zend_destroy_file_handle(&file_handle); php_request_shutdown(NULL); @@ -511,8 +581,20 @@ void ArrayItem::store(zval *zvalue) { } } /* no break */ + case IS_OBJECT: { + if (instanceof_function(Z_OBJCE_P(zvalue), swoole_socket_coro_ce)) { + swoole::coroutine::Socket *socket = php_swoole_get_socket(zvalue); + if (socket) { + value.socket.fd = socket->get_fd(); + value.socket.type = socket->get_type(); + type = IS_CO_SOCKET; + break; + } + } + } + /* no break */ default: { - auto _serialized_object = php_swoole_thread_serialize(zvalue); + auto _serialized_object = php_swoole_serialize(zvalue); if (!_serialized_object) { type = IS_UNDEF; break; @@ -545,8 +627,15 @@ void ArrayItem::fetch(zval *return_value) { case IS_STREAM_SOCKET: php_swoole_thread_stream_restore(value.lval, return_value); break; + case IS_CO_SOCKET: { + zend_object *sockobj = php_swoole_create_socket_from_fd(value.socket.fd, value.socket.type); + if (sockobj) { + ZVAL_OBJ(return_value, sockobj); + } + break; + } case IS_SERIALIZED_OBJECT: - php_swoole_thread_unserialize(value.serialized_object, return_value); + php_swoole_unserialize(value.serialized_object, return_value); break; default: break;