diff --git a/ext-src/php_swoole.cc b/ext-src/php_swoole.cc index f290005b060..196c8238cd3 100644 --- a/ext-src/php_swoole.cc +++ b/ext-src/php_swoole.cc @@ -749,6 +749,11 @@ PHP_MINIT_FUNCTION(swoole) { #endif #ifdef SW_THREAD php_swoole_thread_minit(module_number); + php_swoole_thread_atomic_minit(module_number); + php_swoole_thread_lock_minit(module_number); + php_swoole_thread_queue_minit(module_number); + php_swoole_thread_map_minit(module_number); + php_swoole_thread_arraylist_minit(module_number); #endif SwooleG.fatal_error = fatal_error; diff --git a/ext-src/php_swoole_private.h b/ext-src/php_swoole_private.h index 38d10cad617..46272a5e344 100644 --- a/ext-src/php_swoole_private.h +++ b/ext-src/php_swoole_private.h @@ -269,6 +269,11 @@ void php_swoole_redis_server_minit(int module_number); void php_swoole_name_resolver_minit(int module_number); #ifdef SW_THREAD void php_swoole_thread_minit(int module_number); +void php_swoole_thread_atomic_minit(int module_number); +void php_swoole_thread_lock_minit(int module_number); +void php_swoole_thread_queue_minit(int module_number); +void php_swoole_thread_map_minit(int module_number); +void php_swoole_thread_arraylist_minit(int module_number); #endif /** diff --git a/ext-src/php_swoole_thread.h b/ext-src/php_swoole_thread.h index 78fa5176920..096a834ba68 100644 --- a/ext-src/php_swoole_thread.h +++ b/ext-src/php_swoole_thread.h @@ -21,6 +21,8 @@ #ifdef SW_THREAD +#include "swoole_lock.h" + typedef uint32_t ThreadResourceId; struct ThreadResource; @@ -55,4 +57,273 @@ struct ThreadResource { } }; + +struct ArrayItem { + uint32_t type; + zend_string *key; + union { + zend_string *str; + zend_long lval; + double dval; + zend_string *serialized_object; + } value; + + ArrayItem(zval *zvalue) { + key = nullptr; + value = {}; + store(zvalue); + } + + void store(zval *zvalue) { + type = Z_TYPE_P(zvalue); + switch (type) { + case IS_LONG: + value.lval = zval_get_long(zvalue); + break; + case IS_DOUBLE: + value.dval = zval_get_double(zvalue); + break; + case IS_STRING: { + value.str = zend_string_init(Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue), 1); + break; + case IS_TRUE: + case IS_FALSE: + case IS_NULL: + break; + } + default: { + auto _serialized_object = php_swoole_thread_serialize(zvalue); + if (!_serialized_object) { + type = IS_UNDEF; + break; + } else { + type = IS_SERIALIZED_OBJECT; + value.serialized_object = _serialized_object; + } + break; + } + } + } + + void fetch(zval *return_value) { + switch (type) { + case IS_LONG: + RETVAL_LONG(value.lval); + break; + case IS_DOUBLE: + RETVAL_LONG(value.dval); + break; + case IS_TRUE: + RETVAL_TRUE; + break; + case IS_FALSE: + RETVAL_FALSE; + break; + case IS_STRING: + RETVAL_NEW_STR(zend_string_init(ZSTR_VAL(value.str), ZSTR_LEN(value.str), 0)); + break; + case IS_SERIALIZED_OBJECT: + php_swoole_thread_unserialize(value.serialized_object, return_value); + break; + default: + break; + } + } + + void release() { + if (type == IS_STRING) { + zend_string_release(value.str); + value.str = nullptr; + } else if (type == IS_SERIALIZED_OBJECT) { + zend_string_release(value.serialized_object); + value.serialized_object = nullptr; + } + } + + ~ArrayItem() { + if (value.str) { + release(); + } + if (key) { + zend_string_release(key); + } + } +}; + +struct ZendArray : ThreadResource { + swoole::RWLock lock_; + zend_array ht; + + static void item_dtor(zval *pDest) { + ArrayItem *item = (ArrayItem *) Z_PTR_P(pDest); + delete item; + } + + ZendArray() : ThreadResource(), lock_(0) { + zend_hash_init(&ht, 0, NULL, item_dtor, 1); + } + + ~ZendArray() { + zend_hash_destroy(&ht); + } + + void clean() { + lock_.lock(); + zend_hash_clean(&ht); + lock_.unlock(); + } + + bool index_exists(zend_long index) { + return index < (zend_long) zend_hash_num_elements(&ht); + } + + void strkey_offsetGet(zval *zkey, zval *return_value) { + zend::String skey(zkey); + lock_.lock_rd(); + ArrayItem *item = (ArrayItem *) zend_hash_find_ptr(&ht, skey.get()); + if (item) { + item->fetch(return_value); + } + lock_.unlock(); + } + + void strkey_offsetExists(zval *zkey, zval *return_value) { + zend::String skey(zkey); + lock_.lock_rd(); + RETVAL_BOOL(zend_hash_find_ptr(&ht, skey.get()) != NULL); + lock_.unlock(); + } + + void strkey_offsetUnset(zval *zkey) { + zend::String skey(zkey); + lock_.lock(); + zend_hash_del(&ht, skey.get()); + lock_.unlock(); + } + + void strkey_offsetSet(zval *zkey, zval *zvalue) { + zend::String skey(zkey); + auto item = new ArrayItem(zvalue); + item->key = zend_string_init(skey.val(), skey.len(), 1); + lock_.lock(); + zend_hash_update_ptr(&ht, item->key, item); + lock_.unlock(); + } + + void count(zval *return_value) { + lock_.lock_rd(); + RETVAL_LONG(zend_hash_num_elements(&ht)); + lock_.unlock(); + } + + void keys(zval *return_value) { + lock_.lock_rd(); + zend_ulong elem_count = zend_hash_num_elements(&ht); + array_init_size(return_value, elem_count); + zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); + zend_ulong num_idx; + zend_string *str_idx; + zval *entry; + ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { + if (HT_IS_PACKED(&ht) && HT_IS_WITHOUT_HOLES(&ht)) { + /* Optimistic case: range(0..n-1) for vector-like packed array */ + zend_ulong lval = 0; + + for (; lval < elem_count; ++lval) { + ZEND_HASH_FILL_SET_LONG(lval); + ZEND_HASH_FILL_NEXT(); + } + } else { + /* Go through input array and add keys to the return array */ + ZEND_HASH_FOREACH_KEY_VAL(&ht, num_idx, str_idx, entry) { + if (str_idx) { + ZEND_HASH_FILL_SET_STR(zend_string_init(str_idx->val, str_idx->len, 0)); + } else { + ZEND_HASH_FILL_SET_LONG(num_idx); + } + ZEND_HASH_FILL_NEXT(); + } + ZEND_HASH_FOREACH_END(); + } + (void) entry; + } + ZEND_HASH_FILL_END(); + lock_.unlock(); + } + + void intkey_offsetGet(zend_long index, zval *return_value) { + lock_.lock_rd(); + ArrayItem *item = (ArrayItem *) zend_hash_index_find_ptr(&ht, index); + if (item) { + item->fetch(return_value); + } + lock_.unlock(); + } + + void intkey_offsetGet(zval *zkey, zval *return_value) { + intkey_offsetGet(zval_get_long(zkey), return_value); + } + + void intkey_offsetExists(zval *zkey, zval *return_value) { + zend_long index = zval_get_long(zkey); + lock_.lock_rd(); + RETVAL_BOOL(zend_hash_index_find_ptr(&ht, index) != NULL); + lock_.unlock(); + } + + void intkey_offsetUnset(zval *zkey) { + zend_long index = zval_get_long(zkey); + lock_.lock(); + zend_hash_index_del(&ht, index); + lock_.unlock(); + } + + void intkey_offsetSet(zval *zkey, zval *zvalue) { + zend_long index = zval_get_long(zkey); + auto item = new ArrayItem(zvalue); + lock_.lock(); + zend_hash_index_update_ptr(&ht, index, item); + lock_.unlock(); + } + + bool index_offsetGet(zval *zkey, zval *return_value) { + zend_long index = zval_get_long(zkey); + bool out_of_range = true; + lock_.lock_rd(); + if (index_exists(index)) { + out_of_range = false; + ArrayItem *item = (ArrayItem *) zend_hash_index_find_ptr(&ht, index); + if (item) { + item->fetch(return_value); + } + } + lock_.unlock(); + return !out_of_range; + } + + bool index_offsetSet(zval *zkey, zval *zvalue) { + zend_long index = ZVAL_IS_NULL(zkey) ? -1 : zval_get_long(zkey); + auto item = new ArrayItem(zvalue); + bool success = true; + lock_.lock(); + if (index > zend_hash_num_elements(&ht)) { + success = false; + delete item; + } else if (index == -1 || index == zend_hash_num_elements(&ht)) { + zend_hash_next_index_insert_ptr(&ht, item); + } else { + zend_hash_index_update_ptr(&ht, index, item); + } + lock_.unlock(); + return success; + } + + void index_offsetExists(zval *zkey, zval *return_value) { + zend_long index = zval_get_long(zkey); + lock_.lock_rd(); + RETVAL_BOOL(index_exists(index)); + lock_.unlock(); + } +}; + #endif diff --git a/ext-src/stubs/php_swoole_atomic.stub.php b/ext-src/stubs/php_swoole_atomic.stub.php index 71bb5eec9d4..adfd74b0f5f 100644 --- a/ext-src/stubs/php_swoole_atomic.stub.php +++ b/ext-src/stubs/php_swoole_atomic.stub.php @@ -9,9 +9,6 @@ public function set(int $value): void {} public function cmpset(int $cmp_value, int $new_value): bool {} public function wait(float $timeout = 1.0): bool {} public function wakeup(int $count = 1): bool {} - #ifdef SW_THREAD - public function __wakeup(): void {} - #endif } } @@ -23,8 +20,5 @@ public function sub(int $sub_value = 1): int {} public function get(): int {} public function set(int $value): void {} public function cmpset(int $cmp_value, int $new_value): bool {} - #ifdef SW_THREAD - public function __wakeup(): void {} - #endif } } diff --git a/ext-src/stubs/php_swoole_atomic_arginfo.h b/ext-src/stubs/php_swoole_atomic_arginfo.h index 62fb6bf7dd1..fbf4d01aa4d 100644 --- a/ext-src/stubs/php_swoole_atomic_arginfo.h +++ b/ext-src/stubs/php_swoole_atomic_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 081724c8ea467fa6daf08906f0d0fcb7603795ed */ + * Stub hash: 7c83f8fbe7fd48ac2c7a2756a4e33a9edd666e42 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Swoole_Atomic___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_LONG, 0, "0") @@ -33,11 +33,6 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Atomic_wakeup, 0, 0 ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "1") ZEND_END_ARG_INFO() -#if defined(SW_THREAD) -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Atomic___wakeup, 0, 0, IS_VOID, 0) -ZEND_END_ARG_INFO() -#endif - #define arginfo_class_Swoole_Atomic_Long___construct arginfo_class_Swoole_Atomic___construct #define arginfo_class_Swoole_Atomic_Long_add arginfo_class_Swoole_Atomic_add @@ -49,7 +44,3 @@ ZEND_END_ARG_INFO() #define arginfo_class_Swoole_Atomic_Long_set arginfo_class_Swoole_Atomic_set #define arginfo_class_Swoole_Atomic_Long_cmpset arginfo_class_Swoole_Atomic_cmpset - -#if defined(SW_THREAD) -#define arginfo_class_Swoole_Atomic_Long___wakeup arginfo_class_Swoole_Atomic___wakeup -#endif diff --git a/ext-src/stubs/php_swoole_lock.stub.php b/ext-src/stubs/php_swoole_lock.stub.php index 7c23e7a8532..9ad3c621b20 100644 --- a/ext-src/stubs/php_swoole_lock.stub.php +++ b/ext-src/stubs/php_swoole_lock.stub.php @@ -1,7 +1,7 @@ -#include - -static sw_inline int swoole_futex_wait(sw_atomic_t *atomic, double timeout) { - if (sw_atomic_cmp_set(atomic, 1, 0)) { - return SW_OK; - } - - int ret; - struct timespec _timeout; - - if (timeout > 0) { - _timeout.tv_sec = (long) timeout; - _timeout.tv_nsec = (timeout - _timeout.tv_sec) * 1000 * 1000 * 1000; - ret = syscall(SYS_futex, atomic, FUTEX_WAIT, 0, &_timeout, nullptr, 0); - } else { - ret = syscall(SYS_futex, atomic, FUTEX_WAIT, 0, nullptr, nullptr, 0); - } - if (ret == SW_OK && sw_atomic_cmp_set(atomic, 1, 0)) { - return SW_OK; - } else { - return SW_ERR; - } -} - -static sw_inline int swoole_futex_wakeup(sw_atomic_t *atomic, int n) { - if (sw_atomic_cmp_set(atomic, 0, 1)) { - return syscall(SYS_futex, atomic, FUTEX_WAKE, n, nullptr, nullptr, 0); - } else { - return SW_OK; - } -} - -#else -static sw_inline int swoole_atomic_wait(sw_atomic_t *atomic, double timeout) { - if (sw_atomic_cmp_set(atomic, (sw_atomic_t) 1, (sw_atomic_t) 0)) { - return SW_OK; - } - timeout = timeout <= 0 ? INT_MAX : timeout; - int32_t i = (int32_t) sw_atomic_sub_fetch(atomic, 1); - while (timeout > 0) { - if ((int32_t) *atomic > i) { - return SW_OK; - } else { - usleep(1000); - timeout -= 0.001; - } - } - sw_atomic_fetch_add(atomic, 1); - return SW_ERR; -} - -static sw_inline int swoole_atomic_wakeup(sw_atomic_t *atomic, int n) { - if (1 == (int32_t) *atomic) { - return SW_OK; - } - sw_atomic_fetch_add(atomic, n); - return SW_OK; -} -#endif - zend_class_entry *swoole_atomic_ce; static zend_object_handlers swoole_atomic_handlers; zend_class_entry *swoole_atomic_long_ce; static zend_object_handlers swoole_atomic_long_handlers; -#ifdef SW_THREAD -struct AtomicResource: public ThreadResource { - sw_atomic_t *ptr_; - AtomicResource(): ThreadResource() { - ptr_ = new sw_atomic_t; - } - ~AtomicResource() { - delete ptr_; - } -}; -#endif - struct AtomicObject { sw_atomic_t *ptr; -#ifdef SW_THREAD - AtomicResource *res; -#endif zend_object std; }; @@ -123,17 +45,7 @@ void php_swoole_atomic_set_ptr(zval *zobject, sw_atomic_t *ptr) { } static void php_swoole_atomic_free_object(zend_object *object) { -#ifdef SW_THREAD - AtomicObject *o = php_swoole_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; - o->ptr = nullptr; - } -#else sw_mem_pool()->free((void *) php_swoole_atomic_fetch_object(object)->ptr); -#endif zend_object_std_dtor(object); } @@ -146,34 +58,16 @@ static zend_object *php_swoole_atomic_create_object(zend_class_entry *ce) { zend_object_std_init(&atomic->std, ce); object_properties_init(&atomic->std, ce); atomic->std.handlers = &swoole_atomic_handlers; - -#ifndef SW_THREAD atomic->ptr = (sw_atomic_t *) sw_mem_pool()->alloc(sizeof(sw_atomic_t)); if (atomic->ptr == nullptr) { zend_throw_exception(swoole_exception_ce, "global memory allocation failure", SW_ERROR_MALLOC_FAIL); } -#endif return &atomic->std; } -#ifdef SW_THREAD -struct AtomicLongResource: public ThreadResource { - sw_atomic_long_t *ptr_; - AtomicLongResource(): ThreadResource() { - ptr_ = new sw_atomic_long_t; - } - ~AtomicLongResource() { - delete ptr_; - } -}; -#endif - struct AtomicLongObject { sw_atomic_long_t *ptr; -#ifdef SW_THREAD - AtomicLongResource *res; -#endif zend_object std; }; @@ -190,18 +84,7 @@ void php_swoole_atomic_long_set_ptr(zval *zobject, sw_atomic_long_t *ptr) { } static void php_swoole_atomic_long_free_object(zend_object *object) { -#ifdef SW_THREAD - AtomicLongObject *o = php_swoole_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; - o->ptr = nullptr; - } -#else sw_mem_pool()->free((void *) php_swoole_atomic_long_fetch_object(object)->ptr); -#endif - zend_object_std_dtor(object); } @@ -215,12 +98,10 @@ static zend_object *php_swoole_atomic_long_create_object(zend_class_entry *ce) { object_properties_init(&atomic_long->std, ce); atomic_long->std.handlers = &swoole_atomic_long_handlers; -#ifndef SW_THREAD atomic_long->ptr = (sw_atomic_long_t *) sw_mem_pool()->alloc(sizeof(sw_atomic_long_t)); if (atomic_long->ptr == nullptr) { zend_throw_exception(swoole_exception_ce, "global memory allocation failure", SW_ERROR_MALLOC_FAIL); } -#endif return &atomic_long->std; } @@ -234,9 +115,6 @@ static PHP_METHOD(swoole_atomic, set); static PHP_METHOD(swoole_atomic, cmpset); static PHP_METHOD(swoole_atomic, wait); static PHP_METHOD(swoole_atomic, wakeup); -#ifdef SW_THREAD -static PHP_METHOD(swoole_atomic, __wakeup); -#endif static PHP_METHOD(swoole_atomic_long, __construct); static PHP_METHOD(swoole_atomic_long, add); @@ -244,9 +122,6 @@ static PHP_METHOD(swoole_atomic_long, sub); static PHP_METHOD(swoole_atomic_long, get); static PHP_METHOD(swoole_atomic_long, set); static PHP_METHOD(swoole_atomic_long, cmpset); -#ifdef SW_THREAD -static PHP_METHOD(swoole_atomic_long, __wakeup); -#endif SW_EXTERN_C_END // clang-format off @@ -261,9 +136,6 @@ static const zend_function_entry swoole_atomic_methods[] = PHP_ME(swoole_atomic, wait, arginfo_class_Swoole_Atomic_wait, ZEND_ACC_PUBLIC) PHP_ME(swoole_atomic, wakeup, arginfo_class_Swoole_Atomic_wakeup, ZEND_ACC_PUBLIC) PHP_ME(swoole_atomic, cmpset, arginfo_class_Swoole_Atomic_cmpset, ZEND_ACC_PUBLIC) -#ifdef SW_THREAD - PHP_ME(swoole_atomic, __wakeup, arginfo_class_Swoole_Atomic___wakeup, ZEND_ACC_PUBLIC) -#endif PHP_FE_END }; @@ -275,9 +147,6 @@ static const zend_function_entry swoole_atomic_long_methods[] = PHP_ME(swoole_atomic_long, get, arginfo_class_Swoole_Atomic_Long_get, ZEND_ACC_PUBLIC) PHP_ME(swoole_atomic_long, set, arginfo_class_Swoole_Atomic_Long_set, ZEND_ACC_PUBLIC) PHP_ME(swoole_atomic_long, cmpset, arginfo_class_Swoole_Atomic_Long_cmpset, ZEND_ACC_PUBLIC) -#ifdef SW_THREAD - PHP_ME(swoole_atomic_long, __wakeup, arginfo_class_Swoole_Atomic_Long___wakeup, ZEND_ACC_PUBLIC) -#endif PHP_FE_END }; @@ -285,22 +154,14 @@ static const zend_function_entry swoole_atomic_long_methods[] = void php_swoole_atomic_minit(int module_number) { SW_INIT_CLASS_ENTRY(swoole_atomic, "Swoole\\Atomic", nullptr, swoole_atomic_methods); -#ifndef SW_THREAD SW_SET_CLASS_NOT_SERIALIZABLE(swoole_atomic); -#else - zend_declare_property_long(swoole_atomic_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC); -#endif SW_SET_CLASS_CLONEABLE(swoole_atomic, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_atomic, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT( swoole_atomic, php_swoole_atomic_create_object, php_swoole_atomic_free_object, AtomicObject, std); SW_INIT_CLASS_ENTRY(swoole_atomic_long, "Swoole\\Atomic\\Long", nullptr, swoole_atomic_long_methods); -#ifndef SW_THREAD SW_SET_CLASS_NOT_SERIALIZABLE(swoole_atomic_long); -#else - zend_declare_property_long(swoole_atomic_long_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC); -#endif SW_SET_CLASS_CLONEABLE(swoole_atomic_long, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_atomic_long, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT(swoole_atomic_long, @@ -311,7 +172,7 @@ void php_swoole_atomic_minit(int module_number) { } PHP_METHOD(swoole_atomic, __construct) { - auto o = php_swoole_atomic_fetch_object(Z_OBJ_P(ZEND_THIS)); + sw_atomic_t *atomic = php_swoole_atomic_get_ptr(ZEND_THIS); zend_long value = 0; ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) @@ -319,18 +180,7 @@ PHP_METHOD(swoole_atomic, __construct) { Z_PARAM_LONG(value) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); -#ifdef SW_THREAD - if (o->ptr) { - 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 AtomicResource(); - auto resource_id = php_swoole_thread_resource_insert(o->res); - zend_update_property_long(swoole_atomic_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), resource_id); - o->ptr = o->res->ptr_; -#endif - - *o->ptr = (sw_atomic_t) value; + *atomic = (sw_atomic_t) value; } PHP_METHOD(swoole_atomic, add) { @@ -394,11 +244,7 @@ PHP_METHOD(swoole_atomic, wait) { Z_PARAM_DOUBLE(timeout) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); -#ifdef HAVE_FUTEX - SW_CHECK_RETURN(swoole_futex_wait(atomic, timeout)); -#else - SW_CHECK_RETURN(swoole_atomic_wait(atomic, timeout)); -#endif + SW_CHECK_RETURN(sw_atomic_futex_wait(atomic, timeout)); } PHP_METHOD(swoole_atomic, wakeup) { @@ -410,28 +256,11 @@ PHP_METHOD(swoole_atomic, wakeup) { Z_PARAM_LONG(n) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); -#ifdef HAVE_FUTEX - SW_CHECK_RETURN(swoole_futex_wakeup(atomic, (int) n)); -#else - SW_CHECK_RETURN(swoole_atomic_wakeup(atomic, n)); -#endif + SW_CHECK_RETURN(sw_atomic_futex_wakeup(atomic, (int) n)); } -#ifdef SW_THREAD -static PHP_METHOD(swoole_atomic, __wakeup) { - auto o = php_swoole_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; - } - o->ptr = o->res->ptr_; -} -#endif - PHP_METHOD(swoole_atomic_long, __construct) { - auto o = php_swoole_atomic_long_fetch_object(Z_OBJ_P(ZEND_THIS)); + sw_atomic_long_t *atomic_long = php_swoole_atomic_long_get_ptr(ZEND_THIS); zend_long value = 0; ZEND_PARSE_PARAMETERS_START(0, 1) @@ -439,18 +268,8 @@ PHP_METHOD(swoole_atomic_long, __construct) { Z_PARAM_LONG(value) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); -#ifdef SW_THREAD - if (o->ptr) { - 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_atomic_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), resource_id); - o->ptr = o->res->ptr_; -#endif - - *o->ptr = (sw_atomic_long_t) value; + *atomic_long = (sw_atomic_long_t) value; + RETURN_TRUE; } PHP_METHOD(swoole_atomic_long, add) { @@ -504,16 +323,3 @@ PHP_METHOD(swoole_atomic_long, cmpset) { RETURN_BOOL(sw_atomic_cmp_set(atomic_long, (sw_atomic_long_t) cmp_value, (sw_atomic_long_t) set_value)); } - -#ifdef SW_THREAD -static PHP_METHOD(swoole_atomic_long, __wakeup) { - auto o = php_swoole_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; - } - o->ptr = o->res->ptr_; -} -#endif diff --git a/ext-src/swoole_lock.cc b/ext-src/swoole_lock.cc index 4ac88051866..9effbb595e6 100644 --- a/ext-src/swoole_lock.cc +++ b/ext-src/swoole_lock.cc @@ -15,7 +15,6 @@ */ #include "php_swoole_private.h" -#include "php_swoole_thread.h" #include "swoole_memory.h" #include "swoole_lock.h" @@ -35,23 +34,8 @@ using swoole::RWLock; static zend_class_entry *swoole_lock_ce; static zend_object_handlers swoole_lock_handlers; -#ifdef SW_THREAD -struct LockResource: public ThreadResource { - Lock *lock_; - LockResource(Lock *lock): ThreadResource() { - lock_ = lock; - } - ~LockResource() { - delete lock_; - } -}; -#endif - struct LockObject { Lock *lock; -#ifdef SW_THREAD - LockResource *lock_res; -#endif zend_object std; }; @@ -77,18 +61,9 @@ void php_swoole_lock_set_ptr(zval *zobject, Lock *ptr) { static void php_swoole_lock_free_object(zend_object *object) { LockObject *o = php_swoole_lock_fetch_object(object); -#ifdef SW_THREAD - zend_long resource_id = zend::object_get_long(object, ZEND_STRL("id")); - if (o->lock_res && php_swoole_thread_resource_free(resource_id, o->lock_res)) { - delete o->lock_res; - o->lock_res = nullptr; - o->lock = nullptr; - } -#else if (o->lock) { delete o->lock; } -#endif zend_object_std_dtor(object); } @@ -110,9 +85,6 @@ static PHP_METHOD(swoole_lock, lock_read); static PHP_METHOD(swoole_lock, trylock_read); static PHP_METHOD(swoole_lock, unlock); static PHP_METHOD(swoole_lock, destroy); -#ifdef SW_THREAD -static PHP_METHOD(swoole_lock, __wakeup); -#endif SW_EXTERN_C_END // clang-format off @@ -127,20 +99,13 @@ static const zend_function_entry swoole_lock_methods[] = PHP_ME(swoole_lock, trylock_read, arginfo_class_Swoole_Lock_trylock_read, ZEND_ACC_PUBLIC) PHP_ME(swoole_lock, unlock, arginfo_class_Swoole_Lock_unlock, ZEND_ACC_PUBLIC) PHP_ME(swoole_lock, destroy, arginfo_class_Swoole_Lock_destroy, ZEND_ACC_PUBLIC) -#ifdef SW_THREAD - PHP_ME(swoole_lock, __wakeup, arginfo_class_Swoole_Lock___wakeup, ZEND_ACC_PUBLIC) -#endif PHP_FE_END }; // clang-format on void php_swoole_lock_minit(int module_number) { SW_INIT_CLASS_ENTRY(swoole_lock, "Swoole\\Lock", nullptr, swoole_lock_methods); -#ifndef SW_THREAD SW_SET_CLASS_NOT_SERIALIZABLE(swoole_lock); -#else - zend_declare_property_long(swoole_lock_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC); -#endif SW_SET_CLASS_CLONEABLE(swoole_lock, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_lock, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT( @@ -154,9 +119,6 @@ void php_swoole_lock_minit(int module_number) { zend_declare_class_constant_long(swoole_lock_ce, ZEND_STRL("SPINLOCK"), Lock::SPIN_LOCK); #endif zend_declare_property_long(swoole_lock_ce, ZEND_STRL("errCode"), 0, ZEND_ACC_PUBLIC); -#ifdef SW_THREAD - zend_declare_property_long(swoole_lock_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); -#endif SW_REGISTER_LONG_CONSTANT("SWOOLE_MUTEX", Lock::MUTEX); #ifdef HAVE_RWLOCK @@ -168,47 +130,40 @@ void php_swoole_lock_minit(int module_number) { } static PHP_METHOD(swoole_lock, __construct) { - auto o = php_swoole_lock_fetch_object(Z_OBJ_P(ZEND_THIS)); - if (o->lock != nullptr) { + Lock *lock = php_swoole_lock_get_ptr(ZEND_THIS); + if (lock != nullptr) { zend_throw_error(NULL, "Constructor of %s can only be called once", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS)); RETURN_FALSE; } - zend_long type = swoole::Lock::MUTEX; - - ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_LONG(type) - ZEND_PARSE_PARAMETERS_END(); + zend_long type = Lock::MUTEX; + char *filelock; + size_t filelock_len = 0; -#ifdef SW_THREAD - bool process_shared = false; -#else - bool process_shared = true; -#endif + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ls", &type, &filelock, &filelock_len) == FAILURE) { + RETURN_FALSE; + } - Lock *lock; switch (type) { #ifdef HAVE_SPINLOCK case Lock::SPIN_LOCK: - lock = new SpinLock(process_shared ? 1 : 0); + lock = new SpinLock(1); break; #endif #ifdef HAVE_RWLOCK case Lock::RW_LOCK: - lock = new RWLock(process_shared ? 1 : 0); + lock = new RWLock(1); break; #endif case Lock::MUTEX: + lock = new Mutex(Mutex::PROCESS_SHARED); + break; default: - lock = new Mutex(process_shared ? Mutex::PROCESS_SHARED: 0); + zend_throw_exception( + swoole_exception_ce, "lock type[%d] is not support", type); + RETURN_FALSE; break; } -#ifdef SW_THREAD - o->lock_res = new LockResource(lock); - auto resource_id = php_swoole_thread_resource_insert(o->lock_res); - zend_update_property_long(swoole_lock_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), resource_id); -#endif php_swoole_lock_set_ptr(ZEND_THIS, lock); RETURN_TRUE; } @@ -260,22 +215,7 @@ static PHP_METHOD(swoole_lock, lock_read) { } static PHP_METHOD(swoole_lock, destroy) { -#ifndef SW_THREAD Lock *lock = php_swoole_lock_get_and_check_ptr(ZEND_THIS); delete lock; php_swoole_lock_set_ptr(ZEND_THIS, nullptr); -#endif -} - -#ifdef SW_THREAD -static PHP_METHOD(swoole_lock, __wakeup) { - auto o = php_swoole_lock_fetch_object(Z_OBJ_P(ZEND_THIS)); - zend_long resource_id = zend::object_get_long(ZEND_THIS, ZEND_STRL("id")); - o->lock_res = static_cast(php_swoole_thread_resource_fetch(resource_id)); - if (!o->lock_res) { - zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE); - return; - } - php_swoole_lock_set_ptr(ZEND_THIS, o->lock_res->lock_); } -#endif diff --git a/ext-src/swoole_thread.cc b/ext-src/swoole_thread.cc index 3dcb24a5dbe..244ef90efb8 100644 --- a/ext-src/swoole_thread.cc +++ b/ext-src/swoole_thread.cc @@ -23,7 +23,6 @@ #include #include -#include #include "swoole_lock.h" @@ -31,290 +30,11 @@ BEGIN_EXTERN_C() #include "stubs/php_swoole_thread_arginfo.h" END_EXTERN_C() -using swoole::RWLock; - zend_class_entry *swoole_thread_ce; static zend_object_handlers swoole_thread_handlers; -zend_class_entry *swoole_thread_map_ce; -static zend_object_handlers swoole_thread_map_handlers; - -zend_class_entry *swoole_thread_arraylist_ce; -static zend_object_handlers swoole_thread_arraylist_handlers; - -zend_class_entry *swoole_thread_queue_ce; -static zend_object_handlers swoole_thread_queue_handlers; - TSRMLS_CACHE_DEFINE(); -struct ArrayItem { - uint32_t type; - zend_string *key; - union { - zend_string *str; - zend_long lval; - double dval; - zend_string *serialized_object; - } value; - - ArrayItem(zval *zvalue) { - key = nullptr; - value = {}; - store(zvalue); - } - - void store(zval *zvalue) { - type = Z_TYPE_P(zvalue); - switch (type) { - case IS_LONG: - value.lval = zval_get_long(zvalue); - break; - case IS_DOUBLE: - value.dval = zval_get_double(zvalue); - break; - case IS_STRING: { - value.str = zend_string_init(Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue), 1); - break; - case IS_TRUE: - case IS_FALSE: - case IS_NULL: - break; - } - default: { - auto _serialized_object = php_swoole_thread_serialize(zvalue); - if (!_serialized_object) { - type = IS_UNDEF; - break; - } else { - type = IS_SERIALIZED_OBJECT; - value.serialized_object = _serialized_object; - } - break; - } - } - } - - void fetch(zval *return_value) { - switch (type) { - case IS_LONG: - RETVAL_LONG(value.lval); - break; - case IS_DOUBLE: - RETVAL_LONG(value.dval); - break; - case IS_TRUE: - RETVAL_TRUE; - break; - case IS_FALSE: - RETVAL_FALSE; - break; - case IS_STRING: - RETVAL_NEW_STR(zend_string_init(ZSTR_VAL(value.str), ZSTR_LEN(value.str), 0)); - break; - case IS_SERIALIZED_OBJECT: - php_swoole_thread_unserialize(value.serialized_object, return_value); - break; - default: - break; - } - } - - void release() { - if (type == IS_STRING) { - zend_string_release(value.str); - value.str = nullptr; - } else if (type == IS_SERIALIZED_OBJECT) { - zend_string_release(value.serialized_object); - value.serialized_object = nullptr; - } - } - - ~ArrayItem() { - if (value.str) { - release(); - } - if (key) { - zend_string_release(key); - } - } -}; - -struct ZendArray : ThreadResource { - RWLock lock_; - zend_array ht; - - static void item_dtor(zval *pDest) { - ArrayItem *item = (ArrayItem *) Z_PTR_P(pDest); - delete item; - } - - ZendArray() : ThreadResource(), lock_(0) { - zend_hash_init(&ht, 0, NULL, item_dtor, 1); - } - - ~ZendArray() { - zend_hash_destroy(&ht); - } - - void clean() { - lock_.lock(); - zend_hash_clean(&ht); - lock_.unlock(); - } - - bool index_exists(zend_long index) { - return index < (zend_long) zend_hash_num_elements(&ht); - } - - void strkey_offsetGet(zval *zkey, zval *return_value) { - zend::String skey(zkey); - lock_.lock_rd(); - ArrayItem *item = (ArrayItem *) zend_hash_find_ptr(&ht, skey.get()); - if (item) { - item->fetch(return_value); - } - lock_.unlock(); - } - - void strkey_offsetExists(zval *zkey, zval *return_value) { - zend::String skey(zkey); - lock_.lock_rd(); - RETVAL_BOOL(zend_hash_find_ptr(&ht, skey.get()) != NULL); - lock_.unlock(); - } - - void strkey_offsetUnset(zval *zkey) { - zend::String skey(zkey); - lock_.lock(); - zend_hash_del(&ht, skey.get()); - lock_.unlock(); - } - - void strkey_offsetSet(zval *zkey, zval *zvalue) { - zend::String skey(zkey); - auto item = new ArrayItem(zvalue); - item->key = zend_string_init(skey.val(), skey.len(), 1); - lock_.lock(); - zend_hash_update_ptr(&ht, item->key, item); - lock_.unlock(); - } - - void count(zval *return_value) { - lock_.lock_rd(); - RETVAL_LONG(zend_hash_num_elements(&ht)); - lock_.unlock(); - } - - void keys(zval *return_value) { - lock_.lock_rd(); - zend_ulong elem_count = zend_hash_num_elements(&ht); - array_init_size(return_value, elem_count); - zend_hash_real_init_packed(Z_ARRVAL_P(return_value)); - zend_ulong num_idx; - zend_string *str_idx; - zval *entry; - ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { - if (HT_IS_PACKED(&ht) && HT_IS_WITHOUT_HOLES(&ht)) { - /* Optimistic case: range(0..n-1) for vector-like packed array */ - zend_ulong lval = 0; - - for (; lval < elem_count; ++lval) { - ZEND_HASH_FILL_SET_LONG(lval); - ZEND_HASH_FILL_NEXT(); - } - } else { - /* Go through input array and add keys to the return array */ - ZEND_HASH_FOREACH_KEY_VAL(&ht, num_idx, str_idx, entry) { - if (str_idx) { - ZEND_HASH_FILL_SET_STR(zend_string_init(str_idx->val, str_idx->len, 0)); - } else { - ZEND_HASH_FILL_SET_LONG(num_idx); - } - ZEND_HASH_FILL_NEXT(); - } - ZEND_HASH_FOREACH_END(); - } - (void) entry; - } - ZEND_HASH_FILL_END(); - lock_.unlock(); - } - - void intkey_offsetGet(zend_long index, zval *return_value) { - lock_.lock_rd(); - ArrayItem *item = (ArrayItem *) zend_hash_index_find_ptr(&ht, index); - if (item) { - item->fetch(return_value); - } - lock_.unlock(); - } - - void intkey_offsetGet(zval *zkey, zval *return_value) { - intkey_offsetGet(zval_get_long(zkey), return_value); - } - - void intkey_offsetExists(zval *zkey, zval *return_value) { - zend_long index = zval_get_long(zkey); - lock_.lock_rd(); - RETVAL_BOOL(zend_hash_index_find_ptr(&ht, index) != NULL); - lock_.unlock(); - } - - void intkey_offsetUnset(zval *zkey) { - zend_long index = zval_get_long(zkey); - lock_.lock(); - zend_hash_index_del(&ht, index); - lock_.unlock(); - } - - void intkey_offsetSet(zval *zkey, zval *zvalue) { - zend_long index = zval_get_long(zkey); - auto item = new ArrayItem(zvalue); - lock_.lock(); - zend_hash_index_update_ptr(&ht, index, item); - lock_.unlock(); - } - - bool index_offsetGet(zval *zkey, zval *return_value) { - zend_long index = zval_get_long(zkey); - bool out_of_range = true; - lock_.lock_rd(); - if (index_exists(index)) { - out_of_range = false; - ArrayItem *item = (ArrayItem *) zend_hash_index_find_ptr(&ht, index); - if (item) { - item->fetch(return_value); - } - } - lock_.unlock(); - return !out_of_range; - } - - bool index_offsetSet(zval *zkey, zval *zvalue) { - zend_long index = ZVAL_IS_NULL(zkey) ? -1 : zval_get_long(zkey); - auto item = new ArrayItem(zvalue); - bool success = true; - lock_.lock(); - if (index > zend_hash_num_elements(&ht)) { - success = false; - delete item; - } else if (index == -1 || index == zend_hash_num_elements(&ht)) { - zend_hash_next_index_insert_ptr(&ht, item); - } else { - zend_hash_index_update_ptr(&ht, index, item); - } - lock_.unlock(); - return success; - } - - void index_offsetExists(zval *zkey, zval *return_value) { - zend_long index = zval_get_long(zkey); - lock_.lock_rd(); - RETVAL_BOOL(index_exists(index)); - lock_.unlock(); - } -}; - typedef std::thread Thread; struct ThreadObject { @@ -322,112 +42,6 @@ struct ThreadObject { zend_object std; }; -struct ThreadMapObject { - ZendArray *map; - zend_object std; -}; - -struct ThreadArrayListObject { - ZendArray *list; - zend_object std; -}; - -struct Queue : ThreadResource { - std::queue queue; - std::mutex lock_; - std::condition_variable cv_; - - enum { - NOTIFY_NONE = 0, - NOTIFY_ONE = 1, - NOTIFY_ALL = 2, - }; - - Queue() : ThreadResource(), queue() {} - - ~Queue() { - clean(); - } - - void push(zval *zvalue) { - auto item = new ArrayItem(zvalue); - lock_.lock(); - queue.push(item); - lock_.unlock(); - } - - void pop(zval *return_value) { - ArrayItem *item = nullptr; - lock_.lock(); - if (!queue.empty()) { - item = queue.front(); - queue.pop(); - } - lock_.unlock(); - if (item) { - item->fetch(return_value); - delete item; - } - } - - void push_notify(zval *zvalue, bool notify_all) { - auto item = new ArrayItem(zvalue); - std::unique_lock _lock(lock_); - queue.push(item); - if (notify_all) { - cv_.notify_all(); - } else { - cv_.notify_one(); - } - } - - void pop_wait(zval *return_value, double timeout) { - ArrayItem *item = nullptr; - std::unique_lock _lock(lock_); - SW_LOOP { - if (!queue.empty()) { - item = queue.front(); - queue.pop(); - break; - } else { - if (timeout > 0) { - if (cv_.wait_for(_lock, std::chrono::duration(timeout)) == std::cv_status::timeout) { - break; - } - } else { - cv_.wait(_lock); - } - } - } - _lock.unlock(); - if (item) { - item->fetch(return_value); - delete item; - } - } - - void count(zval *return_value) { - lock_.lock(); - RETVAL_LONG(queue.size()); - lock_.unlock(); - } - - void clean() { - lock_.lock(); - while (!queue.empty()) { - ArrayItem *item = queue.front(); - delete item; - queue.pop(); - } - lock_.unlock(); - } -}; - -struct ThreadQueueObject { - Queue *queue; - zend_object std; -}; - static void php_swoole_thread_join(zend_object *object); static thread_local zval thread_argv; @@ -488,126 +102,6 @@ static void php_swoole_thread_join(zend_object *object) { } } -// =======================================Map============================================== -static sw_inline ThreadMapObject *thread_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; - mo->map = nullptr; - } - zend_object_std_dtor(object); -} - -static zend_object *thread_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); - mo->std.handlers = &swoole_thread_map_handlers; - return &mo->std; -} - -ThreadMapObject *thread_map_fetch_object_check(zval *zobject) { - ThreadMapObject *map = thread_map_fetch_object(Z_OBJ_P(zobject)); - if (!map->map) { - php_swoole_fatal_error(E_ERROR, "must call constructor first"); - } - return map; -} - -// =======================================ArrayList============================================== -static sw_inline ThreadArrayListObject *thread_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; - ao->list = nullptr; - } - zend_object_std_dtor(object); -} - -static zend_object *thread_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); - ao->std.handlers = &swoole_thread_arraylist_handlers; - return &ao->std; -} - -ThreadArrayListObject *thread_arraylist_fetch_object_check(zval *zobject) { - ThreadArrayListObject *ao = thread_arraylist_fetch_object(Z_OBJ_P(zobject)); - if (!ao->list) { - php_swoole_fatal_error(E_ERROR, "must call constructor first"); - } - return ao; -} - -// =======================================Queue============================================== -static sw_inline ThreadQueueObject *thread_queue_fetch_object(zend_object *obj) { - return (ThreadQueueObject *) ((char *) obj - swoole_thread_map_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; - qo->queue = nullptr; - } - zend_object_std_dtor(object); -} - -static zend_object *thread_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); - qo->std.handlers = &swoole_thread_queue_handlers; - return &qo->std; -} - -ThreadQueueObject *thread_queue_fetch_object_check(zval *zobject) { - ThreadQueueObject *qo = thread_queue_fetch_object(Z_OBJ_P(zobject)); - if (!qo->queue) { - php_swoole_fatal_error(E_ERROR, "must call constructor first"); - } - return qo; -} - SW_EXTERN_C_BEGIN static PHP_METHOD(swoole_thread, __construct); static PHP_METHOD(swoole_thread, join); @@ -616,33 +110,6 @@ 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_map, __construct); -static PHP_METHOD(swoole_thread_map, offsetGet); -static PHP_METHOD(swoole_thread_map, offsetExists); -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, clean); -static PHP_METHOD(swoole_thread_map, __wakeup); - -static PHP_METHOD(swoole_thread_arraylist, __construct); -static PHP_METHOD(swoole_thread_arraylist, offsetGet); -static PHP_METHOD(swoole_thread_arraylist, offsetExists); -static PHP_METHOD(swoole_thread_arraylist, offsetSet); -static PHP_METHOD(swoole_thread_arraylist, offsetUnset); -static PHP_METHOD(swoole_thread_arraylist, count); -static PHP_METHOD(swoole_thread_arraylist, clean); -static PHP_METHOD(swoole_thread_arraylist, __wakeup); - -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 @@ -656,41 +123,6 @@ static const zend_function_entry swoole_thread_methods[] = { PHP_ME(swoole_thread, getId, arginfo_class_Swoole_Thread_getId, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END }; - -static const zend_function_entry swoole_thread_map_methods[] = { - PHP_ME(swoole_thread_map, __construct, arginfo_class_Swoole_Thread_Map___construct, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_map, offsetGet, arginfo_class_Swoole_Thread_Map_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_map, offsetExists, arginfo_class_Swoole_Thread_Map_offsetExists, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_map, offsetSet, arginfo_class_Swoole_Thread_Map_offsetSet, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_map, offsetUnset, arginfo_class_Swoole_Thread_Map_offsetUnset, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_map, count, arginfo_class_Swoole_Thread_Map_count, 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_FE_END -}; - -static const zend_function_entry swoole_thread_arraylist_methods[] = { - PHP_ME(swoole_thread_arraylist, __construct, arginfo_class_Swoole_Thread_ArrayList___construct, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_arraylist, offsetGet, arginfo_class_Swoole_Thread_ArrayList_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_arraylist, offsetExists, arginfo_class_Swoole_Thread_ArrayList_offsetExists, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_arraylist, offsetSet, arginfo_class_Swoole_Thread_ArrayList_offsetSet, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_arraylist, offsetUnset, arginfo_class_Swoole_Thread_ArrayList_offsetUnset, 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_FE_END -}; - -static const zend_function_entry swoole_thread_queue_methods[] = { - PHP_ME(swoole_thread_queue, __construct, arginfo_class_Swoole_Thread_Queue___construct, ZEND_ACC_PUBLIC) - PHP_ME(swoole_thread_queue, push, arginfo_class_Swoole_Thread_Queue_push, ZEND_ACC_PUBLIC) - 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_minit(int module_number) { @@ -704,39 +136,6 @@ void php_swoole_thread_minit(int module_number) { 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()); - - SW_INIT_CLASS_ENTRY(swoole_thread_map, "Swoole\\Thread\\Map", nullptr, swoole_thread_map_methods); - 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); - - 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); - - SW_INIT_CLASS_ENTRY(swoole_thread_arraylist, "Swoole\\Thread\\ArrayList", nullptr, swoole_thread_arraylist_methods); - 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, - ThreadArrayListObject, - std); - - zend_class_implements(swoole_thread_arraylist_ce, 2, zend_ce_arrayaccess, zend_ce_countable); - zend_declare_property_long(swoole_thread_arraylist_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); - - SW_INIT_CLASS_ENTRY(swoole_thread_queue, "Swoole\\Thread\\Queue", nullptr, swoole_thread_queue_methods); - 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); - - 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, __construct) {} @@ -907,219 +306,4 @@ static PHP_METHOD(swoole_thread, exec) { swoole_thread_ce, SW_Z8_OBJ_P(return_value), ZEND_STRL("id"), to->thread->native_handle()); } -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); -} - -#define ZEND_ARRAY_CALL_METHOD(array, method, zkey, ...) \ - if (ZVAL_IS_LONG(zkey)) { \ - array->intkey_##method(zkey, ##__VA_ARGS__); \ - } else { \ - array->strkey_##method(zkey, ##__VA_ARGS__); \ - } - -static PHP_METHOD(swoole_thread_map, offsetGet) { - zval *zkey; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(zkey) - ZEND_PARSE_PARAMETERS_END(); - - auto mo = thread_map_fetch_object_check(ZEND_THIS); - ZEND_ARRAY_CALL_METHOD(mo->map, offsetGet, zkey, return_value); -} - -static PHP_METHOD(swoole_thread_map, offsetExists) { - zval *zkey; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(zkey) - ZEND_PARSE_PARAMETERS_END(); - - auto mo = thread_map_fetch_object_check(ZEND_THIS); - ZEND_ARRAY_CALL_METHOD(mo->map, offsetExists, zkey, return_value); -} - -static PHP_METHOD(swoole_thread_map, offsetSet) { - zval *zkey; - zval *zvalue; - - ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(zkey) - Z_PARAM_ZVAL(zvalue) - ZEND_PARSE_PARAMETERS_END(); - - auto mo = thread_map_fetch_object_check(ZEND_THIS); - ZEND_ARRAY_CALL_METHOD(mo->map, offsetSet, zkey, zvalue); -} - -static PHP_METHOD(swoole_thread_map, offsetUnset) { - zval *zkey; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(zkey) - ZEND_PARSE_PARAMETERS_END(); - - auto mo = thread_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); - mo->map->count(return_value); -} - -static PHP_METHOD(swoole_thread_map, keys) { - auto mo = thread_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, __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_arraylist, __construct) { - ZEND_PARSE_PARAMETERS_NONE(); - - 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); -} - -static PHP_METHOD(swoole_thread_arraylist, offsetGet) { - zval *zkey; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(zkey) - ZEND_PARSE_PARAMETERS_END(); - - auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); - if (!ao->list->index_offsetGet(zkey, return_value)) { - zend_throw_exception(swoole_exception_ce, "out of range", -1); - } -} - -static PHP_METHOD(swoole_thread_arraylist, offsetExists) { - zval *zkey; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(zkey) - ZEND_PARSE_PARAMETERS_END(); - - auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); - ao->list->index_offsetExists(zkey, return_value); -} - -static PHP_METHOD(swoole_thread_arraylist, offsetSet) { - zval *zkey; - zval *zvalue; - - ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL(zkey) - Z_PARAM_ZVAL(zvalue) - ZEND_PARSE_PARAMETERS_END(); - - auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); - if (!ao->list->index_offsetSet(zkey, zvalue)) { - zend_throw_exception(swoole_exception_ce, "out of range", -1); - } -} - -static PHP_METHOD(swoole_thread_arraylist, offsetUnset) { - zend_throw_exception(swoole_exception_ce, "unsupported", -3); -} - -static PHP_METHOD(swoole_thread_arraylist, count) { - auto ao = thread_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); - 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_queue, __construct) { - auto qo = thread_queue_fetch_object(Z_OBJ_P(ZEND_THIS)); - 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) { - zval *zvalue; - zend_long notify_which = 0; - - ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_ZVAL(zvalue) - Z_PARAM_OPTIONAL - Z_PARAM_LONG(notify_which) - ZEND_PARSE_PARAMETERS_END(); - - auto qo = thread_queue_fetch_object_check(ZEND_THIS); - if (notify_which > 0) { - qo->queue->push_notify(zvalue, notify_which == Queue::NOTIFY_ALL); - } else { - qo->queue->push(zvalue); - } -} - -static PHP_METHOD(swoole_thread_queue, pop) { - double timeout = 0; - - ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_DOUBLE(timeout) - ZEND_PARSE_PARAMETERS_END(); - - auto qo = thread_queue_fetch_object_check(ZEND_THIS); - if (timeout == 0) { - qo->queue->pop(return_value); - } else { - qo->queue->pop_wait(return_value, timeout); - } -} - -static PHP_METHOD(swoole_thread_queue, count) { - auto qo = thread_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); - 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/ext-src/swoole_thread_arraylist.cc b/ext-src/swoole_thread_arraylist.cc new file mode 100644 index 00000000000..7ec202bc9d3 --- /dev/null +++ b/ext-src/swoole_thread_arraylist.cc @@ -0,0 +1,182 @@ +/* + +----------------------------------------------------------------------+ + | Swoole | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.0 of the Apache license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.apache.org/licenses/LICENSE-2.0.html | + | If you did not receive a copy of the Apache2.0 license and are unable| + | to obtain it through the world-wide-web, please send a note to | + | license@swoole.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Tianfeng Han | + +----------------------------------------------------------------------+ +*/ + +#include "php_swoole_cxx.h" + +#ifdef SW_THREAD +#include "php_swoole_thread.h" + +SW_EXTERN_C_BEGIN +#include "stubs/php_swoole_thread_arraylist_arginfo.h" +SW_EXTERN_C_END + +zend_class_entry *swoole_thread_arraylist_ce; +static zend_object_handlers swoole_thread_arraylist_handlers; + +struct ThreadArrayListObject { + ZendArray *list; + zend_object std; +}; + +SW_EXTERN_C_BEGIN +static PHP_METHOD(swoole_thread_arraylist, __construct); +static PHP_METHOD(swoole_thread_arraylist, offsetGet); +static PHP_METHOD(swoole_thread_arraylist, offsetExists); +static PHP_METHOD(swoole_thread_arraylist, offsetSet); +static PHP_METHOD(swoole_thread_arraylist, offsetUnset); +static PHP_METHOD(swoole_thread_arraylist, count); +static PHP_METHOD(swoole_thread_arraylist, clean); +static PHP_METHOD(swoole_thread_arraylist, __wakeup); +SW_EXTERN_C_END + +static sw_inline ThreadArrayListObject *thread_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; + ao->list = nullptr; + } + zend_object_std_dtor(object); +} + +static zend_object *thread_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); + ao->std.handlers = &swoole_thread_arraylist_handlers; + return &ao->std; +} + +ThreadArrayListObject *thread_arraylist_fetch_object_check(zval *zobject) { + ThreadArrayListObject *ao = thread_arraylist_fetch_object(Z_OBJ_P(zobject)); + if (!ao->list) { + php_swoole_fatal_error(E_ERROR, "must call constructor first"); + } + return ao; +} + +// 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) + PHP_ME(swoole_thread_arraylist, offsetGet, arginfo_class_Swoole_Thread_ArrayList_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_arraylist, offsetExists, arginfo_class_Swoole_Thread_ArrayList_offsetExists, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_arraylist, offsetSet, arginfo_class_Swoole_Thread_ArrayList_offsetSet, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_arraylist, offsetUnset, arginfo_class_Swoole_Thread_ArrayList_offsetUnset, 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_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); + 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, + ThreadArrayListObject, + std); + + zend_class_implements(swoole_thread_arraylist_ce, 2, zend_ce_arrayaccess, zend_ce_countable); + zend_declare_property_long(swoole_thread_arraylist_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY); +} + +static PHP_METHOD(swoole_thread_arraylist, __construct) { + ZEND_PARSE_PARAMETERS_NONE(); + + 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); +} + +static PHP_METHOD(swoole_thread_arraylist, offsetGet) { + zval *zkey; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(zkey) + ZEND_PARSE_PARAMETERS_END(); + + auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); + if (!ao->list->index_offsetGet(zkey, return_value)) { + zend_throw_exception(swoole_exception_ce, "out of range", -1); + } +} + +static PHP_METHOD(swoole_thread_arraylist, offsetExists) { + zval *zkey; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(zkey) + ZEND_PARSE_PARAMETERS_END(); + + auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); + ao->list->index_offsetExists(zkey, return_value); +} + +static PHP_METHOD(swoole_thread_arraylist, offsetSet) { + zval *zkey; + zval *zvalue; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(zkey) + Z_PARAM_ZVAL(zvalue) + ZEND_PARSE_PARAMETERS_END(); + + auto ao = thread_arraylist_fetch_object_check(ZEND_THIS); + if (!ao->list->index_offsetSet(zkey, zvalue)) { + zend_throw_exception(swoole_exception_ce, "out of range", -1); + } +} + +static PHP_METHOD(swoole_thread_arraylist, offsetUnset) { + zend_throw_exception(swoole_exception_ce, "unsupported", -3); +} + +static PHP_METHOD(swoole_thread_arraylist, count) { + auto ao = thread_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); + 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); + } +} +#endif diff --git a/ext-src/swoole_thread_atomic.cc b/ext-src/swoole_thread_atomic.cc new file mode 100644 index 00000000000..f4bfd71c14a --- /dev/null +++ b/ext-src/swoole_thread_atomic.cc @@ -0,0 +1,362 @@ +/* + +----------------------------------------------------------------------+ + | Swoole | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.0 of the Apache license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.apache.org/licenses/LICENSE-2.0.html | + | If you did not receive a copy of the Apache2.0 license and are unable| + | to obtain it through the world-wide-web, please send a note to | + | license@swoole.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Tianfeng Han | + +----------------------------------------------------------------------+ +*/ + +#include "php_swoole_cxx.h" +#include "php_swoole_thread.h" +#include "swoole_memory.h" + +#ifdef SW_THREAD + +BEGIN_EXTERN_C() +#include "stubs/php_swoole_thread_atomic_arginfo.h" +END_EXTERN_C() + +zend_class_entry *swoole_thread_atomic_ce; +static zend_object_handlers swoole_thread_atomic_handlers; + +zend_class_entry *swoole_thread_atomic_long_ce; +static zend_object_handlers swoole_thread_atomic_long_handlers; + +struct AtomicResource: public ThreadResource { + sw_atomic_t value; +}; + +struct AtomicObject { + AtomicResource *res; + zend_object std; +}; + +static sw_inline AtomicObject *php_swoole_thread_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 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; + } + zend_object_std_dtor(object); +} + +static zend_object *php_swoole_thread_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; + + return &atomic->std; +} + +struct AtomicLongResource: public ThreadResource { + sw_atomic_long_t value; +}; + +struct AtomicLongObject { + AtomicLongResource *res; + zend_object std; +}; + +static sw_inline AtomicLongObject *php_swoole_thread_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 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; + } + zend_object_std_dtor(object); +} + +static zend_object *php_swoole_thread_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); + atomic_long->std.handlers = &swoole_thread_atomic_long_handlers; + return &atomic_long->std; +} + +SW_EXTERN_C_BEGIN +static PHP_METHOD(swoole_thread_atomic, __construct); +static PHP_METHOD(swoole_thread_atomic, add); +static PHP_METHOD(swoole_thread_atomic, sub); +static PHP_METHOD(swoole_thread_atomic, get); +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); +#ifdef SW_THREAD +static PHP_METHOD(swoole_thread_atomic, __wakeup); +#endif + +static PHP_METHOD(swoole_thread_atomic_long, __construct); +static PHP_METHOD(swoole_thread_atomic_long, add); +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); +#ifdef SW_THREAD +static PHP_METHOD(swoole_thread_atomic_long, __wakeup); +#endif +SW_EXTERN_C_END + +// clang-format off +static const zend_function_entry swoole_thread_atomic_methods[] = +{ + PHP_ME(swoole_thread_atomic, __construct, arginfo_class_Swoole_Thread_Atomic___construct, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_atomic, add, arginfo_class_Swoole_Thread_Atomic_add, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_atomic, sub, arginfo_class_Swoole_Thread_Atomic_sub, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_atomic, get, arginfo_class_Swoole_Thread_Atomic_get, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_atomic, set, arginfo_class_Swoole_Thread_Atomic_set, ZEND_ACC_PUBLIC) + 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 +}; + +static const zend_function_entry swoole_thread_atomic_long_methods[] = +{ + PHP_ME(swoole_thread_atomic_long, __construct, arginfo_class_Swoole_Thread_Atomic_Long___construct, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_atomic_long, add, arginfo_class_Swoole_Thread_Atomic_Long_add, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_atomic_long, sub, arginfo_class_Swoole_Thread_Atomic_Long_sub, ZEND_ACC_PUBLIC) + 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); + 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, 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); + 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, + AtomicLongObject, + std); +} + +PHP_METHOD(swoole_thread_atomic, __construct) { + auto o = php_swoole_thread_atomic_fetch_object(Z_OBJ_P(ZEND_THIS)); + zend_long value = 0; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(value) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + if (o->res) { + 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 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); +} + +PHP_METHOD(swoole_thread_atomic, add) { + sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + zend_long add_value = 1; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(add_value) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + RETURN_LONG(sw_atomic_add_fetch(atomic, (uint32_t) add_value)); +} + +PHP_METHOD(swoole_thread_atomic, sub) { + sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + zend_long sub_value = 1; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(sub_value) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + RETURN_LONG(sw_atomic_sub_fetch(atomic, (uint32_t) sub_value)); +} + +PHP_METHOD(swoole_thread_atomic, get) { + sw_atomic_t *atomic = php_swoole_thread_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); + zend_long set_value; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(set_value) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + *atomic = (uint32_t) set_value; +} + +PHP_METHOD(swoole_thread_atomic, cmpset) { + sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + zend_long cmp_value, set_value; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_LONG(cmp_value) + Z_PARAM_LONG(set_value) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + RETURN_BOOL(sw_atomic_cmp_set(atomic, (sw_atomic_t) cmp_value, (sw_atomic_t) set_value)); +} + +PHP_METHOD(swoole_thread_atomic, wait) { + sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + double timeout = 1.0; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_DOUBLE(timeout) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + SW_CHECK_RETURN(sw_atomic_futex_wait(atomic, timeout)); +} + +PHP_METHOD(swoole_thread_atomic, wakeup) { + sw_atomic_t *atomic = php_swoole_thread_atomic_get_ptr(ZEND_THIS); + zend_long n = 1; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(n) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + 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)); + zend_long value = 0; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(value) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + if (o->res) { + 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); +} + +PHP_METHOD(swoole_thread_atomic_long, add) { + sw_atomic_long_t *atomic_long = php_swoole_thread_atomic_long_get_ptr(ZEND_THIS); + zend_long add_value = 1; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(add_value) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + RETURN_LONG(sw_atomic_add_fetch(atomic_long, (sw_atomic_long_t) add_value)); +} + +PHP_METHOD(swoole_thread_atomic_long, sub) { + sw_atomic_long_t *atomic_long = php_swoole_thread_atomic_long_get_ptr(ZEND_THIS); + zend_long sub_value = 1; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(sub_value) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + RETURN_LONG(sw_atomic_sub_fetch(atomic_long, (sw_atomic_long_t) sub_value)); +} + +PHP_METHOD(swoole_thread_atomic_long, get) { + sw_atomic_long_t *atomic_long = php_swoole_thread_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); + zend_long set_value; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(set_value) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + *atomic_long = (sw_atomic_long_t) set_value; +} + +PHP_METHOD(swoole_thread_atomic_long, cmpset) { + sw_atomic_long_t *atomic_long = php_swoole_thread_atomic_long_get_ptr(ZEND_THIS); + zend_long cmp_value, set_value; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_LONG(cmp_value) + Z_PARAM_LONG(set_value) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + 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_lock.cc b/ext-src/swoole_thread_lock.cc new file mode 100644 index 00000000000..c3087c7ca2b --- /dev/null +++ b/ext-src/swoole_thread_lock.cc @@ -0,0 +1,230 @@ +/* + +----------------------------------------------------------------------+ + | Swoole | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.0 of the Apache license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.apache.org/licenses/LICENSE-2.0.html | + | If you did not receive a copy of the Apache2.0 license and are unable| + | to obtain it through the world-wide-web, please send a note to | + | license@swoole.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Tianfeng Han | + +----------------------------------------------------------------------+ +*/ + +#include "php_swoole_private.h" +#include "php_swoole_thread.h" +#include "swoole_memory.h" +#include "swoole_lock.h" + +BEGIN_EXTERN_C() +#include "stubs/php_swoole_thread_lock_arginfo.h" +END_EXTERN_C() + +using swoole::Lock; +using swoole::Mutex; +#ifdef HAVE_SPINLOCK +using swoole::SpinLock; +#endif +#ifdef HAVE_RWLOCK +using swoole::RWLock; +#endif + +static zend_class_entry *swoole_thread_lock_ce; +static zend_object_handlers swoole_thread_lock_handlers; + +#ifdef SW_THREAD +struct LockResource : public ThreadResource { + Lock *lock_; + LockResource(int type) : ThreadResource() { + switch (type) { +#ifdef HAVE_SPINLOCK + case Lock::SPIN_LOCK: + lock_ = new SpinLock(0); + break; +#endif +#ifdef HAVE_RWLOCK + case Lock::RW_LOCK: + lock_ = new RWLock(0); + break; +#endif + case Lock::MUTEX: + default: + lock_ = new Mutex(0); + break; + } + } + ~LockResource() { + delete lock_; + } +}; +#endif + +struct LockObject { + LockResource *lock; + zend_object std; +}; + +static sw_inline LockObject *php_swoole_thread_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 *php_swoole_thread_lock_get_and_check_ptr(zval *zobject) { + Lock *lock = php_swoole_thread_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; + o->lock = nullptr; + } + zend_object_std_dtor(object); +} + +static zend_object *php_swoole_thread_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); + lock->std.handlers = &swoole_thread_lock_handlers; + return &lock->std; +} + +SW_EXTERN_C_BEGIN +static PHP_METHOD(swoole_thread_lock, __construct); +static PHP_METHOD(swoole_thread_lock, __destruct); +static PHP_METHOD(swoole_thread_lock, lock); +static PHP_METHOD(swoole_thread_lock, lockwait); +static PHP_METHOD(swoole_thread_lock, trylock); +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); +#ifdef SW_THREAD +static PHP_METHOD(swoole_thread_lock, __wakeup); +#endif +SW_EXTERN_C_END + +// clang-format off +static const zend_function_entry swoole_thread_lock_methods[] = +{ + PHP_ME(swoole_thread_lock, __construct, arginfo_class_Swoole_Thread_Lock___construct, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_lock, __destruct, arginfo_class_Swoole_Thread_Lock___destruct, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_lock, lock, arginfo_class_Swoole_Thread_Lock_lock, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_lock, lockwait, arginfo_class_Swoole_Thread_Lock_locakwait, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_lock, trylock, arginfo_class_Swoole_Thread_Lock_trylock, ZEND_ACC_PUBLIC) + 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); + 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); + + zend_declare_class_constant_long(swoole_thread_lock_ce, ZEND_STRL("MUTEX"), Lock::MUTEX); +#ifdef HAVE_RWLOCK + zend_declare_class_constant_long(swoole_thread_lock_ce, ZEND_STRL("RWLOCK"), Lock::RW_LOCK); +#endif +#ifdef HAVE_SPINLOCK + 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)); + 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; + } + + zend_long type = swoole::Lock::MUTEX; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(type) + 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); + SW_LOCK_CHECK_RETURN(lock->lock()); +} + +static PHP_METHOD(swoole_thread_lock, lockwait) { + double timeout = 1.0; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &timeout) == FAILURE) { + RETURN_FALSE; + } + Lock *lock = php_swoole_thread_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; + } + Mutex *mutex = dynamic_cast(lock); + if (mutex == nullptr) { + zend_throw_exception(swoole_exception_ce, "wrong lock type", -3); + RETURN_FALSE; + } + SW_LOCK_CHECK_RETURN(mutex->lock_wait((int) timeout * 1000)); +} + +static PHP_METHOD(swoole_thread_lock, unlock) { + Lock *lock = php_swoole_thread_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); + 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); + 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); + 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; + } +} diff --git a/ext-src/swoole_thread_map.cc b/ext-src/swoole_thread_map.cc new file mode 100644 index 00000000000..705d38597ab --- /dev/null +++ b/ext-src/swoole_thread_map.cc @@ -0,0 +1,196 @@ +/* + +----------------------------------------------------------------------+ + | Swoole | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.0 of the Apache license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.apache.org/licenses/LICENSE-2.0.html | + | If you did not receive a copy of the Apache2.0 license and are unable| + | to obtain it through the world-wide-web, please send a note to | + | license@swoole.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Tianfeng Han | + +----------------------------------------------------------------------+ +*/ + +#include "php_swoole_cxx.h" + +#ifdef SW_THREAD +#include "php_swoole_thread.h" + +SW_EXTERN_C_BEGIN +#include "stubs/php_swoole_thread_map_arginfo.h" +SW_EXTERN_C_END + +zend_class_entry *swoole_thread_map_ce; +static zend_object_handlers swoole_thread_map_handlers; + +struct ThreadMapObject { + ZendArray *map; + zend_object std; +}; + +static sw_inline ThreadMapObject *thread_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; + mo->map = nullptr; + } + zend_object_std_dtor(object); +} + +static zend_object *thread_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); + mo->std.handlers = &swoole_thread_map_handlers; + return &mo->std; +} + +ThreadMapObject *thread_map_fetch_object_check(zval *zobject) { + ThreadMapObject *map = thread_map_fetch_object(Z_OBJ_P(zobject)); + if (!map->map) { + php_swoole_fatal_error(E_ERROR, "must call constructor first"); + } + return map; +} + +SW_EXTERN_C_BEGIN +static PHP_METHOD(swoole_thread_map, __construct); +static PHP_METHOD(swoole_thread_map, offsetGet); +static PHP_METHOD(swoole_thread_map, offsetExists); +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, clean); +static PHP_METHOD(swoole_thread_map, __wakeup); +SW_EXTERN_C_END + +// clang-format off +static const zend_function_entry swoole_thread_map_methods[] = { + PHP_ME(swoole_thread_map, __construct, arginfo_class_Swoole_Thread_Map___construct, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_map, offsetGet, arginfo_class_Swoole_Thread_Map_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_map, offsetExists, arginfo_class_Swoole_Thread_Map_offsetExists, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_map, offsetSet, arginfo_class_Swoole_Thread_Map_offsetSet, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_map, offsetUnset, arginfo_class_Swoole_Thread_Map_offsetUnset, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_map, count, arginfo_class_Swoole_Thread_Map_count, 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_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); + 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); + + 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); +} + +#define ZEND_ARRAY_CALL_METHOD(array, method, zkey, ...) \ + if (ZVAL_IS_LONG(zkey)) { \ + array->intkey_##method(zkey, ##__VA_ARGS__); \ + } else { \ + array->strkey_##method(zkey, ##__VA_ARGS__); \ + } + +static PHP_METHOD(swoole_thread_map, offsetGet) { + zval *zkey; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(zkey) + ZEND_PARSE_PARAMETERS_END(); + + auto mo = thread_map_fetch_object_check(ZEND_THIS); + ZEND_ARRAY_CALL_METHOD(mo->map, offsetGet, zkey, return_value); +} + +static PHP_METHOD(swoole_thread_map, offsetExists) { + zval *zkey; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(zkey) + ZEND_PARSE_PARAMETERS_END(); + + auto mo = thread_map_fetch_object_check(ZEND_THIS); + ZEND_ARRAY_CALL_METHOD(mo->map, offsetExists, zkey, return_value); +} + +static PHP_METHOD(swoole_thread_map, offsetSet) { + zval *zkey; + zval *zvalue; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ZVAL(zkey) + Z_PARAM_ZVAL(zvalue) + ZEND_PARSE_PARAMETERS_END(); + + auto mo = thread_map_fetch_object_check(ZEND_THIS); + ZEND_ARRAY_CALL_METHOD(mo->map, offsetSet, zkey, zvalue); +} + +static PHP_METHOD(swoole_thread_map, offsetUnset) { + zval *zkey; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(zkey) + ZEND_PARSE_PARAMETERS_END(); + + auto mo = thread_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); + mo->map->count(return_value); +} + +static PHP_METHOD(swoole_thread_map, keys) { + auto mo = thread_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, __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); + } +} + +#endif diff --git a/ext-src/swoole_thread_queue.cc b/ext-src/swoole_thread_queue.cc new file mode 100644 index 00000000000..daa5c68a97c --- /dev/null +++ b/ext-src/swoole_thread_queue.cc @@ -0,0 +1,259 @@ +/* + +----------------------------------------------------------------------+ + | Swoole | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.0 of the Apache license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.apache.org/licenses/LICENSE-2.0.html | + | If you did not receive a copy of the Apache2.0 license and are unable| + | to obtain it through the world-wide-web, please send a note to | + | license@swoole.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Tianfeng Han | + +----------------------------------------------------------------------+ +*/ + +#include "php_swoole_cxx.h" + +#ifdef SW_THREAD +#include "php_swoole_thread.h" +#include "stubs/php_swoole_thread_queue_arginfo.h" + +#include +#include + +zend_class_entry *swoole_thread_queue_ce; +static zend_object_handlers swoole_thread_queue_handlers; + +struct Queue : ThreadResource { + std::queue queue; + std::mutex lock_; + std::condition_variable cv_; + + enum { + NOTIFY_NONE = 0, + NOTIFY_ONE = 1, + NOTIFY_ALL = 2, + }; + + Queue() : ThreadResource(), queue() {} + + ~Queue() { + clean(); + } + + void push(zval *zvalue) { + auto item = new ArrayItem(zvalue); + lock_.lock(); + queue.push(item); + lock_.unlock(); + } + + void pop(zval *return_value) { + ArrayItem *item = nullptr; + lock_.lock(); + if (!queue.empty()) { + item = queue.front(); + queue.pop(); + } + lock_.unlock(); + if (item) { + item->fetch(return_value); + delete item; + } + } + + void push_notify(zval *zvalue, bool notify_all) { + auto item = new ArrayItem(zvalue); + std::unique_lock _lock(lock_); + queue.push(item); + if (notify_all) { + cv_.notify_all(); + } else { + cv_.notify_one(); + } + } + + void pop_wait(zval *return_value, double timeout) { + ArrayItem *item = nullptr; + std::unique_lock _lock(lock_); + SW_LOOP { + if (!queue.empty()) { + item = queue.front(); + queue.pop(); + break; + } else { + if (timeout > 0) { + if (cv_.wait_for(_lock, std::chrono::duration(timeout)) == std::cv_status::timeout) { + break; + } + } else { + cv_.wait(_lock); + } + } + } + _lock.unlock(); + if (item) { + item->fetch(return_value); + delete item; + } + } + + void count(zval *return_value) { + lock_.lock(); + RETVAL_LONG(queue.size()); + lock_.unlock(); + } + + void clean() { + lock_.lock(); + while (!queue.empty()) { + ArrayItem *item = queue.front(); + delete item; + queue.pop(); + } + lock_.unlock(); + } +}; + +struct ThreadQueueObject { + Queue *queue; + zend_object std; +}; + +static sw_inline ThreadQueueObject *thread_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; + qo->queue = nullptr; + } + zend_object_std_dtor(object); +} + +static zend_object *thread_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); + qo->std.handlers = &swoole_thread_queue_handlers; + return &qo->std; +} + +ThreadQueueObject *thread_queue_fetch_object_check(zval *zobject) { + ThreadQueueObject *qo = thread_queue_fetch_object(Z_OBJ_P(zobject)); + if (!qo->queue) { + php_swoole_fatal_error(E_ERROR, "must call constructor first"); + } + return qo; +} + +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 +static const zend_function_entry swoole_thread_queue_methods[] = { + PHP_ME(swoole_thread_queue, __construct, arginfo_class_Swoole_Thread_Queue___construct, ZEND_ACC_PUBLIC) + PHP_ME(swoole_thread_queue, push, arginfo_class_Swoole_Thread_Queue_push, ZEND_ACC_PUBLIC) + 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); + 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); + + 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)); + 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) { + zval *zvalue; + zend_long notify_which = 0; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(zvalue) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(notify_which) + ZEND_PARSE_PARAMETERS_END(); + + auto qo = thread_queue_fetch_object_check(ZEND_THIS); + if (notify_which > 0) { + qo->queue->push_notify(zvalue, notify_which == Queue::NOTIFY_ALL); + } else { + qo->queue->push(zvalue); + } +} + +static PHP_METHOD(swoole_thread_queue, pop) { + double timeout = 0; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_DOUBLE(timeout) + ZEND_PARSE_PARAMETERS_END(); + + auto qo = thread_queue_fetch_object_check(ZEND_THIS); + if (timeout == 0) { + qo->queue->pop(return_value); + } else { + qo->queue->pop_wait(return_value, timeout); + } +} + +static PHP_METHOD(swoole_thread_queue, count) { + auto qo = thread_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); + 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/include/swoole_atomic.h b/include/swoole_atomic.h index adead3cd1f2..6fe231b4eb3 100644 --- a/include/swoole_atomic.h +++ b/include/swoole_atomic.h @@ -42,3 +42,65 @@ typedef sw_atomic_uint32_t sw_atomic_t; #endif #define sw_spinlock_release(lock) __sync_lock_release(lock) + +#ifdef HAVE_FUTEX +#include +#include + +static inline int sw_atomic_futex_wait(sw_atomic_t *atomic, double timeout) { + if (sw_atomic_cmp_set(atomic, 1, 0)) { + return 0; + } + + int ret; + struct timespec _timeout; + + if (timeout > 0) { + _timeout.tv_sec = (long) timeout; + _timeout.tv_nsec = (timeout - _timeout.tv_sec) * 1000 * 1000 * 1000; + ret = syscall(SYS_futex, atomic, FUTEX_WAIT, 0, &_timeout, NULL, 0); + } else { + ret = syscall(SYS_futex, atomic, FUTEX_WAIT, 0, NULL, NULL, 0); + } + if (ret == 0 && sw_atomic_cmp_set(atomic, 1, 0)) { + return 0; + } else { + return -1; + } +} + +static inline int sw_atomic_futex_wakeup(sw_atomic_t *atomic, int n) { + if (sw_atomic_cmp_set(atomic, 0, 1)) { + return syscall(SYS_futex, atomic, FUTEX_WAKE, n, NULL, NULL, 0); + } else { + return 0; + } +} + +#else +static inline int sw_atomic_futex_wait(sw_atomic_t *atomic, double timeout) { + if (sw_atomic_cmp_set(atomic, (sw_atomic_t) 1, (sw_atomic_t) 0)) { + return 0; + } + timeout = timeout <= 0 ? INT_MAX : timeout; + int32_t i = (int32_t) sw_atomic_sub_fetch(atomic, 1); + while (timeout > 0) { + if ((int32_t) *atomic > i) { + return 0; + } else { + usleep(1000); + timeout -= 0.001; + } + } + sw_atomic_fetch_add(atomic, 1); + return -1; +} + +static inline int sw_atomic_futex_wakeup(sw_atomic_t *atomic, int n) { + if (1 == (int32_t) *atomic) { + return 0; + } + sw_atomic_fetch_add(atomic, n); + return 0; +} +#endif diff --git a/include/swoole_error.h b/include/swoole_error.h index 3d6097e3318..c608de54eec 100644 --- a/include/swoole_error.h +++ b/include/swoole_error.h @@ -36,6 +36,7 @@ enum swErrorCode { SW_ERROR_WRONG_OPERATION, SW_ERROR_PHP_RUNTIME_NOTICE, // Non-fatal errors, just runtime warnings SW_ERROR_UNDEFINED_BEHAVIOR = 600, + SW_ERROR_NOT_THREAD_SAFETY, SW_ERROR_FILE_NOT_EXIST = 700, SW_ERROR_FILE_TOO_LARGE, diff --git a/tests/swoole_thread/async-io.phpt b/tests/swoole_thread/async-io.phpt index 58b531e3d56..e9aa5de4fc5 100644 --- a/tests/swoole_thread/async-io.phpt +++ b/tests/swoole_thread/async-io.phpt @@ -12,6 +12,7 @@ use Swoole\Thread; const C = 4; const N = 256; +const M = 9999; $args = Thread::getArguments(); $running = true; @@ -19,20 +20,24 @@ $md5 = md5_file(__FILE__); if (empty($args)) { $threads = []; - $atomic = new Swoole\Atomic(); + $atomic = new Swoole\Thread\Atomic(); + $atomicLong = new Swoole\Thread\Atomic\Long(); for ($i = 0; $i < C; $i++) { - $threads[] = Thread::exec(__FILE__, $argv, $i, $atomic); + $threads[] = Thread::exec(__FILE__, $argv, $i, $atomic, $atomicLong); } for ($i = 0; $i < C; $i++) { $threads[$i]->join(); } Assert::eq($atomic->get(), C * N); + Assert::eq($atomicLong->get(), C * N * M); } else { $atomic = $args[2]; - Co\run(function () use ($atomic, $md5) { + $atomicLong = $args[3]; + Co\run(function () use ($atomic, $atomicLong, $md5) { $n = N; while ($n--) { $atomic->add(); + $atomicLong->add(M); $rs = \Swoole\Coroutine\System::readFile(__FILE__); Assert::eq(md5($rs), $md5); } diff --git a/tests/swoole_thread/lock.phpt b/tests/swoole_thread/lock.phpt index 1f25e946ae2..9554db680b7 100644 --- a/tests/swoole_thread/lock.phpt +++ b/tests/swoole_thread/lock.phpt @@ -9,7 +9,7 @@ require __DIR__ . '/../include/skipif.inc'; require __DIR__ . '/../include/bootstrap.php'; use Swoole\Thread; -use Swoole\Lock; +use Swoole\Thread\Lock; $args = Thread::getArguments();