diff --git a/examples/thread/nested_map.php b/examples/thread/nested_map.php new file mode 100644 index 00000000000..daa0af5f9c2 --- /dev/null +++ b/examples/thread/nested_map.php @@ -0,0 +1,21 @@ + uniqid(), + 'b' => random_int(1000, 9999), +]; + +var_dump($map['map1']['key1']); +var_dump($map['list1'][0]); + +var_dump($map['list1']->toArray()); + +var_dump($map['map2']); diff --git a/ext-src/php_swoole_cxx.h b/ext-src/php_swoole_cxx.h index f0ce177322f..4947cbdb031 100644 --- a/ext-src/php_swoole_cxx.h +++ b/ext-src/php_swoole_cxx.h @@ -670,6 +670,10 @@ static inline void object_set(zval *obj, const char *name, size_t l_name, const zend_update_property_string(Z_OBJCE_P(obj), Z_OBJ_P(obj), name, l_name, value); } +static inline void object_set(zval *obj, const char *name, size_t l_name, zend_long value) { + zend_update_property_long(Z_OBJCE_P(obj), Z_OBJ_P(obj), name, l_name, value); +} + static inline zval *object_get(zval *obj, const char *name, size_t l_name) { static zval rv; return zend_read_property(Z_OBJCE_P(obj), Z_OBJ_P(obj), name, l_name, 1, &rv); diff --git a/ext-src/php_swoole_thread.h b/ext-src/php_swoole_thread.h index 3a568a4f275..aee0ddd02d2 100644 --- a/ext-src/php_swoole_thread.h +++ b/ext-src/php_swoole_thread.h @@ -25,44 +25,81 @@ typedef uint32_t ThreadResourceId; struct ThreadResource; - -ThreadResourceId php_swoole_thread_resource_insert(ThreadResource *res); -bool php_swoole_thread_resource_free(ThreadResourceId resource_id, ThreadResource *res); -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_argv_serialize(zval *zdata); -bool php_swoole_thread_argv_unserialize(zend_string *data, zval *zv); +struct ZendArray; + +extern zend_class_entry *swoole_thread_ce; +extern zend_class_entry *swoole_thread_error_ce; +extern zend_class_entry *swoole_thread_arraylist_ce; +extern zend_class_entry *swoole_thread_atomic_ce; +extern zend_class_entry *swoole_thread_atomic_long_ce; +extern zend_class_entry *swoole_thread_barrier_ce; +extern zend_class_entry *swoole_thread_lock_ce; +extern zend_class_entry *swoole_thread_map_ce; +extern zend_class_entry *swoole_thread_queue_ce; + +void php_swoole_thread_start(zend_string *file, ZendArray *argv); zend_string *php_swoole_serialize(zval *zdata); bool php_swoole_unserialize(zend_string *data, zval *zv); -void php_swoole_thread_argv_clean(zval *zdata); void php_swoole_thread_bailout(void); -zval *php_swoole_thread_get_arguments(); +ThreadResource *php_swoole_thread_arraylist_cast(zval *zobject); +ThreadResource *php_swoole_thread_map_cast(zval *zobject); +ThreadResource *php_swoole_thread_queue_cast(zval *zobject); +ThreadResource *php_swoole_thread_lock_cast(zval *zobject); +ThreadResource *php_swoole_thread_atomic_cast(zval *zobject); +ThreadResource *php_swoole_thread_atomic_long_cast(zval *zobject); +ThreadResource *php_swoole_thread_barrier_cast(zval *zobject); + +void php_swoole_thread_arraylist_create(zval *return_value, ThreadResource *resource); +void php_swoole_thread_map_create(zval *return_value, ThreadResource *resource); +void php_swoole_thread_queue_create(zval *return_value, ThreadResource *resource); +void php_swoole_thread_lock_create(zval *return_value, ThreadResource *resource); +void php_swoole_thread_atomic_create(zval *return_value, ThreadResource *resource); +void php_swoole_thread_atomic_long_create(zval *return_value, ThreadResource *resource); +void php_swoole_thread_barrier_create(zval *return_value, ThreadResource *resource); + +int php_swoole_thread_stream_cast(zval *zstream); +void php_swoole_thread_stream_create(zval *return_value, zend_long sockfd); + +int php_swoole_thread_co_socket_cast(zval *zstream, swSocketType *type); +void php_swoole_thread_co_socket_create(zval *return_value, zend_long sockfd, swSocketType type); #define EMSG_NO_RESOURCE "resource not found" #define ECODE_NO_RESOURCE -2 enum { + IS_ARRAYLIST = 80, + IS_QUEUE = 81, + IS_LOCK = 82, + IS_MAP = 83, + IS_BARRIER = 84, + IS_ATOMIC = 85, + IS_ATOMIC_LONG = 86, IS_CO_SOCKET = 97, IS_STREAM_SOCKET = 98, IS_SERIALIZED_OBJECT = 99, }; -struct ThreadResource { - uint32_t ref_count; +class ThreadResource { + sw_atomic_t ref_count; + public: ThreadResource() { ref_count = 1; } - uint32_t add_ref() { - return ++ref_count; + void add_ref() { + sw_atomic_add_fetch(&ref_count, 1); } - uint32_t del_ref() { - return --ref_count; + void del_ref() { + if (sw_atomic_sub_fetch(&ref_count, 1) == 0) { + delete this; + } } + + protected: + virtual ~ThreadResource() {} }; struct ArrayItem { @@ -77,6 +114,7 @@ struct ArrayItem { swSocketType type; } socket; zend_string *serialized_object; + ThreadResource *resource; } value; ArrayItem(zval *zvalue) { @@ -88,6 +126,10 @@ struct ArrayItem { key = zend_string_init(_key.val(), _key.len(), 1); } + void setKey(zend_string *_key) { + key = zend_string_init(ZSTR_VAL(_key), ZSTR_LEN(_key), 1); + } + void store(zval *zvalue); void fetch(zval *return_value); void release(); @@ -115,7 +157,7 @@ struct ZendArray : ThreadResource { zend_hash_init(&ht, 0, NULL, item_dtor, 1); } - ~ZendArray() { + ~ZendArray() override { zend_hash_destroy(&ht); } @@ -125,6 +167,25 @@ struct ZendArray : ThreadResource { lock_.unlock(); } + void append(zval *zvalue); + + void add(zend_string *skey, zval *zvalue) { + auto item = new ArrayItem(zvalue); + item->setKey(skey); + zend_hash_add_ptr(&ht, item->key, item); + } + + void add(zend::String &skey, zval *zvalue) { + auto item = new ArrayItem(zvalue); + item->setKey(skey); + zend_hash_add_ptr(&ht, item->key, item); + } + + void add(zend_long index, zval *zvalue) { + auto item = new ArrayItem(zvalue); + zend_hash_index_add_ptr(&ht, index, item); + } + bool index_exists(zend_long index) { return index < (zend_long) zend_hash_num_elements(&ht); } @@ -189,6 +250,8 @@ struct ZendArray : ThreadResource { } void keys(zval *return_value); + void values(zval *return_value); + void toArray(zval *return_value); void intkey_offsetGet(zend_long index, zval *return_value) { lock_.lock_rd(); @@ -251,6 +314,7 @@ struct ZendArray : ThreadResource { static void incr_update(ArrayItem *item, zval *zvalue, zval *return_value); static ArrayItem *incr_create(zval *zvalue, zval *return_value); + static ZendArray *from(zend_array *ht); }; #define INIT_ARRAY_INCR_PARAMS \ diff --git a/ext-src/stubs/php_swoole_thread.stub.php b/ext-src/stubs/php_swoole_thread.stub.php index a6617fb67b6..88df2d46c40 100644 --- a/ext-src/stubs/php_swoole_thread.stub.php +++ b/ext-src/stubs/php_swoole_thread.stub.php @@ -8,7 +8,7 @@ public function join(): bool {} public function joinable(): bool {} public function detach(): bool {} - public static function getArguments(): array {} + public static function getArguments(): ?array {} public static function getId(): int {} public static function getTsrmInfo(): array {} } diff --git a/ext-src/stubs/php_swoole_thread_arginfo.h b/ext-src/stubs/php_swoole_thread_arginfo.h index 02f0a7c4a0f..12e7e6d3262 100644 --- a/ext-src/stubs/php_swoole_thread_arginfo.h +++ b/ext-src/stubs/php_swoole_thread_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 234aeadaab2ab31facf1909f0e3027e433f2a88f */ + * Stub hash: 261ac9fd29d4f2f37118ff3b96428a0b2f85223a */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Swoole_Thread___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, script_file, IS_STRING, 0) @@ -13,10 +13,11 @@ ZEND_END_ARG_INFO() #define arginfo_class_Swoole_Thread_detach arginfo_class_Swoole_Thread_join -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Thread_getArguments, 0, 0, IS_ARRAY, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Thread_getArguments, 0, 0, IS_ARRAY, 1) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Thread_getId, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() -#define arginfo_class_Swoole_Thread_getTsrmInfo arginfo_class_Swoole_Thread_getArguments +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Thread_getTsrmInfo, 0, 0, IS_ARRAY, 0) +ZEND_END_ARG_INFO() diff --git a/ext-src/stubs/php_swoole_thread_arraylist.stub.php b/ext-src/stubs/php_swoole_thread_arraylist.stub.php index 29f7f3375d2..ad44d417850 100644 --- a/ext-src/stubs/php_swoole_thread_arraylist.stub.php +++ b/ext-src/stubs/php_swoole_thread_arraylist.stub.php @@ -1,7 +1,7 @@ chan; if (UNEXPECTED(!chan)) { - php_swoole_fatal_error(E_ERROR, "you must call Channel constructor first"); + swoole_fatal_error(SW_ERROR_WRONG_OPERATION, "must call constructor first"); } return chan; } diff --git a/ext-src/swoole_http_client_coro.cc b/ext-src/swoole_http_client_coro.cc index 4746b332bf6..8ea9ee85959 100644 --- a/ext-src/swoole_http_client_coro.cc +++ b/ext-src/swoole_http_client_coro.cc @@ -1638,7 +1638,7 @@ static sw_inline HttpClientObject *http_client_coro_fetch_object(zend_object *ob static sw_inline Client *http_client_coro_get_client(zval *zobject) { Client *phc = http_client_coro_fetch_object(Z_OBJ_P(zobject))->client; if (UNEXPECTED(!phc)) { - php_swoole_fatal_error(E_ERROR, "you must call Http Client constructor first"); + swoole_fatal_error(SW_ERROR_WRONG_OPERATION, "must call constructor first"); } return phc; } diff --git a/ext-src/swoole_lock.cc b/ext-src/swoole_lock.cc index 902dcf79535..36dc18f5ade 100644 --- a/ext-src/swoole_lock.cc +++ b/ext-src/swoole_lock.cc @@ -49,8 +49,8 @@ static Lock *php_swoole_lock_get_ptr(zval *zobject) { static Lock *php_swoole_lock_get_and_check_ptr(zval *zobject) { Lock *lock = php_swoole_lock_get_ptr(zobject); - if (!lock) { - php_swoole_fatal_error(E_ERROR, "must call constructor first"); + if (UNEXPECTED(!lock)) { + swoole_fatal_error(SW_ERROR_WRONG_OPERATION, "must call constructor first"); } return lock; } diff --git a/ext-src/swoole_name_resolver.cc b/ext-src/swoole_name_resolver.cc index 2a9e1584e2f..8c3b61ec727 100644 --- a/ext-src/swoole_name_resolver.cc +++ b/ext-src/swoole_name_resolver.cc @@ -44,8 +44,8 @@ static zend_always_inline ContextObject *swoole_name_resolver_context_get_object static zend_always_inline ContextObject *swoole_name_resolver_context_get_object_safe(zend_object *object) { NameResolver::Context *name_resolver_context = swoole_name_resolver_context_get_handle(object); - if (!name_resolver_context) { - php_swoole_fatal_error(E_ERROR, "must call name_resolver_context constructor first"); + if (UNEXPECTED(!name_resolver_context)) { + swoole_fatal_error(SW_ERROR_WRONG_OPERATION, "must call constructor first"); } return swoole_name_resolver_context_get_object(object); } diff --git a/ext-src/swoole_process.cc b/ext-src/swoole_process.cc index 667ffcc1cf8..7bfac0af358 100644 --- a/ext-src/swoole_process.cc +++ b/ext-src/swoole_process.cc @@ -51,8 +51,8 @@ Worker *php_swoole_process_get_worker(zval *zobject) { Worker *php_swoole_process_get_and_check_worker(zval *zobject) { Worker *worker = php_swoole_process_get_worker(zobject); - if (!worker) { - php_swoole_fatal_error(E_ERROR, "must call constructor first"); + if (UNEXPECTED(!worker)) { + swoole_fatal_error(SW_ERROR_WRONG_OPERATION, "must call constructor first"); } return worker; } diff --git a/ext-src/swoole_process_pool.cc b/ext-src/swoole_process_pool.cc index f14004f8ff1..3a79859c534 100644 --- a/ext-src/swoole_process_pool.cc +++ b/ext-src/swoole_process_pool.cc @@ -58,8 +58,8 @@ static sw_inline ProcessPool *process_pool_get_pool(zval *zobject) { static sw_inline ProcessPool *process_pool_get_and_check_pool(zval *zobject) { ProcessPool *pool = process_pool_get_pool(zobject); - if (!pool) { - php_swoole_fatal_error(E_ERROR, "you must call Process\\Pool constructor first"); + if (UNEXPECTED(!pool)) { + swoole_fatal_error(SW_ERROR_WRONG_OPERATION, "must call constructor first"); } return pool; } diff --git a/ext-src/swoole_server.cc b/ext-src/swoole_server.cc index 2d90a08b2f1..cf070668373 100644 --- a/ext-src/swoole_server.cc +++ b/ext-src/swoole_server.cc @@ -2642,23 +2642,26 @@ static PHP_METHOD(swoole_server, start) { #ifdef SW_THREAD zend_string *bootstrap = nullptr; - zend_string *thread_argv_serialized = nullptr; - zval thread_argv = {}; + ZendArray *thread_argv = nullptr; if (serv->is_thread_mode()) { zval *_bootstrap = zend::object_get(ZEND_THIS, ZEND_STRL("bootstrap")); bootstrap = zend_string_dup(Z_STR_P(_bootstrap), 1); 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_argv_serialize(&thread_argv); + zval _thread_argv; + call_user_function(NULL, NULL, &server_object->init_arguments, &_thread_argv, 0, NULL); + if (ZVAL_IS_ARRAY(&_thread_argv)) { + thread_argv = ZendArray::from(Z_ARRVAL(_thread_argv)); + } + zval_ptr_dtor(&_thread_argv); } - serv->worker_thread_start = [bootstrap, thread_argv_serialized](const WorkerFn &fn) { + serv->worker_thread_start = [bootstrap, thread_argv](const WorkerFn &fn) { worker_thread_fn = fn; zend_string *bootstrap_copy = zend_string_dup(bootstrap, 1); - zend_string *argv_copy = thread_argv_serialized ? zend_string_dup(thread_argv_serialized, 1) : nullptr; - php_swoole_thread_start(bootstrap_copy, argv_copy); + thread_argv->add_ref(); + php_swoole_thread_start(bootstrap_copy, thread_argv); }; } #endif @@ -2674,10 +2677,9 @@ static PHP_METHOD(swoole_server, start) { if (bootstrap) { zend_string_release(bootstrap); } - if (thread_argv_serialized) { - zend_string_release(thread_argv_serialized); + if (thread_argv) { + thread_argv->del_ref(); } - zval_ptr_dtor(&thread_argv); #endif RETURN_TRUE; diff --git a/ext-src/swoole_socket_coro.cc b/ext-src/swoole_socket_coro.cc index 288051522f6..8fb21478809 100644 --- a/ext-src/swoole_socket_coro.cc +++ b/ext-src/swoole_socket_coro.cc @@ -136,7 +136,7 @@ static const zend_function_entry swoole_socket_coro_methods[] = #define swoole_get_socket_coro(_sock, _zobject) \ SocketObject *_sock = socket_coro_fetch_object(Z_OBJ_P(_zobject)); \ if (UNEXPECTED(!sock->socket)) { \ - php_swoole_fatal_error(E_ERROR, "you must call Socket constructor first"); \ + swoole_fatal_error(SW_ERROR_WRONG_OPERATION, "must call constructor first"); \ } \ if (UNEXPECTED(_sock->socket->is_closed())) { \ zend_update_property_long(swoole_socket_coro_ce, SW_Z8_OBJ_P(_zobject), ZEND_STRL("errCode"), EBADF); \ diff --git a/ext-src/swoole_table.cc b/ext-src/swoole_table.cc index 585faa63839..5211f514c35 100644 --- a/ext-src/swoole_table.cc +++ b/ext-src/swoole_table.cc @@ -91,8 +91,8 @@ static inline Table *php_swoole_table_get_ptr(zval *zobject) { static inline Table *php_swoole_table_get_and_check_ptr(zval *zobject) { Table *table = php_swoole_table_get_ptr(zobject); - if (!table) { - php_swoole_fatal_error(E_ERROR, "you must call Table constructor first"); + if (UNEXPECTED(!table)) { + swoole_fatal_error(SW_ERROR_WRONG_OPERATION, "must call constructor first"); } return table; } diff --git a/ext-src/swoole_thread.cc b/ext-src/swoole_thread.cc index b3730fce62a..1cd9d51ef01 100644 --- a/ext-src/swoole_thread.cc +++ b/ext-src/swoole_thread.cc @@ -34,11 +34,8 @@ END_EXTERN_C() zend_class_entry *swoole_thread_ce; 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; +zend_class_entry *swoole_thread_error_ce; +static zend_object_handlers swoole_thread_error_handlers; static struct { char *path_translated; @@ -56,54 +53,21 @@ struct ThreadObject { }; static void php_swoole_thread_join(zend_object *object); -static void php_swoole_thread_create(INTERNAL_FUNCTION_PARAMETERS, zval *zobject); -static int php_swoole_thread_stream_fileno(zval *zstream); -static bool php_swoole_thread_stream_restore(zend_long sockfd, zval *return_value); static void php_swoole_thread_register_stdio_file_handles(bool no_close); -static thread_local zval thread_argv; +static thread_local zval thread_argv = {}; static thread_local JMP_BUF *thread_bailout = nullptr; -static zend_long thread_resource_id = 0; -static std::unordered_map thread_resources; - -ThreadResourceId php_swoole_thread_resource_insert(ThreadResource *res) { - std::unique_lock _lock(sw_thread_lock); - zend_long resource_id = ++thread_resource_id; - thread_resources[resource_id] = res; - return resource_id; -} - -ThreadResource *php_swoole_thread_resource_fetch(ThreadResourceId resource_id) { - ThreadResource *res = nullptr; - std::unique_lock _lock(sw_thread_lock); - auto iter = thread_resources.find(resource_id); - if (iter != thread_resources.end()) { - res = iter->second; - res->add_ref(); - } - return res; -} -bool php_swoole_thread_resource_free(ThreadResourceId resource_id, ThreadResource *res) { - std::unique_lock _lock(sw_thread_lock); - if (res->del_ref() == 0) { - thread_resources.erase(resource_id); - return true; - } else { - return false; - } -} - -static sw_inline ThreadObject *php_swoole_thread_fetch_object(zend_object *obj) { +static sw_inline ThreadObject *thread_fetch_object(zend_object *obj) { return (ThreadObject *) ((char *) obj - swoole_thread_handlers.offset); } -static void php_swoole_thread_free_object(zend_object *object) { +static void thread_free_object(zend_object *object) { php_swoole_thread_join(object); zend_object_std_dtor(object); } -static zend_object *php_swoole_thread_create_object(zend_class_entry *ce) { +static zend_object *thread_create_object(zend_class_entry *ce) { ThreadObject *to = (ThreadObject *) zend_object_alloc(sizeof(ThreadObject), ce); zend_object_std_init(&to->std, ce); object_properties_init(&to->std, ce); @@ -112,7 +76,7 @@ static zend_object *php_swoole_thread_create_object(zend_class_entry *ce) { } static void php_swoole_thread_join(zend_object *object) { - ThreadObject *to = php_swoole_thread_fetch_object(object); + ThreadObject *to = thread_fetch_object(object); if (to->thread && to->thread->joinable()) { to->thread->join(); delete to->thread; @@ -125,7 +89,6 @@ static PHP_METHOD(swoole_thread, __construct); static PHP_METHOD(swoole_thread, join); static PHP_METHOD(swoole_thread, joinable); static PHP_METHOD(swoole_thread, detach); -static PHP_METHOD(swoole_thread, exec); static PHP_METHOD(swoole_thread, getArguments); static PHP_METHOD(swoole_thread, getId); static PHP_METHOD(swoole_thread, getTsrmInfo); @@ -146,33 +109,59 @@ static const zend_function_entry swoole_thread_methods[] = { void php_swoole_thread_minit(int module_number) { SW_INIT_CLASS_ENTRY(swoole_thread, "Swoole\\Thread", nullptr, swoole_thread_methods); - SW_SET_CLASS_NOT_SERIALIZABLE(swoole_thread); + swoole_thread_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NOT_SERIALIZABLE; SW_SET_CLASS_CLONEABLE(swoole_thread, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_thread, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT( - swoole_thread, php_swoole_thread_create_object, php_swoole_thread_free_object, ThreadObject, std); + swoole_thread, thread_create_object, thread_free_object, ThreadObject, std); zend_declare_property_long(swoole_thread_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); zend_declare_class_constant_long( swoole_thread_ce, ZEND_STRL("HARDWARE_CONCURRENCY"), std::thread::hardware_concurrency()); - // 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); + SW_INIT_CLASS_ENTRY_DATA_OBJECT(swoole_thread_error, "Swoole\\Thread\\Error"); + zend_declare_property_long(swoole_thread_error_ce, ZEND_STRL("code"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); } static PHP_METHOD(swoole_thread, __construct) { - php_swoole_thread_create(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_THIS); + char *script_file; + size_t l_script_file; + zval *args; + int argc; + ZendArray *argv = nullptr; + + ZEND_PARSE_PARAMETERS_START(1, -1) + Z_PARAM_STRING(script_file, l_script_file) + Z_PARAM_VARIADIC('+', args, argc) + ZEND_PARSE_PARAMETERS_END(); + + if (l_script_file < 1) { + zend_throw_exception(swoole_exception_ce, "exec file name is empty", SW_ERROR_INVALID_PARAMS); + return; + } + + ThreadObject *to = thread_fetch_object(Z_OBJ_P(ZEND_THIS)); + zend_string *file = zend_string_init(script_file, l_script_file, 1); + + if (argc > 0) { + argv = new ZendArray(); + for (int i = 0; i < argc; i++) { + argv->append(&args[i]); + } + } + + try { + to->thread = new std::thread([file, argv]() { php_swoole_thread_start(file, argv); }); + } catch (const std::exception &e) { + zend_throw_exception(swoole_exception_ce, e.what(), SW_ERROR_SYSTEM_CALL_FAIL); + return; + } + zend_update_property_long( + swoole_thread_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), (zend_long) to->thread->native_handle()); } static PHP_METHOD(swoole_thread, join) { - ThreadObject *to = php_swoole_thread_fetch_object(Z_OBJ_P(ZEND_THIS)); + ThreadObject *to = thread_fetch_object(Z_OBJ_P(ZEND_THIS)); if (!to || !to->thread || !to->thread->joinable()) { RETURN_FALSE; } @@ -181,7 +170,7 @@ static PHP_METHOD(swoole_thread, join) { } static PHP_METHOD(swoole_thread, joinable) { - ThreadObject *to = php_swoole_thread_fetch_object(Z_OBJ_P(ZEND_THIS)); + ThreadObject *to = thread_fetch_object(Z_OBJ_P(ZEND_THIS)); if (to == nullptr || !to->thread) { RETURN_FALSE; } @@ -189,7 +178,7 @@ static PHP_METHOD(swoole_thread, joinable) { } static PHP_METHOD(swoole_thread, detach) { - ThreadObject *to = php_swoole_thread_fetch_object(Z_OBJ_P(ZEND_THIS)); + ThreadObject *to = thread_fetch_object(Z_OBJ_P(ZEND_THIS)); if (to == nullptr || !to->thread) { RETURN_FALSE; } @@ -199,97 +188,16 @@ static PHP_METHOD(swoole_thread, detach) { RETURN_TRUE; } -zval *php_swoole_thread_get_arguments() { - if (!ZVAL_IS_ARRAY(&thread_argv)) { - array_init(&thread_argv); - } - return &thread_argv; -} - static PHP_METHOD(swoole_thread, getArguments) { - RETURN_ZVAL(php_swoole_thread_get_arguments(), 1, 0); + if (Z_TYPE(thread_argv) == IS_ARRAY) { + RETURN_ZVAL(&thread_argv, 1, 0); + } } static PHP_METHOD(swoole_thread, getId) { RETURN_LONG((zend_long) pthread_self()); } -zend_string *php_swoole_thread_argv_serialize(zval *zdata) { - if (!ZVAL_IS_ARRAY(zdata)) { - return nullptr; - } - - 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; - } - 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(); - return true; -} - zend_string *php_swoole_serialize(zval *zdata) { php_serialize_data_t var_hash; smart_str serialized_data = {0}; @@ -322,22 +230,6 @@ bool php_swoole_unserialize(zend_string *data, zval *zv) { return unserialized; } -void php_swoole_thread_argv_clean(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(); -} - void php_swoole_thread_rinit() { if (tsrm_is_main_thread()) { if (SG(request_info).path_translated) { @@ -346,7 +238,7 @@ 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_argv_serialize(global_argv); + request_info.argv_serialized = php_swoole_serialize(global_argv); request_info.argc = SG(request_info).argc; } } @@ -405,49 +297,7 @@ static void php_swoole_thread_register_stdio_file_handles(bool no_close) { zend_register_constant(&ec); } -static void php_swoole_thread_create(INTERNAL_FUNCTION_PARAMETERS, zval *zobject) { - char *script_file; - size_t l_script_file; - zval *args; - int argc; - - ZEND_PARSE_PARAMETERS_START(1, -1) - Z_PARAM_STRING(script_file, l_script_file) - Z_PARAM_VARIADIC('+', args, argc) - ZEND_PARSE_PARAMETERS_END(); - - if (l_script_file < 1) { - zend_throw_exception(swoole_exception_ce, "exec file name is empty", SW_ERROR_INVALID_PARAMS); - return; - } - - ThreadObject *to = php_swoole_thread_fetch_object(Z_OBJ_P(zobject)); - zend_string *file = zend_string_init(script_file, l_script_file, 1); - - zval zargv; - array_init(&zargv); - for (int i = 0; i < argc; i++) { - zend::array_add(&zargv, &args[i]); - } - zend_string *argv = php_swoole_thread_argv_serialize(&zargv); - zval_dtor(&zargv); - - if (!argv) { - zend_string_release(file); - return; - } - - try { - to->thread = new std::thread([file, argv]() { php_swoole_thread_start(file, argv); }); - } catch (const std::exception &e) { - zend_throw_exception(swoole_exception_ce, e.what(), SW_ERROR_SYSTEM_CALL_FAIL); - return; - } - zend_update_property_long( - swoole_thread_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("id"), (zend_long) to->thread->native_handle()); -} - -void php_swoole_thread_start(zend_string *file, zend_string *argv_serialized) { +void php_swoole_thread_start(zend_string *file, ZendArray *argv) { ts_resource(0); #if defined(COMPILE_DL_SWOOLE) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); @@ -482,24 +332,21 @@ void php_swoole_thread_start(zend_string *file, zend_string *argv_serialized) { zend_first_try { thread_bailout = EG(bailout); - if (argv_serialized == nullptr || ZSTR_LEN(argv_serialized) == 0) { - array_init(&thread_argv); - } else { - php_swoole_thread_argv_unserialize(argv_serialized, &thread_argv); - } if (request_info.argv_serialized) { - php_swoole_thread_argv_unserialize(request_info.argv_serialized, &global_argv); + php_swoole_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); } + if (argv) { + argv->toArray(&thread_argv); + argv->del_ref(); + } php_swoole_thread_register_stdio_file_handles(true); php_execute_script(&file_handle); } zend_end_try(); - php_swoole_thread_argv_clean(&thread_argv); - php_swoole_thread_argv_clean(&global_argv); zend_destroy_file_handle(&file_handle); php_request_shutdown(NULL); @@ -507,9 +354,6 @@ void php_swoole_thread_start(zend_string *file, zend_string *argv_serialized) { _startup_error: zend_string_release(file); - if (argv_serialized) { - zend_string_release(argv_serialized); - } ts_free_thread(); swoole_thread_clean(); } @@ -521,7 +365,7 @@ void php_swoole_thread_bailout(void) { } } -static int php_swoole_thread_stream_fileno(zval *zstream) { +int php_swoole_thread_stream_cast(zval *zstream) { php_stream *stream; int sockfd; int cast_flags = PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL; @@ -533,20 +377,49 @@ static int php_swoole_thread_stream_fileno(zval *zstream) { return -1; } -static bool php_swoole_thread_stream_restore(zend_long sockfd, zval *return_value) { +int php_swoole_thread_co_socket_cast(zval *zvalue, swSocketType *type) { + swoole::coroutine::Socket *socket = php_swoole_get_socket(zvalue); + if (!socket) { + return -1; + } + int sockfd = socket->get_fd(); + if (sockfd < 0) { + return -1; + } + int newfd = dup(sockfd); + if (newfd < 0) { + return -1; + } + *type = socket->get_type(); + return newfd; +} + +void php_swoole_thread_stream_create(zval *return_value, zend_long sockfd) { std::string path = "php://fd/" + std::to_string(sockfd); // The file descriptor will be duplicated once here php_stream *stream = php_stream_open_wrapper_ex(path.c_str(), "", 0, NULL, NULL); if (stream) { php_stream_to_zval(stream, return_value); - return true; + } else { + object_init_ex(return_value, swoole_thread_error_ce); + zend::object_set(return_value, ZEND_STRL("code"), errno); } - return false; } -static PHP_METHOD(swoole_thread, exec) { - object_init_ex(return_value, swoole_thread_ce); - php_swoole_thread_create(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value); +void php_swoole_thread_co_socket_create(zval *return_value, zend_long sockfd, swSocketType type) { + int newfd = dup(sockfd); + if (newfd < 0) { + object_init_ex(return_value, swoole_thread_error_ce); + zend::object_set(return_value, ZEND_STRL("code"), errno); + return; + } + zend_object *sockobj = php_swoole_create_socket_from_fd(newfd, type); + if (sockobj) { + ZVAL_OBJ(return_value, sockobj); + } else { + // never here + abort(); + } } static PHP_METHOD(swoole_thread, getTsrmInfo) { @@ -556,6 +429,14 @@ static PHP_METHOD(swoole_thread, getTsrmInfo) { add_assoc_string(return_value, "api_name", tsrm_api_name()); } +#define CAST_OBJ_TO_RESOURCE(_name, _type) \ + else if (instanceof_function(Z_OBJCE_P(zvalue), swoole_thread_##_name##_ce)) { \ + value.resource = php_swoole_thread_##_name##_cast(zvalue); \ + value.resource->add_ref(); \ + type = _type; \ + break; \ + } + void ArrayItem::store(zval *zvalue) { type = Z_TYPE_P(zvalue); switch (type) { @@ -574,31 +455,34 @@ void ArrayItem::store(zval *zvalue) { case IS_NULL: break; case IS_RESOURCE: { - int sock_fd = php_swoole_thread_stream_fileno(zvalue); - if (sock_fd != -1) { - value.socket.fd = sock_fd; - type = IS_STREAM_SOCKET; - break; + value.socket.fd = php_swoole_thread_stream_cast(zvalue); + type = IS_STREAM_SOCKET; + if (value.socket.fd == -1) { + zend_throw_exception(swoole_exception_ce, "failed to convert to socket fd", errno); } + break; + } + case IS_ARRAY: { + type = zend_array_is_list(Z_ARRVAL_P(zvalue)) ? IS_ARRAYLIST : IS_MAP; + value.resource = ZendArray::from(Z_ARRVAL_P(zvalue)); + break; } - /* 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) { - int sockfd = socket->get_fd(); - if (sockfd < 0) { - break; - } - value.socket.fd = dup(sockfd); - if (value.socket.fd < 0) { - break; - } - value.socket.type = socket->get_type(); - type = IS_CO_SOCKET; - break; + value.socket.fd = php_swoole_thread_co_socket_cast(zvalue, &value.socket.type); + type = IS_CO_SOCKET; + if (value.socket.fd == -1) { + zend_throw_exception(swoole_exception_ce, "failed to convert to socket fd", errno); } + break; } + CAST_OBJ_TO_RESOURCE(arraylist, IS_ARRAYLIST) + CAST_OBJ_TO_RESOURCE(map, IS_MAP) + CAST_OBJ_TO_RESOURCE(queue, IS_QUEUE) + CAST_OBJ_TO_RESOURCE(lock, IS_LOCK) + CAST_OBJ_TO_RESOURCE(atomic, IS_ATOMIC) + CAST_OBJ_TO_RESOURCE(atomic_long, IS_ATOMIC_LONG) + CAST_OBJ_TO_RESOURCE(barrier, IS_BARRIER) } /* no break */ default: { @@ -632,20 +516,40 @@ void ArrayItem::fetch(zval *return_value) { case IS_STRING: RETVAL_NEW_STR(zend_string_init(ZSTR_VAL(value.str), ZSTR_LEN(value.str), 0)); break; + case IS_ARRAYLIST: + value.resource->add_ref(); + php_swoole_thread_arraylist_create(return_value, value.resource); + break; + case IS_QUEUE: + value.resource->add_ref(); + php_swoole_thread_queue_create(return_value, value.resource); + break; + case IS_LOCK: + value.resource->add_ref(); + php_swoole_thread_lock_create(return_value, value.resource); + break; + case IS_MAP: + value.resource->add_ref(); + php_swoole_thread_map_create(return_value, value.resource); + break; + case IS_BARRIER: + value.resource->add_ref(); + php_swoole_thread_barrier_create(return_value, value.resource); + break; + case IS_ATOMIC: + value.resource->add_ref(); + php_swoole_thread_atomic_create(return_value, value.resource); + break; + case IS_ATOMIC_LONG: + value.resource->add_ref(); + php_swoole_thread_atomic_long_create(return_value, value.resource); + break; case IS_STREAM_SOCKET: - php_swoole_thread_stream_restore(value.socket.fd, return_value); + php_swoole_thread_stream_create(return_value, value.socket.fd); break; - case IS_CO_SOCKET: { - int sockfd = dup(value.socket.fd); - if (sockfd < 0) { - break; - } - zend_object *sockobj = php_swoole_create_socket_from_fd(sockfd, value.socket.type); - if (sockobj) { - ZVAL_OBJ(return_value, sockobj); - } + case IS_CO_SOCKET: + php_swoole_thread_co_socket_create(return_value, value.socket.fd, value.socket.type); break; - } case IS_SERIALIZED_OBJECT: php_swoole_unserialize(value.serialized_object, return_value); break; @@ -664,6 +568,9 @@ void ArrayItem::release() { } else if (type == IS_SERIALIZED_OBJECT) { zend_string_release(value.serialized_object); value.serialized_object = nullptr; + } else if (type >= IS_ARRAYLIST && type <= IS_ATOMIC_LONG) { + value.resource->del_ref(); + value.resource = nullptr; } } @@ -743,9 +650,7 @@ void ZendArray::strkey_add(zval *zkey, zval *zvalue, zval *return_value) { if (strkey_exists(skey)) { RETVAL_FALSE; } else { - auto item = new ArrayItem(zvalue); - item->setKey(skey); - zend_hash_update_ptr(&ht, item->key, item); + add(skey, zvalue); RETVAL_TRUE; } lock_.unlock(); @@ -757,8 +662,7 @@ void ZendArray::intkey_add(zval *zkey, zval *zvalue, zval *return_value) { if (intkey_exists(index)) { RETVAL_FALSE; } else { - auto item = new ArrayItem(zvalue); - zend_hash_index_update_ptr(&ht, index, item); + add(index, zvalue); RETVAL_TRUE; } lock_.unlock(); @@ -808,6 +712,10 @@ bool ZendArray::index_offsetSet(zval *zkey, zval *zvalue) { return success; } +void ZendArray::append(zval *zvalue) { + zend_hash_next_index_insert_ptr(&ht, new ArrayItem(zvalue)); +} + bool ZendArray::index_incr(zval *zkey, zval *zvalue, zval *return_value) { zend_long index = ZVAL_IS_NULL(zkey) ? -1 : zval_get_long(zkey); @@ -866,4 +774,57 @@ void ZendArray::keys(zval *return_value) { lock_.unlock(); } +void ZendArray::values(zval *return_value) { + lock_.lock_rd(); + zend_ulong elem_count = zend_hash_num_elements(&ht); + array_init_size(return_value, elem_count); + void *tmp; + ZEND_HASH_FOREACH_PTR(&ht, tmp) { + zval value; + ArrayItem *item = (ArrayItem *) tmp; + item->fetch(&value); + zend_hash_next_index_insert_new(Z_ARR_P(return_value), &value); + } + ZEND_HASH_FOREACH_END(); + lock_.unlock(); +} + +void ZendArray::toArray(zval *return_value) { + lock_.lock_rd(); + zend_ulong elem_count = zend_hash_num_elements(&ht); + array_init_size(return_value, elem_count); + zend_string *key; + zend_ulong index; + void *tmp; + ZEND_HASH_FOREACH_KEY_PTR(&ht, index, key, tmp) { + zval value; + ArrayItem *item = (ArrayItem *) tmp; + item->fetch(&value); + if (key) { + zend_hash_add(Z_ARR_P(return_value), key, &value); + } else { + zend_hash_index_add(Z_ARR_P(return_value), index, &value); + } + } + ZEND_HASH_FOREACH_END(); + lock_.unlock(); +} + +ZendArray *ZendArray::from(zend_array *src) { + zend_string *key; + zend_ulong index; + zval *tmp; + ZendArray *result = new ZendArray(); + ZEND_HASH_FOREACH_KEY_VAL(src, index, key, tmp) { + ZVAL_DEREF(tmp); + if (key) { + result->add(key, tmp); + } else { + result->add(index, tmp); + } + } + ZEND_HASH_FOREACH_END(); + return result; +} + #endif diff --git a/ext-src/swoole_thread_arraylist.cc b/ext-src/swoole_thread_arraylist.cc index 3eb0b667dea..7858a81a515 100644 --- a/ext-src/swoole_thread_arraylist.cc +++ b/ext-src/swoole_thread_arraylist.cc @@ -41,33 +41,23 @@ static PHP_METHOD(swoole_thread_arraylist, count); static PHP_METHOD(swoole_thread_arraylist, incr); static PHP_METHOD(swoole_thread_arraylist, decr); static PHP_METHOD(swoole_thread_arraylist, clean); -static PHP_METHOD(swoole_thread_arraylist, __wakeup); +static PHP_METHOD(swoole_thread_arraylist, toArray); SW_EXTERN_C_END -static sw_inline ThreadArrayListObject *thread_arraylist_fetch_object(zend_object *obj) { +static sw_inline ThreadArrayListObject *arraylist_fetch_object(zend_object *obj) { return (ThreadArrayListObject *) ((char *) obj - swoole_thread_arraylist_handlers.offset); } -static sw_inline zend_long thread_arraylist_get_resource_id(zend_object *obj) { - zval rv, *property = zend_read_property(swoole_thread_arraylist_ce, obj, ZEND_STRL("id"), 1, &rv); - return property ? zval_get_long(property) : 0; -} - -static sw_inline zend_long thread_arraylist_get_resource_id(zval *zobject) { - return thread_arraylist_get_resource_id(Z_OBJ_P(zobject)); -} - -static void thread_arraylist_free_object(zend_object *object) { - zend_long resource_id = thread_arraylist_get_resource_id(object); - ThreadArrayListObject *ao = thread_arraylist_fetch_object(object); - if (ao->list && php_swoole_thread_resource_free(resource_id, ao->list)) { - delete ao->list; +static void arraylist_free_object(zend_object *object) { + ThreadArrayListObject *ao = arraylist_fetch_object(object); + if (ao->list) { + ao->list->del_ref(); ao->list = nullptr; } zend_object_std_dtor(object); } -static zend_object *thread_arraylist_create_object(zend_class_entry *ce) { +static zend_object *arraylist_create_object(zend_class_entry *ce) { ThreadArrayListObject *ao = (ThreadArrayListObject *) zend_object_alloc(sizeof(ThreadArrayListObject), ce); zend_object_std_init(&ao->std, ce); object_properties_init(&ao->std, ce); @@ -75,14 +65,25 @@ static zend_object *thread_arraylist_create_object(zend_class_entry *ce) { return &ao->std; } -ThreadArrayListObject *thread_arraylist_fetch_object_check(zval *zobject) { - ThreadArrayListObject *ao = thread_arraylist_fetch_object(Z_OBJ_P(zobject)); +static ThreadArrayListObject *arraylist_fetch_object_check(zval *zobject) { + ThreadArrayListObject *ao = arraylist_fetch_object(Z_OBJ_P(zobject)); if (!ao->list) { - php_swoole_fatal_error(E_ERROR, "must call constructor first"); + swoole_fatal_error(SW_ERROR_WRONG_OPERATION, "must call constructor first"); } return ao; } +ThreadResource *php_swoole_thread_arraylist_cast(zval *zobject) { + return arraylist_fetch_object_check(zobject)->list; +} + +void php_swoole_thread_arraylist_create(zval *return_value, ThreadResource *resource) { + auto obj = arraylist_create_object(swoole_thread_arraylist_ce); + auto ao = (ThreadArrayListObject *) arraylist_fetch_object(obj); + ao->list = static_cast(resource); + ZVAL_OBJ(return_value, obj); +} + // clang-format off static const zend_function_entry swoole_thread_arraylist_methods[] = { PHP_ME(swoole_thread_arraylist, __construct, arginfo_class_Swoole_Thread_ArrayList___construct, ZEND_ACC_PUBLIC) @@ -94,18 +95,19 @@ static const zend_function_entry swoole_thread_arraylist_methods[] = { PHP_ME(swoole_thread_arraylist, decr, arginfo_class_Swoole_Thread_ArrayList_decr, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_arraylist, clean, arginfo_class_Swoole_Thread_ArrayList_clean, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_arraylist, count, arginfo_class_Swoole_Thread_ArrayList_count, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_arraylist, __wakeup, arginfo_class_Swoole_Thread_ArrayList___wakeup, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_arraylist, toArray, arginfo_class_Swoole_Thread_ArrayList_toArray, ZEND_ACC_PUBLIC) PHP_FE_END }; // clang-format on void php_swoole_thread_arraylist_minit(int module_number) { SW_INIT_CLASS_ENTRY(swoole_thread_arraylist, "Swoole\\Thread\\ArrayList", nullptr, swoole_thread_arraylist_methods); + swoole_thread_arraylist_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NOT_SERIALIZABLE; SW_SET_CLASS_CLONEABLE(swoole_thread_arraylist, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_thread_arraylist, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT(swoole_thread_arraylist, - thread_arraylist_create_object, - thread_arraylist_free_object, + arraylist_create_object, + arraylist_free_object, ThreadArrayListObject, std); @@ -114,12 +116,27 @@ void php_swoole_thread_arraylist_minit(int module_number) { } static PHP_METHOD(swoole_thread_arraylist, __construct) { - ZEND_PARSE_PARAMETERS_NONE(); + zend_array *array = nullptr; + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_HT_OR_NULL(array) + ZEND_PARSE_PARAMETERS_END(); + + auto ao = arraylist_fetch_object(Z_OBJ_P(ZEND_THIS)); + if (ao->list != nullptr) { + zend_throw_error(NULL, "Constructor of %s can only be called once", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS)); + return; + } - auto ao = thread_arraylist_fetch_object(Z_OBJ_P(ZEND_THIS)); - ao->list = new ZendArray(); - auto resource_id = php_swoole_thread_resource_insert(ao->list); - zend_update_property_long(swoole_thread_arraylist_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), resource_id); + if (array) { + if (!zend_array_is_list(array)) { + zend_throw_error(NULL, "the parameter $array must be an array of type list"); + return; + } + ao->list = ZendArray::from(array); + } else { + ao->list = new ZendArray(); + } } static PHP_METHOD(swoole_thread_arraylist, offsetGet) { @@ -129,7 +146,7 @@ static PHP_METHOD(swoole_thread_arraylist, offsetGet) { Z_PARAM_ZVAL(zkey) ZEND_PARSE_PARAMETERS_END(); - auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); + auto ao = arraylist_fetch_object_check(ZEND_THIS); if (!ao->list->index_offsetGet(zkey, return_value)) { zend_throw_exception(swoole_exception_ce, "out of range", -1); } @@ -142,7 +159,7 @@ static PHP_METHOD(swoole_thread_arraylist, offsetExists) { Z_PARAM_ZVAL(zkey) ZEND_PARSE_PARAMETERS_END(); - auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); + auto ao = arraylist_fetch_object_check(ZEND_THIS); ao->list->index_offsetExists(zkey, return_value); } @@ -155,7 +172,7 @@ static PHP_METHOD(swoole_thread_arraylist, offsetSet) { Z_PARAM_ZVAL(zvalue) ZEND_PARSE_PARAMETERS_END(); - auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); + auto ao = arraylist_fetch_object_check(ZEND_THIS); if (!ao->list->index_offsetSet(zkey, zvalue)) { zend_throw_exception(swoole_exception_ce, "out of range", -1); } @@ -163,7 +180,7 @@ static PHP_METHOD(swoole_thread_arraylist, offsetSet) { static PHP_METHOD(swoole_thread_arraylist, incr) { INIT_ARRAY_INCR_PARAMS - auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); + auto ao = arraylist_fetch_object_check(ZEND_THIS); if (!ao->list->index_incr(zkey, zvalue, return_value)) { zend_throw_exception(swoole_exception_ce, "out of range", -1); } @@ -171,7 +188,7 @@ static PHP_METHOD(swoole_thread_arraylist, incr) { static PHP_METHOD(swoole_thread_arraylist, decr) { INIT_ARRAY_INCR_PARAMS - auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); + auto ao = arraylist_fetch_object_check(ZEND_THIS); if (!ao->list->index_decr(zkey, zvalue, return_value)) { zend_throw_exception(swoole_exception_ce, "out of range", -1); } @@ -182,21 +199,17 @@ static PHP_METHOD(swoole_thread_arraylist, offsetUnset) { } static PHP_METHOD(swoole_thread_arraylist, count) { - auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); + auto ao = arraylist_fetch_object_check(ZEND_THIS); ao->list->count(return_value); } static PHP_METHOD(swoole_thread_arraylist, clean) { - auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); + auto ao = arraylist_fetch_object_check(ZEND_THIS); ao->list->clean(); } -static PHP_METHOD(swoole_thread_arraylist, __wakeup) { - auto mo = thread_arraylist_fetch_object(Z_OBJ_P(ZEND_THIS)); - zend_long resource_id = thread_arraylist_get_resource_id(ZEND_THIS); - mo->list = static_cast(php_swoole_thread_resource_fetch(resource_id)); - if (!mo->list) { - zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE); - } +static PHP_METHOD(swoole_thread_arraylist, toArray) { + auto ao = arraylist_fetch_object_check(ZEND_THIS); + ao->list->toArray(return_value); } #endif diff --git a/ext-src/swoole_thread_atomic.cc b/ext-src/swoole_thread_atomic.cc index 8ef1266fe3a..5d5dce07d73 100644 --- a/ext-src/swoole_thread_atomic.cc +++ b/ext-src/swoole_thread_atomic.cc @@ -32,37 +32,38 @@ static zend_object_handlers swoole_thread_atomic_long_handlers; struct AtomicResource : public ThreadResource { sw_atomic_t value; + + AtomicResource(zend_long _value) : ThreadResource() { + value = _value; + } + + ~AtomicResource() override { } }; struct AtomicObject { - AtomicResource *res; + AtomicResource *atomic; zend_object std; }; -static sw_inline AtomicObject *php_swoole_thread_atomic_fetch_object(zend_object *obj) { +static sw_inline AtomicObject *atomic_fetch_object(zend_object *obj) { return (AtomicObject *) ((char *) obj - swoole_thread_atomic_handlers.offset); } -static sw_atomic_t *php_swoole_thread_atomic_get_ptr(zval *zobject) { - return &php_swoole_thread_atomic_fetch_object(Z_OBJ_P(zobject))->res->value; +static sw_atomic_t *atomic_get_ptr(zval *zobject) { + return &atomic_fetch_object(Z_OBJ_P(zobject))->atomic->value; } -static void php_swoole_thread_atomic_free_object(zend_object *object) { - AtomicObject *o = php_swoole_thread_atomic_fetch_object(object); - zend_long resource_id = zend::object_get_long(object, ZEND_STRL("id")); - if (o->res && php_swoole_thread_resource_free(resource_id, o->res)) { - delete o->res; - o->res = nullptr; +static void atomic_free_object(zend_object *object) { + AtomicObject *o = atomic_fetch_object(object); + if (o->atomic) { + o->atomic->del_ref(); + o->atomic = nullptr; } zend_object_std_dtor(object); } -static zend_object *php_swoole_thread_atomic_create_object(zend_class_entry *ce) { +static zend_object *atomic_create_object(zend_class_entry *ce) { AtomicObject *atomic = (AtomicObject *) zend_object_alloc(sizeof(AtomicObject), ce); - if (atomic == nullptr) { - zend_throw_exception(swoole_exception_ce, "global memory allocation failure", SW_ERROR_MALLOC_FAIL); - } - zend_object_std_init(&atomic->std, ce); object_properties_init(&atomic->std, ce); atomic->std.handlers = &swoole_thread_atomic_handlers; @@ -72,32 +73,37 @@ static zend_object *php_swoole_thread_atomic_create_object(zend_class_entry *ce) struct AtomicLongResource : public ThreadResource { sw_atomic_long_t value; + + AtomicLongResource(zend_long _value) : ThreadResource() { + value = _value; + } + + ~AtomicLongResource() override { } }; struct AtomicLongObject { - AtomicLongResource *res; + AtomicLongResource *atomic; zend_object std; }; -static sw_inline AtomicLongObject *php_swoole_thread_atomic_long_fetch_object(zend_object *obj) { +static sw_inline AtomicLongObject *atomic_long_fetch_object(zend_object *obj) { return (AtomicLongObject *) ((char *) obj - swoole_thread_atomic_long_handlers.offset); } -static sw_atomic_long_t *php_swoole_thread_atomic_long_get_ptr(zval *zobject) { - return &php_swoole_thread_atomic_long_fetch_object(Z_OBJ_P(zobject))->res->value; +static sw_atomic_long_t *atomic_long_get_ptr(zval *zobject) { + return &atomic_long_fetch_object(Z_OBJ_P(zobject))->atomic->value; } -static void php_swoole_thread_atomic_long_free_object(zend_object *object) { - AtomicLongObject *o = php_swoole_thread_atomic_long_fetch_object(object); - zend_long resource_id = zend::object_get_long(object, ZEND_STRL("id")); - if (o->res && php_swoole_thread_resource_free(resource_id, o->res)) { - delete o->res; - o->res = nullptr; +static void atomic_long_free_object(zend_object *object) { + AtomicLongObject *o = atomic_long_fetch_object(object); + if (o->atomic) { + o->atomic->del_ref(); + o->atomic = nullptr; } zend_object_std_dtor(object); } -static zend_object *php_swoole_thread_atomic_long_create_object(zend_class_entry *ce) { +static zend_object *atomic_long_create_object(zend_class_entry *ce) { AtomicLongObject *atomic_long = (AtomicLongObject *) zend_object_alloc(sizeof(AtomicLongObject), ce); zend_object_std_init(&atomic_long->std, ce); object_properties_init(&atomic_long->std, ce); @@ -105,6 +111,28 @@ static zend_object *php_swoole_thread_atomic_long_create_object(zend_class_entry return &atomic_long->std; } +ThreadResource *php_swoole_thread_atomic_cast(zval *zobject) { + return atomic_fetch_object(Z_OBJ_P(zobject))->atomic; +} + +ThreadResource *php_swoole_thread_atomic_long_cast(zval *zobject) { + return atomic_long_fetch_object(Z_OBJ_P(zobject))->atomic; +} + +void php_swoole_thread_atomic_create(zval *return_value, ThreadResource *resource) { + auto obj = atomic_create_object(swoole_thread_atomic_ce); + auto ao = (AtomicObject *) atomic_fetch_object(obj); + ao->atomic = static_cast(resource); + ZVAL_OBJ(return_value, obj); +} + +void php_swoole_thread_atomic_long_create(zval *return_value, ThreadResource *resource) { + auto obj = atomic_long_create_object(swoole_thread_atomic_long_ce); + auto ao = (AtomicLongObject *) atomic_long_fetch_object(obj); + ao->atomic = static_cast(resource); + ZVAL_OBJ(return_value, obj); +} + SW_EXTERN_C_BEGIN static PHP_METHOD(swoole_thread_atomic, __construct); static PHP_METHOD(swoole_thread_atomic, add); @@ -114,7 +142,6 @@ static PHP_METHOD(swoole_thread_atomic, set); static PHP_METHOD(swoole_thread_atomic, cmpset); static PHP_METHOD(swoole_thread_atomic, wait); static PHP_METHOD(swoole_thread_atomic, wakeup); -static PHP_METHOD(swoole_thread_atomic, __wakeup); static PHP_METHOD(swoole_thread_atomic_long, __construct); static PHP_METHOD(swoole_thread_atomic_long, add); @@ -122,7 +149,6 @@ static PHP_METHOD(swoole_thread_atomic_long, sub); static PHP_METHOD(swoole_thread_atomic_long, get); static PHP_METHOD(swoole_thread_atomic_long, set); static PHP_METHOD(swoole_thread_atomic_long, cmpset); -static PHP_METHOD(swoole_thread_atomic_long, __wakeup); SW_EXTERN_C_END // clang-format off @@ -136,7 +162,6 @@ static const zend_function_entry swoole_thread_atomic_methods[] = PHP_ME(swoole_thread_atomic, wait, arginfo_class_Swoole_Thread_Atomic_wait, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_atomic, wakeup, arginfo_class_Swoole_Thread_Atomic_wakeup, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_atomic, cmpset, arginfo_class_Swoole_Thread_Atomic_cmpset, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_atomic, __wakeup, arginfo_class_Swoole_Thread_Atomic___wakeup, ZEND_ACC_PUBLIC) PHP_FE_END }; @@ -148,36 +173,35 @@ static const zend_function_entry swoole_thread_atomic_long_methods[] = PHP_ME(swoole_thread_atomic_long, get, arginfo_class_Swoole_Thread_Atomic_Long_get, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_atomic_long, set, arginfo_class_Swoole_Thread_Atomic_Long_set, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_atomic_long, cmpset, arginfo_class_Swoole_Thread_Atomic_Long_cmpset, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_atomic_long, __wakeup, arginfo_class_Swoole_Thread_Atomic_Long___wakeup, ZEND_ACC_PUBLIC) PHP_FE_END }; // clang-format on void php_swoole_thread_atomic_minit(int module_number) { SW_INIT_CLASS_ENTRY(swoole_thread_atomic, "Swoole\\Thread\\Atomic", nullptr, swoole_thread_atomic_methods); - zend_declare_property_long(swoole_thread_atomic_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC); + swoole_thread_atomic_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NOT_SERIALIZABLE; SW_SET_CLASS_CLONEABLE(swoole_thread_atomic, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_thread_atomic, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT(swoole_thread_atomic, - php_swoole_thread_atomic_create_object, - php_swoole_thread_atomic_free_object, + atomic_create_object, + atomic_free_object, AtomicObject, std); SW_INIT_CLASS_ENTRY( swoole_thread_atomic_long, "Swoole\\Thread\\Atomic\\Long", nullptr, swoole_thread_atomic_long_methods); - zend_declare_property_long(swoole_thread_atomic_long_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC); + swoole_thread_atomic_long_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NOT_SERIALIZABLE; SW_SET_CLASS_CLONEABLE(swoole_thread_atomic_long, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_thread_atomic_long, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT(swoole_thread_atomic_long, - php_swoole_thread_atomic_long_create_object, - php_swoole_thread_atomic_long_free_object, + atomic_long_create_object, + atomic_long_free_object, AtomicLongObject, std); } PHP_METHOD(swoole_thread_atomic, __construct) { - auto o = php_swoole_thread_atomic_fetch_object(Z_OBJ_P(ZEND_THIS)); + auto o = atomic_fetch_object(Z_OBJ_P(ZEND_THIS)); zend_long value = 0; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) @@ -185,18 +209,15 @@ PHP_METHOD(swoole_thread_atomic, __construct) { Z_PARAM_LONG(value) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); - if (o->res) { + if (o->atomic) { zend_throw_error(NULL, "Constructor of %s can only be called once", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS)); - RETURN_FALSE; + return; } - o->res = new AtomicResource(); - auto resource_id = php_swoole_thread_resource_insert(o->res); - zend_update_property_long(swoole_thread_atomic_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), resource_id); - o->res->value = value; + o->atomic = new AtomicResource(value); } PHP_METHOD(swoole_thread_atomic, add) { - sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + sw_atomic_t *atomic = atomic_get_ptr(ZEND_THIS); zend_long add_value = 1; ZEND_PARSE_PARAMETERS_START(0, 1) @@ -208,7 +229,7 @@ PHP_METHOD(swoole_thread_atomic, add) { } PHP_METHOD(swoole_thread_atomic, sub) { - sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + sw_atomic_t *atomic = atomic_get_ptr(ZEND_THIS); zend_long sub_value = 1; ZEND_PARSE_PARAMETERS_START(0, 1) @@ -220,12 +241,12 @@ PHP_METHOD(swoole_thread_atomic, sub) { } PHP_METHOD(swoole_thread_atomic, get) { - sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + sw_atomic_t *atomic = atomic_get_ptr(ZEND_THIS); RETURN_LONG(*atomic); } PHP_METHOD(swoole_thread_atomic, set) { - sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + sw_atomic_t *atomic = atomic_get_ptr(ZEND_THIS); zend_long set_value; ZEND_PARSE_PARAMETERS_START(1, 1) @@ -236,7 +257,7 @@ PHP_METHOD(swoole_thread_atomic, set) { } PHP_METHOD(swoole_thread_atomic, cmpset) { - sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + sw_atomic_t *atomic = atomic_get_ptr(ZEND_THIS); zend_long cmp_value, set_value; ZEND_PARSE_PARAMETERS_START(2, 2) @@ -248,7 +269,7 @@ PHP_METHOD(swoole_thread_atomic, cmpset) { } PHP_METHOD(swoole_thread_atomic, wait) { - sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + sw_atomic_t *atomic = atomic_get_ptr(ZEND_THIS); double timeout = 1.0; ZEND_PARSE_PARAMETERS_START(0, 1) @@ -260,7 +281,7 @@ PHP_METHOD(swoole_thread_atomic, wait) { } PHP_METHOD(swoole_thread_atomic, wakeup) { - sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + sw_atomic_t *atomic = atomic_get_ptr(ZEND_THIS); zend_long n = 1; ZEND_PARSE_PARAMETERS_START(0, 1) @@ -271,18 +292,8 @@ PHP_METHOD(swoole_thread_atomic, wakeup) { SW_CHECK_RETURN(sw_atomic_futex_wakeup(atomic, (int) n)); } -static PHP_METHOD(swoole_thread_atomic, __wakeup) { - auto o = php_swoole_thread_atomic_fetch_object(Z_OBJ_P(ZEND_THIS)); - zend_long resource_id = zend::object_get_long(ZEND_THIS, ZEND_STRL("id")); - o->res = static_cast(php_swoole_thread_resource_fetch(resource_id)); - if (!o->res) { - zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE); - return; - } -} - PHP_METHOD(swoole_thread_atomic_long, __construct) { - auto o = php_swoole_thread_atomic_long_fetch_object(Z_OBJ_P(ZEND_THIS)); + auto o = atomic_long_fetch_object(Z_OBJ_P(ZEND_THIS)); zend_long value = 0; ZEND_PARSE_PARAMETERS_START(0, 1) @@ -290,18 +301,15 @@ PHP_METHOD(swoole_thread_atomic_long, __construct) { Z_PARAM_LONG(value) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); - if (o->res) { + if (o->atomic) { zend_throw_error(NULL, "Constructor of %s can only be called once", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS)); RETURN_FALSE; } - o->res = new AtomicLongResource(); - auto resource_id = php_swoole_thread_resource_insert(o->res); - zend_update_property_long(swoole_thread_atomic_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), resource_id); - o->res->value = value; + o->atomic = new AtomicLongResource(value); } PHP_METHOD(swoole_thread_atomic_long, add) { - sw_atomic_long_t *atomic_long = php_swoole_thread_atomic_long_get_ptr(ZEND_THIS); + sw_atomic_long_t *atomic_long = atomic_long_get_ptr(ZEND_THIS); zend_long add_value = 1; ZEND_PARSE_PARAMETERS_START(0, 1) @@ -313,7 +321,7 @@ PHP_METHOD(swoole_thread_atomic_long, add) { } PHP_METHOD(swoole_thread_atomic_long, sub) { - sw_atomic_long_t *atomic_long = php_swoole_thread_atomic_long_get_ptr(ZEND_THIS); + sw_atomic_long_t *atomic_long = atomic_long_get_ptr(ZEND_THIS); zend_long sub_value = 1; ZEND_PARSE_PARAMETERS_START(0, 1) @@ -325,12 +333,12 @@ PHP_METHOD(swoole_thread_atomic_long, sub) { } PHP_METHOD(swoole_thread_atomic_long, get) { - sw_atomic_long_t *atomic_long = php_swoole_thread_atomic_long_get_ptr(ZEND_THIS); + sw_atomic_long_t *atomic_long = atomic_long_get_ptr(ZEND_THIS); RETURN_LONG(*atomic_long); } PHP_METHOD(swoole_thread_atomic_long, set) { - sw_atomic_long_t *atomic_long = php_swoole_thread_atomic_long_get_ptr(ZEND_THIS); + sw_atomic_long_t *atomic_long = atomic_long_get_ptr(ZEND_THIS); zend_long set_value; ZEND_PARSE_PARAMETERS_START(1, 1) @@ -341,7 +349,7 @@ PHP_METHOD(swoole_thread_atomic_long, set) { } PHP_METHOD(swoole_thread_atomic_long, cmpset) { - sw_atomic_long_t *atomic_long = php_swoole_thread_atomic_long_get_ptr(ZEND_THIS); + sw_atomic_long_t *atomic_long = atomic_long_get_ptr(ZEND_THIS); zend_long cmp_value, set_value; ZEND_PARSE_PARAMETERS_START(2, 2) @@ -352,13 +360,4 @@ PHP_METHOD(swoole_thread_atomic_long, cmpset) { RETURN_BOOL(sw_atomic_cmp_set(atomic_long, (sw_atomic_long_t) cmp_value, (sw_atomic_long_t) set_value)); } -static PHP_METHOD(swoole_thread_atomic_long, __wakeup) { - auto o = php_swoole_thread_atomic_long_fetch_object(Z_OBJ_P(ZEND_THIS)); - zend_long resource_id = zend::object_get_long(ZEND_THIS, ZEND_STRL("id")); - o->res = static_cast(php_swoole_thread_resource_fetch(resource_id)); - if (!o->res) { - zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE); - return; - } -} #endif diff --git a/ext-src/swoole_thread_barrier.cc b/ext-src/swoole_thread_barrier.cc index 05d193225ed..9bf3539bf59 100644 --- a/ext-src/swoole_thread_barrier.cc +++ b/ext-src/swoole_thread_barrier.cc @@ -27,7 +27,7 @@ END_EXTERN_C() using swoole::Barrier; -static zend_class_entry *swoole_thread_barrier_ce; +zend_class_entry *swoole_thread_barrier_ce; static zend_object_handlers swoole_thread_barrier_handlers; struct BarrierResource : public ThreadResource { @@ -38,7 +38,7 @@ struct BarrierResource : public ThreadResource { void wait() { barrier_.wait(); } - ~BarrierResource() { + ~BarrierResource() override { barrier_.destroy(); } }; @@ -48,33 +48,32 @@ struct BarrierObject { zend_object std; }; -static sw_inline BarrierObject *php_swoole_thread_barrier_fetch_object(zend_object *obj) { +static sw_inline BarrierObject *barrier_fetch_object(zend_object *obj) { return (BarrierObject *) ((char *) obj - swoole_thread_barrier_handlers.offset); } -static BarrierResource *php_swoole_thread_barrier_get_ptr(zval *zobject) { - return php_swoole_thread_barrier_fetch_object(Z_OBJ_P(zobject))->barrier; +static BarrierResource *barrier_get_ptr(zval *zobject) { + return barrier_fetch_object(Z_OBJ_P(zobject))->barrier; } -static BarrierResource *php_swoole_thread_barrier_get_and_check_ptr(zval *zobject) { - BarrierResource *barrier = php_swoole_thread_barrier_get_ptr(zobject); - if (!barrier) { - php_swoole_fatal_error(E_ERROR, "must call constructor first"); +static BarrierResource *barrier_get_and_check_ptr(zval *zobject) { + BarrierResource *barrier = barrier_get_ptr(zobject); + if (UNEXPECTED(!barrier)) { + swoole_fatal_error(SW_ERROR_WRONG_OPERATION, "must call constructor first"); } return barrier; } -static void php_swoole_thread_barrier_free_object(zend_object *object) { - BarrierObject *bo = php_swoole_thread_barrier_fetch_object(object); - zend_long resource_id = zend::object_get_long(object, ZEND_STRL("id")); - if (bo->barrier && php_swoole_thread_resource_free(resource_id, bo->barrier)) { - delete bo->barrier; +static void barrier_free_object(zend_object *object) { + BarrierObject *bo = barrier_fetch_object(object); + if (bo->barrier) { + bo->barrier->del_ref(); bo->barrier = nullptr; } zend_object_std_dtor(object); } -static zend_object *php_swoole_thread_barrier_create_object(zend_class_entry *ce) { +static zend_object *barrier_create_object(zend_class_entry *ce) { BarrierObject *bo = (BarrierObject *) zend_object_alloc(sizeof(BarrierObject), ce); zend_object_std_init(&bo->std, ce); object_properties_init(&bo->std, ce); @@ -82,10 +81,20 @@ static zend_object *php_swoole_thread_barrier_create_object(zend_class_entry *ce return &bo->std; } +ThreadResource *php_swoole_thread_barrier_cast(zval *zobject) { + return barrier_fetch_object(Z_OBJ_P(zobject))->barrier; +} + +void php_swoole_thread_barrier_create(zval *return_value, ThreadResource *resource) { + auto obj = barrier_create_object(swoole_thread_barrier_ce); + auto bo = (BarrierObject *) barrier_fetch_object(obj); + bo->barrier = static_cast(resource); + ZVAL_OBJ(return_value, obj); +} + SW_EXTERN_C_BEGIN static PHP_METHOD(swoole_thread_barrier, __construct); static PHP_METHOD(swoole_thread_barrier, wait); -static PHP_METHOD(swoole_thread_barrier, __wakeup); SW_EXTERN_C_END // clang-format off @@ -93,28 +102,27 @@ static const zend_function_entry swoole_thread_barrier_methods[] = { PHP_ME(swoole_thread_barrier, __construct, arginfo_class_Swoole_Thread_Barrier___construct, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_barrier, wait, arginfo_class_Swoole_Thread_Barrier_wait, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_barrier, __wakeup, arginfo_class_Swoole_Thread_Barrier___wakeup, ZEND_ACC_PUBLIC) PHP_FE_END }; // clang-format on void php_swoole_thread_barrier_minit(int module_number) { SW_INIT_CLASS_ENTRY(swoole_thread_barrier, "Swoole\\Thread\\Barrier", nullptr, swoole_thread_barrier_methods); - zend_declare_property_long(swoole_thread_barrier_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC); + swoole_thread_barrier_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NOT_SERIALIZABLE; SW_SET_CLASS_CLONEABLE(swoole_thread_barrier, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_thread_barrier, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT(swoole_thread_barrier, - php_swoole_thread_barrier_create_object, - php_swoole_thread_barrier_free_object, + barrier_create_object, + barrier_free_object, BarrierObject, std); } static PHP_METHOD(swoole_thread_barrier, __construct) { - auto bo = php_swoole_thread_barrier_fetch_object(Z_OBJ_P(ZEND_THIS)); + auto bo = barrier_fetch_object(Z_OBJ_P(ZEND_THIS)); if (bo->barrier != nullptr) { zend_throw_error(NULL, "Constructor of %s can only be called once", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS)); - RETURN_FALSE; + return; } zend_long count; @@ -125,29 +133,17 @@ static PHP_METHOD(swoole_thread_barrier, __construct) { if (count < 2) { zend_throw_exception( swoole_exception_ce, "The parameter $count must be greater than 1", SW_ERROR_INVALID_PARAMS); - RETURN_FALSE; + return; } bo->barrier = new BarrierResource(count); - auto resource_id = php_swoole_thread_resource_insert(bo->barrier); - zend_update_property_long(swoole_thread_barrier_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), resource_id); - RETURN_TRUE; } static PHP_METHOD(swoole_thread_barrier, wait) { - BarrierResource *barrier = php_swoole_thread_barrier_get_and_check_ptr(ZEND_THIS); + BarrierResource *barrier = barrier_get_and_check_ptr(ZEND_THIS); if (barrier) { barrier->wait(); } } -static PHP_METHOD(swoole_thread_barrier, __wakeup) { - auto bo = php_swoole_thread_barrier_fetch_object(Z_OBJ_P(ZEND_THIS)); - zend_long resource_id = zend::object_get_long(ZEND_THIS, ZEND_STRL("id")); - bo->barrier = static_cast(php_swoole_thread_resource_fetch(resource_id)); - if (!bo->barrier) { - zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE); - return; - } -} #endif diff --git a/ext-src/swoole_thread_lock.cc b/ext-src/swoole_thread_lock.cc index 7ced5d50023..df6aa88e717 100644 --- a/ext-src/swoole_thread_lock.cc +++ b/ext-src/swoole_thread_lock.cc @@ -34,7 +34,7 @@ using swoole::SpinLock; using swoole::RWLock; #endif -static zend_class_entry *swoole_thread_lock_ce; +zend_class_entry *swoole_thread_lock_ce; static zend_object_handlers swoole_thread_lock_handlers; struct LockResource : public ThreadResource { @@ -57,7 +57,7 @@ struct LockResource : public ThreadResource { break; } } - ~LockResource() { + ~LockResource() override { delete lock_; } }; @@ -67,33 +67,32 @@ struct LockObject { zend_object std; }; -static sw_inline LockObject *php_swoole_thread_lock_fetch_object(zend_object *obj) { +static sw_inline LockObject *lock_fetch_object(zend_object *obj) { return (LockObject *) ((char *) obj - swoole_thread_lock_handlers.offset); } -static Lock *php_swoole_thread_lock_get_ptr(zval *zobject) { - return php_swoole_thread_lock_fetch_object(Z_OBJ_P(zobject))->lock->lock_; +static Lock *lock_get_ptr(zval *zobject) { + return lock_fetch_object(Z_OBJ_P(zobject))->lock->lock_; } -static Lock *php_swoole_thread_lock_get_and_check_ptr(zval *zobject) { - Lock *lock = php_swoole_thread_lock_get_ptr(zobject); +static Lock *lock_get_and_check_ptr(zval *zobject) { + Lock *lock = lock_get_ptr(zobject); if (!lock) { php_swoole_fatal_error(E_ERROR, "must call constructor first"); } return lock; } -static void php_swoole_thread_lock_free_object(zend_object *object) { - LockObject *o = php_swoole_thread_lock_fetch_object(object); - zend_long resource_id = zend::object_get_long(object, ZEND_STRL("id")); - if (o->lock && php_swoole_thread_resource_free(resource_id, o->lock)) { - delete o->lock; +static void lock_free_object(zend_object *object) { + LockObject *o = lock_fetch_object(object); + if (o->lock) { + o->lock->del_ref(); o->lock = nullptr; } zend_object_std_dtor(object); } -static zend_object *php_swoole_thread_lock_create_object(zend_class_entry *ce) { +static zend_object *lock_create_object(zend_class_entry *ce) { LockObject *lock = (LockObject *) zend_object_alloc(sizeof(LockObject), ce); zend_object_std_init(&lock->std, ce); object_properties_init(&lock->std, ce); @@ -101,6 +100,17 @@ static zend_object *php_swoole_thread_lock_create_object(zend_class_entry *ce) { return &lock->std; } +ThreadResource *php_swoole_thread_lock_cast(zval *zobject) { + return lock_fetch_object(Z_OBJ_P(zobject))->lock; +} + +void php_swoole_thread_lock_create(zval *return_value, ThreadResource *resource) { + auto obj = lock_create_object(swoole_thread_lock_ce); + auto lo = (LockObject *) lock_fetch_object(obj); + lo->lock = static_cast(resource); + ZVAL_OBJ(return_value, obj); +} + SW_EXTERN_C_BEGIN static PHP_METHOD(swoole_thread_lock, __construct); static PHP_METHOD(swoole_thread_lock, __destruct); @@ -111,7 +121,6 @@ static PHP_METHOD(swoole_thread_lock, lock_read); static PHP_METHOD(swoole_thread_lock, trylock_read); static PHP_METHOD(swoole_thread_lock, unlock); static PHP_METHOD(swoole_thread_lock, destroy); -static PHP_METHOD(swoole_thread_lock, __wakeup); SW_EXTERN_C_END // clang-format off @@ -125,18 +134,17 @@ static const zend_function_entry swoole_thread_lock_methods[] = PHP_ME(swoole_thread_lock, lock_read, arginfo_class_Swoole_Thread_Lock_lock_read, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_lock, trylock_read, arginfo_class_Swoole_Thread_Lock_trylock_read, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_lock, unlock, arginfo_class_Swoole_Thread_Lock_unlock, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_lock, __wakeup, arginfo_class_Swoole_Thread_Lock___wakeup, ZEND_ACC_PUBLIC) PHP_FE_END }; // clang-format on void php_swoole_thread_lock_minit(int module_number) { SW_INIT_CLASS_ENTRY(swoole_thread_lock, "Swoole\\Thread\\Lock", nullptr, swoole_thread_lock_methods); - zend_declare_property_long(swoole_thread_lock_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC); + swoole_thread_lock_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NOT_SERIALIZABLE; SW_SET_CLASS_CLONEABLE(swoole_thread_lock, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_thread_lock, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT( - swoole_thread_lock, php_swoole_thread_lock_create_object, php_swoole_thread_lock_free_object, LockObject, std); + swoole_thread_lock, lock_create_object, lock_free_object, LockObject, std); zend_declare_class_constant_long(swoole_thread_lock_ce, ZEND_STRL("MUTEX"), Lock::MUTEX); #ifdef HAVE_RWLOCK @@ -146,13 +154,10 @@ void php_swoole_thread_lock_minit(int module_number) { zend_declare_class_constant_long(swoole_thread_lock_ce, ZEND_STRL("SPINLOCK"), Lock::SPIN_LOCK); #endif zend_declare_property_long(swoole_thread_lock_ce, ZEND_STRL("errCode"), 0, ZEND_ACC_PUBLIC); -#ifdef SW_THREAD - zend_declare_property_long(swoole_thread_lock_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); -#endif } static PHP_METHOD(swoole_thread_lock, __construct) { - auto o = php_swoole_thread_lock_fetch_object(Z_OBJ_P(ZEND_THIS)); + auto o = lock_fetch_object(Z_OBJ_P(ZEND_THIS)); if (o->lock != nullptr) { zend_throw_error(NULL, "Constructor of %s can only be called once", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS)); RETURN_FALSE; @@ -166,15 +171,12 @@ static PHP_METHOD(swoole_thread_lock, __construct) { ZEND_PARSE_PARAMETERS_END(); o->lock = new LockResource(type); - auto resource_id = php_swoole_thread_resource_insert(o->lock); - zend_update_property_long(swoole_thread_lock_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), resource_id); - RETURN_TRUE; } static PHP_METHOD(swoole_thread_lock, __destruct) {} static PHP_METHOD(swoole_thread_lock, lock) { - Lock *lock = php_swoole_thread_lock_get_and_check_ptr(ZEND_THIS); + Lock *lock = lock_get_and_check_ptr(ZEND_THIS); SW_LOCK_CHECK_RETURN(lock->lock()); } @@ -184,7 +186,7 @@ static PHP_METHOD(swoole_thread_lock, lockwait) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &timeout) == FAILURE) { RETURN_FALSE; } - Lock *lock = php_swoole_thread_lock_get_and_check_ptr(ZEND_THIS); + Lock *lock = lock_get_and_check_ptr(ZEND_THIS); if (lock->get_type() != Lock::MUTEX) { zend_throw_exception(swoole_exception_ce, "only mutex supports lockwait", -2); RETURN_FALSE; @@ -198,33 +200,23 @@ static PHP_METHOD(swoole_thread_lock, lockwait) { } static PHP_METHOD(swoole_thread_lock, unlock) { - Lock *lock = php_swoole_thread_lock_get_and_check_ptr(ZEND_THIS); + Lock *lock = lock_get_and_check_ptr(ZEND_THIS); SW_LOCK_CHECK_RETURN(lock->unlock()); } static PHP_METHOD(swoole_thread_lock, trylock) { - Lock *lock = php_swoole_thread_lock_get_and_check_ptr(ZEND_THIS); + Lock *lock = lock_get_and_check_ptr(ZEND_THIS); SW_LOCK_CHECK_RETURN(lock->trylock()); } static PHP_METHOD(swoole_thread_lock, trylock_read) { - Lock *lock = php_swoole_thread_lock_get_and_check_ptr(ZEND_THIS); + Lock *lock = lock_get_and_check_ptr(ZEND_THIS); SW_LOCK_CHECK_RETURN(lock->trylock_rd()); } static PHP_METHOD(swoole_thread_lock, lock_read) { - Lock *lock = php_swoole_thread_lock_get_and_check_ptr(ZEND_THIS); + Lock *lock = lock_get_and_check_ptr(ZEND_THIS); SW_LOCK_CHECK_RETURN(lock->lock_rd()); } -static PHP_METHOD(swoole_thread_lock, __wakeup) { - auto o = php_swoole_thread_lock_fetch_object(Z_OBJ_P(ZEND_THIS)); - zend_long resource_id = zend::object_get_long(ZEND_THIS, ZEND_STRL("id")); - o->lock = static_cast(php_swoole_thread_resource_fetch(resource_id)); - if (!o->lock) { - zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE); - return; - } -} - #endif diff --git a/ext-src/swoole_thread_map.cc b/ext-src/swoole_thread_map.cc index ff1858d21bb..28458739c50 100644 --- a/ext-src/swoole_thread_map.cc +++ b/ext-src/swoole_thread_map.cc @@ -31,30 +31,20 @@ struct ThreadMapObject { zend_object std; }; -static sw_inline ThreadMapObject *thread_map_fetch_object(zend_object *obj) { +static sw_inline ThreadMapObject *map_fetch_object(zend_object *obj) { return (ThreadMapObject *) ((char *) obj - swoole_thread_map_handlers.offset); } -static sw_inline zend_long thread_map_get_resource_id(zend_object *obj) { - zval rv, *property = zend_read_property(swoole_thread_map_ce, obj, ZEND_STRL("id"), 1, &rv); - return property ? zval_get_long(property) : 0; -} - -static sw_inline zend_long thread_map_get_resource_id(zval *zobject) { - return thread_map_get_resource_id(Z_OBJ_P(zobject)); -} - -static void thread_map_free_object(zend_object *object) { - zend_long resource_id = thread_map_get_resource_id(object); - ThreadMapObject *mo = thread_map_fetch_object(object); - if (mo->map && php_swoole_thread_resource_free(resource_id, mo->map)) { - delete mo->map; +static void map_free_object(zend_object *object) { + ThreadMapObject *mo = map_fetch_object(object); + if (mo->map) { + mo->map->del_ref(); mo->map = nullptr; } zend_object_std_dtor(object); } -static zend_object *thread_map_create_object(zend_class_entry *ce) { +static zend_object *map_create_object(zend_class_entry *ce) { ThreadMapObject *mo = (ThreadMapObject *) zend_object_alloc(sizeof(ThreadMapObject), ce); zend_object_std_init(&mo->std, ce); object_properties_init(&mo->std, ce); @@ -62,14 +52,25 @@ static zend_object *thread_map_create_object(zend_class_entry *ce) { return &mo->std; } -ThreadMapObject *thread_map_fetch_object_check(zval *zobject) { - ThreadMapObject *map = thread_map_fetch_object(Z_OBJ_P(zobject)); +static ThreadMapObject *map_fetch_object_check(zval *zobject) { + ThreadMapObject *map = map_fetch_object(Z_OBJ_P(zobject)); if (!map->map) { php_swoole_fatal_error(E_ERROR, "must call constructor first"); } return map; } +ThreadResource *php_swoole_thread_map_cast(zval *zobject) { + return map_fetch_object(Z_OBJ_P(zobject))->map; +} + +void php_swoole_thread_map_create(zval *return_value, ThreadResource *resource) { + auto obj = map_create_object(swoole_thread_map_ce); + auto mo = (ThreadMapObject *) map_fetch_object(obj); + mo->map = static_cast(resource); + ZVAL_OBJ(return_value, obj); +} + SW_EXTERN_C_BEGIN static PHP_METHOD(swoole_thread_map, __construct); static PHP_METHOD(swoole_thread_map, offsetGet); @@ -78,12 +79,13 @@ static PHP_METHOD(swoole_thread_map, offsetSet); static PHP_METHOD(swoole_thread_map, offsetUnset); static PHP_METHOD(swoole_thread_map, count); static PHP_METHOD(swoole_thread_map, keys); +static PHP_METHOD(swoole_thread_map, values); static PHP_METHOD(swoole_thread_map, incr); static PHP_METHOD(swoole_thread_map, decr); static PHP_METHOD(swoole_thread_map, add); static PHP_METHOD(swoole_thread_map, update); static PHP_METHOD(swoole_thread_map, clean); -static PHP_METHOD(swoole_thread_map, __wakeup); +static PHP_METHOD(swoole_thread_map, toArray); SW_EXTERN_C_END // clang-format off @@ -100,27 +102,41 @@ static const zend_function_entry swoole_thread_map_methods[] = { PHP_ME(swoole_thread_map, update, arginfo_class_Swoole_Thread_Map_update, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_map, clean, arginfo_class_Swoole_Thread_Map_clean, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_map, keys, arginfo_class_Swoole_Thread_Map_keys, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_map, __wakeup, arginfo_class_Swoole_Thread_Map___wakeup, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_map, values, arginfo_class_Swoole_Thread_Map_values, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_map, toArray, arginfo_class_Swoole_Thread_Map_toArray, ZEND_ACC_PUBLIC) PHP_FE_END }; // clang-format on void php_swoole_thread_map_minit(int module_number) { SW_INIT_CLASS_ENTRY(swoole_thread_map, "Swoole\\Thread\\Map", nullptr, swoole_thread_map_methods); + swoole_thread_map_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NOT_SERIALIZABLE; SW_SET_CLASS_CLONEABLE(swoole_thread_map, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_thread_map, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT( - swoole_thread_map, thread_map_create_object, thread_map_free_object, ThreadMapObject, std); + swoole_thread_map, map_create_object, map_free_object, ThreadMapObject, std); zend_class_implements(swoole_thread_map_ce, 2, zend_ce_arrayaccess, zend_ce_countable); - zend_declare_property_long(swoole_thread_map_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC); } static PHP_METHOD(swoole_thread_map, __construct) { - auto mo = thread_map_fetch_object(Z_OBJ_P(ZEND_THIS)); - mo->map = new ZendArray(); - auto resource_id = php_swoole_thread_resource_insert(mo->map); - zend_update_property_long(swoole_thread_map_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), resource_id); + zend_array *array = nullptr; + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_HT_OR_NULL(array) + ZEND_PARSE_PARAMETERS_END(); + + auto mo = map_fetch_object(Z_OBJ_P(ZEND_THIS)); + if (mo->map != nullptr) { + zend_throw_error(NULL, "Constructor of %s can only be called once", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS)); + return; + } + + if (array) { + mo->map = ZendArray::from(array); + } else { + mo->map = new ZendArray(); + } } #define ZEND_ARRAY_CALL_METHOD(array, method, zkey, ...) \ @@ -137,7 +153,7 @@ static PHP_METHOD(swoole_thread_map, offsetGet) { Z_PARAM_ZVAL(zkey) ZEND_PARSE_PARAMETERS_END(); - auto mo = thread_map_fetch_object_check(ZEND_THIS); + auto mo = map_fetch_object_check(ZEND_THIS); ZEND_ARRAY_CALL_METHOD(mo->map, offsetGet, zkey, return_value); } @@ -148,7 +164,7 @@ static PHP_METHOD(swoole_thread_map, offsetExists) { Z_PARAM_ZVAL(zkey) ZEND_PARSE_PARAMETERS_END(); - auto mo = thread_map_fetch_object_check(ZEND_THIS); + auto mo = map_fetch_object_check(ZEND_THIS); ZEND_ARRAY_CALL_METHOD(mo->map, offsetExists, zkey, return_value); } @@ -161,19 +177,19 @@ static PHP_METHOD(swoole_thread_map, offsetSet) { Z_PARAM_ZVAL(zvalue) ZEND_PARSE_PARAMETERS_END(); - auto mo = thread_map_fetch_object_check(ZEND_THIS); + auto mo = map_fetch_object_check(ZEND_THIS); ZEND_ARRAY_CALL_METHOD(mo->map, offsetSet, zkey, zvalue); } static PHP_METHOD(swoole_thread_map, incr) { INIT_ARRAY_INCR_PARAMS - auto mo = thread_map_fetch_object_check(ZEND_THIS); + auto mo = map_fetch_object_check(ZEND_THIS); ZEND_ARRAY_CALL_METHOD(mo->map, incr, zkey, zvalue, return_value); } static PHP_METHOD(swoole_thread_map, decr) { INIT_ARRAY_INCR_PARAMS - auto mo = thread_map_fetch_object_check(ZEND_THIS); + auto mo = map_fetch_object_check(ZEND_THIS); ZEND_ARRAY_CALL_METHOD(mo->map, decr, zkey, zvalue, return_value); } @@ -186,7 +202,7 @@ static PHP_METHOD(swoole_thread_map, add) { Z_PARAM_ZVAL(zvalue) ZEND_PARSE_PARAMETERS_END(); - auto mo = thread_map_fetch_object_check(ZEND_THIS); + auto mo = map_fetch_object_check(ZEND_THIS); ZEND_ARRAY_CALL_METHOD(mo->map, add, zkey, zvalue, return_value); } @@ -199,7 +215,7 @@ static PHP_METHOD(swoole_thread_map, update) { Z_PARAM_ZVAL(zvalue) ZEND_PARSE_PARAMETERS_END(); - auto mo = thread_map_fetch_object_check(ZEND_THIS); + auto mo = map_fetch_object_check(ZEND_THIS); ZEND_ARRAY_CALL_METHOD(mo->map, update, zkey, zvalue, return_value); } @@ -210,32 +226,33 @@ static PHP_METHOD(swoole_thread_map, offsetUnset) { Z_PARAM_ZVAL(zkey) ZEND_PARSE_PARAMETERS_END(); - auto mo = thread_map_fetch_object_check(ZEND_THIS); + auto mo = map_fetch_object_check(ZEND_THIS); ZEND_ARRAY_CALL_METHOD(mo->map, offsetUnset, zkey); } static PHP_METHOD(swoole_thread_map, count) { - auto mo = thread_map_fetch_object_check(ZEND_THIS); + auto mo = map_fetch_object_check(ZEND_THIS); mo->map->count(return_value); } static PHP_METHOD(swoole_thread_map, keys) { - auto mo = thread_map_fetch_object_check(ZEND_THIS); + auto mo = map_fetch_object_check(ZEND_THIS); mo->map->keys(return_value); } -static PHP_METHOD(swoole_thread_map, clean) { - auto mo = thread_map_fetch_object_check(ZEND_THIS); - mo->map->clean(); +static PHP_METHOD(swoole_thread_map, values) { + auto mo = map_fetch_object_check(ZEND_THIS); + mo->map->values(return_value); } -static PHP_METHOD(swoole_thread_map, __wakeup) { - auto mo = thread_map_fetch_object(Z_OBJ_P(ZEND_THIS)); - zend_long resource_id = thread_map_get_resource_id(ZEND_THIS); - mo->map = static_cast(php_swoole_thread_resource_fetch(resource_id)); - if (!mo->map) { - zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE); - } +static PHP_METHOD(swoole_thread_map, toArray) { + auto mo = map_fetch_object_check(ZEND_THIS); + mo->map->toArray(return_value); +} + +static PHP_METHOD(swoole_thread_map, clean) { + auto mo = map_fetch_object_check(ZEND_THIS); + mo->map->clean(); } #endif diff --git a/ext-src/swoole_thread_queue.cc b/ext-src/swoole_thread_queue.cc index daa5c68a97c..f2baa099696 100644 --- a/ext-src/swoole_thread_queue.cc +++ b/ext-src/swoole_thread_queue.cc @@ -39,7 +39,7 @@ struct Queue : ThreadResource { Queue() : ThreadResource(), queue() {} - ~Queue() { + ~Queue() override { clean(); } @@ -122,30 +122,20 @@ struct ThreadQueueObject { zend_object std; }; -static sw_inline ThreadQueueObject *thread_queue_fetch_object(zend_object *obj) { +static sw_inline ThreadQueueObject *queue_fetch_object(zend_object *obj) { return (ThreadQueueObject *) ((char *) obj - swoole_thread_queue_handlers.offset); } -static sw_inline zend_long thread_queue_get_resource_id(zend_object *obj) { - zval rv, *property = zend_read_property(swoole_thread_queue_ce, obj, ZEND_STRL("id"), 1, &rv); - return property ? zval_get_long(property) : 0; -} - -static sw_inline zend_long thread_queue_get_resource_id(zval *zobject) { - return thread_queue_get_resource_id(Z_OBJ_P(zobject)); -} - -static void thread_queue_free_object(zend_object *object) { - zend_long resource_id = thread_queue_get_resource_id(object); - ThreadQueueObject *qo = thread_queue_fetch_object(object); - if (qo->queue && php_swoole_thread_resource_free(resource_id, qo->queue)) { - delete qo->queue; +static void queue_free_object(zend_object *object) { + ThreadQueueObject *qo = queue_fetch_object(object); + if (qo->queue) { + qo->queue->del_ref(); qo->queue = nullptr; } zend_object_std_dtor(object); } -static zend_object *thread_queue_create_object(zend_class_entry *ce) { +static zend_object *queue_create_object(zend_class_entry *ce) { ThreadQueueObject *qo = (ThreadQueueObject *) zend_object_alloc(sizeof(ThreadQueueObject), ce); zend_object_std_init(&qo->std, ce); object_properties_init(&qo->std, ce); @@ -153,21 +143,31 @@ static zend_object *thread_queue_create_object(zend_class_entry *ce) { return &qo->std; } -ThreadQueueObject *thread_queue_fetch_object_check(zval *zobject) { - ThreadQueueObject *qo = thread_queue_fetch_object(Z_OBJ_P(zobject)); +ThreadQueueObject *queue_fetch_object_check(zval *zobject) { + ThreadQueueObject *qo = queue_fetch_object(Z_OBJ_P(zobject)); if (!qo->queue) { php_swoole_fatal_error(E_ERROR, "must call constructor first"); } return qo; } +ThreadResource *php_swoole_thread_queue_cast(zval *zobject) { + return queue_fetch_object(Z_OBJ_P(zobject))->queue; +} + +void php_swoole_thread_queue_create(zval *return_value, ThreadResource *resource) { + auto obj = queue_create_object(swoole_thread_queue_ce); + auto qo = (ThreadQueueObject *) queue_fetch_object(obj); + qo->queue = static_cast(resource); + ZVAL_OBJ(return_value, obj); +} + SW_EXTERN_C_BEGIN static PHP_METHOD(swoole_thread_queue, __construct); static PHP_METHOD(swoole_thread_queue, push); static PHP_METHOD(swoole_thread_queue, pop); static PHP_METHOD(swoole_thread_queue, count); static PHP_METHOD(swoole_thread_queue, clean); -static PHP_METHOD(swoole_thread_queue, __wakeup); SW_EXTERN_C_END // clang-format off @@ -177,30 +177,31 @@ static const zend_function_entry swoole_thread_queue_methods[] = { PHP_ME(swoole_thread_queue, pop, arginfo_class_Swoole_Thread_Queue_pop, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_queue, clean, arginfo_class_Swoole_Thread_Queue_clean, ZEND_ACC_PUBLIC) PHP_ME(swoole_thread_queue, count, arginfo_class_Swoole_Thread_Queue_count, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_queue, __wakeup, arginfo_class_Swoole_Thread_Queue___wakeup, ZEND_ACC_PUBLIC) PHP_FE_END }; // clang-format on void php_swoole_thread_queue_minit(int module_number) { SW_INIT_CLASS_ENTRY(swoole_thread_queue, "Swoole\\Thread\\Queue", nullptr, swoole_thread_queue_methods); + swoole_thread_queue_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NOT_SERIALIZABLE; SW_SET_CLASS_CLONEABLE(swoole_thread_queue, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_thread_queue, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT( - swoole_thread_queue, thread_queue_create_object, thread_queue_free_object, ThreadQueueObject, std); + swoole_thread_queue, queue_create_object, queue_free_object, ThreadQueueObject, std); zend_class_implements(swoole_thread_queue_ce, 1, zend_ce_countable); - zend_declare_property_long(swoole_thread_queue_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); zend_declare_class_constant_long(swoole_thread_queue_ce, ZEND_STRL("NOTIFY_ONE"), Queue::NOTIFY_ONE); zend_declare_class_constant_long(swoole_thread_queue_ce, ZEND_STRL("NOTIFY_ALL"), Queue::NOTIFY_ALL); } static PHP_METHOD(swoole_thread_queue, __construct) { - auto qo = thread_queue_fetch_object(Z_OBJ_P(ZEND_THIS)); + auto qo = queue_fetch_object(Z_OBJ_P(ZEND_THIS)); + if (qo->queue != nullptr) { + zend_throw_error(NULL, "Constructor of %s can only be called once", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS)); + return; + } qo->queue = new Queue(); - auto resource_id = php_swoole_thread_resource_insert(qo->queue); - zend_update_property_long(swoole_thread_queue_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), resource_id); } static PHP_METHOD(swoole_thread_queue, push) { @@ -213,7 +214,7 @@ static PHP_METHOD(swoole_thread_queue, push) { Z_PARAM_LONG(notify_which) ZEND_PARSE_PARAMETERS_END(); - auto qo = thread_queue_fetch_object_check(ZEND_THIS); + auto qo = queue_fetch_object_check(ZEND_THIS); if (notify_which > 0) { qo->queue->push_notify(zvalue, notify_which == Queue::NOTIFY_ALL); } else { @@ -229,7 +230,7 @@ static PHP_METHOD(swoole_thread_queue, pop) { Z_PARAM_DOUBLE(timeout) ZEND_PARSE_PARAMETERS_END(); - auto qo = thread_queue_fetch_object_check(ZEND_THIS); + auto qo = queue_fetch_object_check(ZEND_THIS); if (timeout == 0) { qo->queue->pop(return_value); } else { @@ -238,22 +239,13 @@ static PHP_METHOD(swoole_thread_queue, pop) { } static PHP_METHOD(swoole_thread_queue, count) { - auto qo = thread_queue_fetch_object_check(ZEND_THIS); + auto qo = queue_fetch_object_check(ZEND_THIS); qo->queue->count(return_value); } static PHP_METHOD(swoole_thread_queue, clean) { - auto qo = thread_queue_fetch_object_check(ZEND_THIS); + auto qo = queue_fetch_object_check(ZEND_THIS); qo->queue->clean(); } -static PHP_METHOD(swoole_thread_queue, __wakeup) { - auto qo = thread_queue_fetch_object(Z_OBJ_P(ZEND_THIS)); - zend_long resource_id = thread_queue_get_resource_id(ZEND_THIS); - qo->queue = static_cast(php_swoole_thread_resource_fetch(resource_id)); - if (!qo->queue) { - zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE); - } -} - #endif diff --git a/tests/include/api/curl_multi.php b/tests/include/api/curl_multi.php index 30126dba6e0..30d457e8d8c 100644 --- a/tests/include/api/curl_multi.php +++ b/tests/include/api/curl_multi.php @@ -14,7 +14,7 @@ function swoole_test_curl_multi_ex($mh, $options = []) { curl_setopt($ch1, CURLOPT_HEADER, 0); curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch2, CURLOPT_URL, "https://www.zhihu.com/"); + curl_setopt($ch2, CURLOPT_URL, "https://www.gov.cn/"); curl_setopt($ch2, CURLOPT_HEADER, 0); curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1); @@ -61,7 +61,7 @@ function swoole_test_curl_multi_ex($mh, $options = []) { Assert::eq($info3, false); Assert::contains(curl_multi_getcontent($ch1), 'baidu.com'); - Assert::contains(curl_multi_getcontent($ch2), 'zhihu'); + Assert::contains(curl_multi_getcontent($ch2), '中国政府网'); curl_multi_remove_handle($mh, $ch1); curl_multi_remove_handle($mh, $ch2); diff --git a/tests/swoole_channel_coro/no_ctor.phpt b/tests/swoole_channel_coro/no_ctor.phpt index 1e497c6a4c9..1404f9065da 100644 --- a/tests/swoole_channel_coro/no_ctor.phpt +++ b/tests/swoole_channel_coro/no_ctor.phpt @@ -6,17 +6,21 @@ swoole_channel_coro: no ctor pop(); +$pm = ProcessManager::exec(function () { + go(function () { + $chan = new MyChan(100); + $chan->pop(); + }); }); +Assert::contains($pm->getChildOutput(), "must call constructor first"); ?> ---EXPECTF-- -Fatal error: Swoole\Coroutine\Channel::pop(): you must call Channel constructor first in %s on line %d +--EXPECT-- diff --git a/tests/swoole_curl/ssl/version.phpt b/tests/swoole_curl/ssl/version.phpt index 5647a6a0bb3..fdeb18c6e31 100644 --- a/tests/swoole_curl/ssl/version.phpt +++ b/tests/swoole_curl/ssl/version.phpt @@ -16,10 +16,10 @@ $cm->run(function ($host) { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_URL, "https://www.qq.com/"); + curl_setopt($ch, CURLOPT_URL, "https://www.baidu.com/"); $result = curl_exec($ch); Assert::assert($result); - Assert::contains($result, 'tencent'); + Assert::contains($result, '百度'); curl_close($ch); }, false); diff --git a/tests/swoole_global/channel_construct_check.phpt b/tests/swoole_global/channel_construct_check.phpt index c33fd6461d2..a796002c3a9 100644 --- a/tests/swoole_global/channel_construct_check.phpt +++ b/tests/swoole_global/channel_construct_check.phpt @@ -5,16 +5,18 @@ swoole_global: socket construct check --FILE-- push('123'); + +$pm = ProcessManager::exec(function () { + go(function () { + $chan = new class () extends Co\Channel { + public function __construct($size = 1) + { + // parent::__construct($size); // without parent call + } + }; + $chan->push('123'); + }); }); +Assert::contains($pm->getChildOutput(), "must call constructor first"); ?> ---EXPECTF-- -Fatal error: Swoole\Coroutine\Channel::push(): you must call Channel constructor first in %s on line %d +--EXPECT-- diff --git a/tests/swoole_global/socket_construct_check.phpt b/tests/swoole_global/socket_construct_check.phpt index b9c97b54c41..1a18346ffed 100644 --- a/tests/swoole_global/socket_construct_check.phpt +++ b/tests/swoole_global/socket_construct_check.phpt @@ -5,16 +5,17 @@ swoole_global: socket construct check --FILE-- connect('127.0.0.1', 12345); +$pm = ProcessManager::exec(function () { + go(function () { + $socket = new class (1, 2, 3) extends Co\Socket { + public function __construct($domain, $type, $protocol) + { + // parent::__construct($domain, $type, $protocol); // without parent call + } + }; + $socket->connect('127.0.0.1', 12345); + }); }); +Assert::contains($pm->getChildOutput(), "must call constructor first"); ?> --EXPECTF-- -Fatal error: Swoole\Coroutine\Socket::connect(): you must call Socket constructor first in %s on line %d diff --git a/tests/swoole_http2_client_coro/connect_twice.phpt b/tests/swoole_http2_client_coro/connect_twice.phpt index 798ca5f724b..88ff09e8a2f 100644 --- a/tests/swoole_http2_client_coro/connect_twice.phpt +++ b/tests/swoole_http2_client_coro/connect_twice.phpt @@ -6,29 +6,33 @@ swoole_http2_client_coro: connect twice connect(); - $req = new \Swoole\Http2\Request(); + $req = new Request(); + $uuid = uniqid(); $req->method = 'GET'; - $req->path = '/io?io=' . str_repeat('xxx', 1000); + $req->path = '/base64/' . base64_encode($uuid); $client->send($req); $chan->push(true); $resp = $client->recv(); Assert::eq($resp->statusCode, 200); - Assert::contains($resp->data, '知乎'); + Assert::eq($resp->data, $uuid); $chan->pop(); }); go(function () use ($client, $chan) { Assert::eq($client->connect(), false); - $req = new \Swoole\Http2\Request(); + $uuid = uniqid(); + $req = new Request(); $req->method = 'GET'; - $req->path = '/io?io=xxx'; + $req->path = '/base64/' . base64_encode($uuid); $client->send($req); $chan->push(true); Assert::eq($client->recv(), false); diff --git a/tests/swoole_http_client_coro/http_proxy.phpt b/tests/swoole_http_client_coro/http_proxy.phpt index 21158bd5fc3..af8d9c39619 100644 --- a/tests/swoole_http_client_coro/http_proxy.phpt +++ b/tests/swoole_http_client_coro/http_proxy.phpt @@ -10,7 +10,7 @@ skip_if_offline(); setHeaders(['Host' => $domain]); // without host header it can also work well $cli->set([ @@ -20,7 +20,7 @@ go(function () { ]); $result = $cli->get('/'); Assert::assert($result); - Assert::assert(stripos($cli->body, 'tencent') !== false); + Assert::assert(stripos($cli->body, '百度') !== false); echo "DONE\n"; }); ?> diff --git a/tests/swoole_thread/arraylist.phpt b/tests/swoole_thread/arraylist.phpt new file mode 100644 index 00000000000..2e9cd5967d3 --- /dev/null +++ b/tests/swoole_thread/arraylist.phpt @@ -0,0 +1,43 @@ +--TEST-- +swoole_thread: arraylist +--SKIPIF-- + +--FILE-- +toArray(), $array); + +for ($i = 0; $i < count($array); $i++) { + Assert::eq($l[$i], $array[$i]); +} + +$array2 = [ + 'key' => 'value', + 'hello' => 'world', +]; +$l[] = $array2; + +Assert::eq($l[4]->toArray(), $array2); + +try { + $l2 = new ArrayList($array2); + echo "never here\n"; +} catch (Throwable $e) { + Assert::contains($e->getMessage(), 'must be an array of type list'); +} +?> +--EXPECTF-- diff --git a/tests/swoole_thread/empty_args.phpt b/tests/swoole_thread/empty_args.phpt new file mode 100644 index 00000000000..8733dbfc040 --- /dev/null +++ b/tests/swoole_thread/empty_args.phpt @@ -0,0 +1,17 @@ +--TEST-- +swoole_thread: info +--SKIPIF-- + +--FILE-- + +--EXPECTF-- diff --git a/tests/swoole_thread/map.phpt b/tests/swoole_thread/map.phpt new file mode 100644 index 00000000000..101bf05f8ae --- /dev/null +++ b/tests/swoole_thread/map.phpt @@ -0,0 +1,37 @@ +--TEST-- +swoole_thread: map +--SKIPIF-- + +--FILE-- + random_int(1, 999999999999999999), + 'b' => random_bytes(128), + 'c' => uniqid(), + 'd' => time(), +]; + +$m = new Map($array); +Assert::eq($m->toArray(), $array); + +foreach ($array as $k => $v) { + Assert::eq($m[$k], $array[$k]); +} + +$array2 = [ + 'key' => 'value', + 'hello' => 'world', +]; +$m['map'] = $array2; + +Assert::eq($m['map']->toArray(), $array2); +Assert::eq($m['map']->values(), array_values($array2)); +?> +--EXPECTF--