diff --git a/config.m4 b/config.m4 index bef3d8227cd..0dc3236700b 100644 --- a/config.m4 +++ b/config.m4 @@ -71,6 +71,11 @@ PHP_ARG_WITH([brotli_dir], [AS_HELP_STRING([[--with-brotli-dir[=DIR]]], [Include Brotli support])], [no], [no]) +PHP_ARG_ENABLE([zstd], + [enable zstd support], + [AS_HELP_STRING([[--enable-zstd]], + [Use zstd])], [no], [no]) + PHP_ARG_WITH([nghttp2_dir], [dir of nghttp2], [AS_HELP_STRING([[--with-nghttp2-dir[=DIR]]], @@ -873,6 +878,13 @@ EOF fi fi + if test "$PHP_ZSTD" = "yes"; then + PKG_CHECK_MODULES([ZSTD], [libzstd >= 1.4.0]) + AC_DEFINE(SW_HAVE_ZSTD, 1, [have zstd]) + PHP_EVAL_LIBLINE($ZSTD_LIBS, SWOOLE_SHARED_LIBADD) + PHP_EVAL_INCLINE($ZSTD_CFLAGS) + fi + PHP_ADD_LIBRARY(pthread) PHP_SUBST(SWOOLE_SHARED_LIBADD) diff --git a/core-tests/src/coroutine/system.cpp b/core-tests/src/coroutine/system.cpp index fcada770deb..0a39762d454 100644 --- a/core-tests/src/coroutine/system.cpp +++ b/core-tests/src/coroutine/system.cpp @@ -121,8 +121,8 @@ TEST(coroutine_system, wait_signal) { System::sleep(0.002); kill(getpid(), SIGUSR1); }); - ASSERT_TRUE(System::wait_signal(SIGUSR1, 1.0)); - ASSERT_FALSE(System::wait_signal(SIGUSR2, 0.1)); + ASSERT_EQ(System::wait_signal(SIGUSR1, 1.0), SIGUSR1); + ASSERT_EQ(System::wait_signal(SIGUSR2, 0.1), -1); }); } diff --git a/ext-src/php_swoole.cc b/ext-src/php_swoole.cc index 10f253535d0..80f5d3b3c23 100644 --- a/ext-src/php_swoole.cc +++ b/ext-src/php_swoole.cc @@ -54,6 +54,9 @@ END_EXTERN_C() #include #include #endif +#ifdef SW_HAVE_ZSTD +#include +#endif #ifdef SW_USE_CARES #include @@ -928,6 +931,13 @@ PHP_MINFO_FUNCTION(swoole) { snprintf(buf, sizeof(buf), "E%u/D%u", BrotliEncoderVersion(), BrotliDecoderVersion()); php_info_print_table_row(2, "brotli", buf); #endif +#ifdef SW_HAVE_ZSTD +#ifdef ZSTD_VERSION_NUMBER + php_info_print_table_row(2, "zstd", ZSTD_VERSION_STRING); +#else + php_info_print_table_row(2, "zstd", "enabled"); +#endif +#endif #ifdef HAVE_MUTEX_TIMEDLOCK php_info_print_table_row(2, "mutex_timedlock", "enabled"); #endif diff --git a/ext-src/php_swoole_cxx.h b/ext-src/php_swoole_cxx.h index 4031a9707c7..403057bd436 100644 --- a/ext-src/php_swoole_cxx.h +++ b/ext-src/php_swoole_cxx.h @@ -737,6 +737,12 @@ static inline void array_unset(zval *arg, const char *key, size_t l_key) { zend_hash_str_del(Z_ARRVAL_P(arg), key, l_key); } +static inline zend_long object_get_long(zval *obj, zend_string *key) { + static zval rv; + zval *property = zend_read_property_ex(Z_OBJCE_P(obj), Z_OBJ_P(obj), key, 1, &rv); + return property ? zval_get_long(property) : 0; +} + static inline zend_long object_get_long(zval *obj, const char *key, size_t l_key) { static zval rv; zval *property = zend_read_property(Z_OBJCE_P(obj), Z_OBJ_P(obj), key, l_key, 1, &rv); diff --git a/ext-src/php_swoole_http.h b/ext-src/php_swoole_http.h index 0e00165e13a..363b34ff021 100644 --- a/ext-src/php_swoole_http.h +++ b/ext-src/php_swoole_http.h @@ -34,6 +34,15 @@ #define SW_ZLIB_ENCODING_ANY 0x2f #endif +#ifdef SW_HAVE_BROTLI +#include +#include +#endif + +#ifdef SW_HAVE_ZSTD +#include +#endif + #include enum swHttpHeaderFlag { @@ -52,6 +61,7 @@ enum swHttpCompressMethod { HTTP_COMPRESS_GZIP, HTTP_COMPRESS_DEFLATE, HTTP_COMPRESS_BR, + HTTP_COMPRESS_ZSTD, }; namespace swoole { diff --git a/ext-src/stubs/php_swoole_coroutine_system.stub.php b/ext-src/stubs/php_swoole_coroutine_system.stub.php index db869c161ff..77e292de935 100644 --- a/ext-src/stubs/php_swoole_coroutine_system.stub.php +++ b/ext-src/stubs/php_swoole_coroutine_system.stub.php @@ -11,7 +11,7 @@ public static function readFile(string $filename, int $flag = 0): false|string { public static function writeFile(string $filename, string $fileContent, int $flags = 0): false|int {} public static function wait(float $timeout = -1): array|false {} public static function waitPid(int $pid, float $timeout = -1): array|false {} - public static function waitSignal(int|array $signals, float $timeout = -1): bool {} + public static function waitSignal(int|array $signals, float $timeout = -1): int|false {} public static function waitEvent(mixed $socket, int $events = SWOOLE_EVENT_READ, float $timeout = -1): int|false {} } } diff --git a/ext-src/stubs/php_swoole_coroutine_system_arginfo.h b/ext-src/stubs/php_swoole_coroutine_system_arginfo.h index 76c3071ee94..2700ef9f4a3 100644 --- a/ext-src/stubs/php_swoole_coroutine_system_arginfo.h +++ b/ext-src/stubs/php_swoole_coroutine_system_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 59e0a163279f6b7bf53de6f8f50a8ba4820ccf3b */ + * Stub hash: 3c270ea28b44ea9ae57763943f8e0188d2fbcc03 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Swoole_Coroutine_System_gethostbyname, 0, 1, MAY_BE_FALSE|MAY_BE_STRING) ZEND_ARG_TYPE_INFO(0, domain_name, IS_STRING, 0) @@ -55,7 +55,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Swoole_Coroutine_System_wa ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timeout, IS_DOUBLE, 0, "-1") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Coroutine_System_waitSignal, 0, 1, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Swoole_Coroutine_System_waitSignal, 0, 1, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_MASK(0, signals, MAY_BE_LONG|MAY_BE_ARRAY, NULL) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timeout, IS_DOUBLE, 0, "-1") ZEND_END_ARG_INFO() diff --git a/ext-src/swoole_client.cc b/ext-src/swoole_client.cc index d809b1e27ef..1db29c46030 100644 --- a/ext-src/swoole_client.cc +++ b/ext-src/swoole_client.cc @@ -75,7 +75,6 @@ static zend_object *client_create_object(zend_class_entry *ce) { return &client->std; } - SW_EXTERN_C_BEGIN static PHP_METHOD(swoole_client, __construct); static PHP_METHOD(swoole_client, __destruct); @@ -166,8 +165,7 @@ void php_swoole_client_minit(int module_number) { SW_SET_CLASS_NOT_SERIALIZABLE(swoole_client); SW_SET_CLASS_CLONEABLE(swoole_client, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_client, sw_zend_class_unset_property_deny); - SW_SET_CLASS_CUSTOM_OBJECT( - swoole_client, client_create_object, client_free_object, ClientObject, std); + SW_SET_CLASS_CUSTOM_OBJECT(swoole_client, client_create_object, client_free_object, ClientObject, std); SW_INIT_CLASS_ENTRY_EX(swoole_client_exception, "Swoole\\Client\\Exception", nullptr, nullptr, swoole_exception); @@ -720,11 +718,11 @@ static PHP_METHOD(swoole_client, connect) { RETURN_TRUE; } php_swoole_core_error(E_WARNING, - "connect to server[%s:%d] failed. Error: %s[%d]", - host, - (int) port, - swoole_strerror(swoole_get_last_error()), - swoole_get_last_error()); + "connect to server[%s:%d] failed. Error: %s[%d]", + host, + (int) port, + swoole_strerror(swoole_get_last_error()), + swoole_get_last_error()); php_swoole_client_free(ZEND_THIS, cli); RETURN_FALSE; } @@ -1234,6 +1232,19 @@ bool php_swoole_client_enable_ssl_encryption(Client *cli, zval *zobject) { } static PHP_METHOD(swoole_client, enableSSL) { + zval *zcallback = nullptr; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(zcallback) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + if (zcallback) { + zend_throw_exception( + swoole_exception_ce, "sync client does not support `onSslReady` callback", SW_ERROR_INVALID_PARAMS); + RETURN_FALSE; + } + Client *cli = php_swoole_client_get_cli_safe(ZEND_THIS); if (!cli) { RETURN_FALSE; @@ -1296,11 +1307,11 @@ PHP_FUNCTION(swoole_client_select) { double timeout = SW_CLIENT_CONNECT_TIMEOUT; ZEND_PARSE_PARAMETERS_START(3, 4) - Z_PARAM_ARRAY_EX2(r_array, 1, 1, 0) - Z_PARAM_ARRAY_EX2(w_array, 1, 1, 0) - Z_PARAM_ARRAY_EX2(e_array, 1, 1, 0) - Z_PARAM_OPTIONAL - Z_PARAM_DOUBLE(timeout) + Z_PARAM_ARRAY_EX2(r_array, 1, 1, 0) + Z_PARAM_ARRAY_EX2(w_array, 1, 1, 0) + Z_PARAM_ARRAY_EX2(e_array, 1, 1, 0) + Z_PARAM_OPTIONAL + Z_PARAM_DOUBLE(timeout) ZEND_PARSE_PARAMETERS_END(); int maxevents = SW_MAX(SW_MAX(php_swoole_array_length_safe(r_array), php_swoole_array_length_safe(w_array)), diff --git a/ext-src/swoole_client_async.cc b/ext-src/swoole_client_async.cc index 9cb33abd912..4c147f7ffeb 100644 --- a/ext-src/swoole_client_async.cc +++ b/ext-src/swoole_client_async.cc @@ -123,7 +123,6 @@ static sw_inline void client_execute_callback(zval *zobject, enum php_swoole_cli } } - // clang-format off static const zend_function_entry swoole_client_async_methods[] = { PHP_ME(swoole_client_async, __construct, arginfo_class_Swoole_Async_Client___construct, ZEND_ACC_PUBLIC) @@ -144,7 +143,8 @@ static const zend_function_entry swoole_client_async_methods[] = { // clang-format on void php_swoole_client_async_minit(int module_number) { - SW_INIT_CLASS_ENTRY_EX(swoole_client_async, "Swoole\\Async\\Client", nullptr, swoole_client_async_methods, swoole_client); + SW_INIT_CLASS_ENTRY_EX( + swoole_client_async, "Swoole\\Async\\Client", nullptr, swoole_client_async_methods, swoole_client); SW_SET_CLASS_NOT_SERIALIZABLE(swoole_client_async); SW_SET_CLASS_CLONEABLE(swoole_client_async, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_client_async, sw_zend_class_unset_property_deny); @@ -504,6 +504,18 @@ static PHP_METHOD(swoole_client_async, wakeup) { #ifdef SW_USE_OPENSSL static PHP_METHOD(swoole_client_async, enableSSL) { + zval *zcallback = nullptr; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(zcallback) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + if (zcallback == nullptr) { + zend_throw_exception(swoole_exception_ce, "require `onSslReady` callback", SW_ERROR_INVALID_PARAMS); + RETURN_FALSE; + } + Client *cli = php_swoole_client_get_cli_safe(ZEND_THIS); if (!cli) { RETURN_FALSE; @@ -512,11 +524,6 @@ static PHP_METHOD(swoole_client_async, enableSSL) { RETURN_FALSE; } - zval *zcallback; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zcallback) == FAILURE) { - RETURN_FALSE; - } - auto client_obj = php_swoole_client_fetch_object(ZEND_THIS); if (swoole_event_set(cli->socket, SW_EVENT_WRITE) < 0) { RETURN_FALSE; @@ -528,7 +535,7 @@ static PHP_METHOD(swoole_client_async, enableSSL) { auto cb = sw_callable_create(zcallback); if (!cb) { - return; + RETURN_FALSE; } zend_update_property(swoole_client_async_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("onSSLReady"), zcallback); client_obj->async->onSSLReady = cb; diff --git a/ext-src/swoole_coroutine_system.cc b/ext-src/swoole_coroutine_system.cc index 64175e844de..f37e8551a0c 100644 --- a/ext-src/swoole_coroutine_system.cc +++ b/ext-src/swoole_coroutine_system.cc @@ -356,7 +356,8 @@ PHP_METHOD(swoole_coroutine_system, waitSignal) { signals.push_back(zval_get_long(zsignals)); } - if (!System::wait_signal(signals, timeout)) { + int signo = System::wait_signal(signals, timeout); + if (signo == -1) { if (swoole_get_last_error() == EBUSY) { php_swoole_fatal_error(E_WARNING, "Unable to wait signal, async signal listener has been registered"); } else if (swoole_get_last_error() == EINVAL) { @@ -366,7 +367,7 @@ PHP_METHOD(swoole_coroutine_system, waitSignal) { RETURN_FALSE; } - RETURN_TRUE; + RETURN_LONG(signo); } PHP_METHOD(swoole_coroutine_system, waitEvent) { diff --git a/ext-src/swoole_http_client_coro.cc b/ext-src/swoole_http_client_coro.cc index 2b2cf23685b..6146cd0d349 100644 --- a/ext-src/swoole_http_client_coro.cc +++ b/ext-src/swoole_http_client_coro.cc @@ -35,18 +35,7 @@ SW_EXTERN_C_BEGIN #include "ext/standard/base64.h" -#ifdef SW_HAVE_ZLIB -#include -#endif - -#include "stubs/php_swoole_http_client_coro_arginfo.h" - SW_EXTERN_C_END - -#ifdef SW_HAVE_BROTLI -#include -#endif - using swoole::File; using swoole::String; using swoole::coroutine::Socket; @@ -175,6 +164,9 @@ class Client { #endif #ifdef SW_HAVE_BROTLI BrotliDecoderState *brotli_decoder_state = nullptr; +#endif +#ifdef SW_HAVE_ZSTD + ZSTD_DStream *zstd_stream = nullptr; #endif bool bind(std::string address, int port = 0); bool connect(); @@ -475,6 +467,11 @@ static int http_parser_on_header_value(llhttp_t *parser, const char *at, size_t } else if (SW_STR_ISTARTS_WITH(at, length, "deflate")) { http->compress_method = HTTP_COMPRESS_DEFLATE; } +#endif +#ifdef SW_HAVE_ZSTD + else if (SW_STR_ISTARTS_WITH(at, length, "zstd")) { + http->compress_method = HTTP_COMPRESS_ZSTD; + } #endif } #endif @@ -708,6 +705,48 @@ bool Client::decompress_response(const char *in, size_t in_len) { body->length = reserved_body_length; return false; } +#endif +#ifdef SW_HAVE_ZSTD + case HTTP_COMPRESS_ZSTD: { + size_t zstd_result = 0; + if (zstd_stream == nullptr) { + zstd_stream = ZSTD_createDStream(); + if (!zstd_stream) { + swoole_warning("ZSTD_createDStream() failed, can not create ZSTD stream"); + return false; + } + + zstd_result = ZSTD_initDStream(zstd_stream); + if (ZSTD_isError(zstd_result)) { + swoole_warning("ZSTD_initDStream() failed, Error: [%s]", ZSTD_getErrorName(zstd_result)); + return false; + } + } + + size_t recommended_size = ZSTD_DStreamOutSize(); + ZSTD_inBuffer in_buffer = {in, in_len, 0}; + ZSTD_outBuffer out_buffer = {body->str + body->length, body->size - body->length, 0}; + while (in_buffer.pos < in_buffer.size) { + if (sw_unlikely(out_buffer.pos == out_buffer.size)) { + if (!body->extend(recommended_size + body->size)) { + swoole_warning("ZSTD_decompressStream() failed, no memory is available"); + return false; + } + + body->length += out_buffer.pos; + out_buffer = {body->str + body->length, body->size - body->length, 0}; + } + + zstd_result = ZSTD_decompressStream(zstd_stream, &out_buffer, &in_buffer); + if (ZSTD_isError(zstd_result)) { + swoole_warning("ZSTD_decompressStream() failed, Error: [%s]", ZSTD_getErrorName(zstd_result)); + return false; + } + } + + body->length += out_buffer.pos; + return true; + } #endif default: break; @@ -1131,6 +1170,10 @@ bool Client::send_request() { #else #ifdef SW_HAVE_BROTLI ZEND_STRL("br") +#else +#ifdef SW_HAVE_ZSTD + ZEND_STRL("zstd") +#endif #endif #endif #endif @@ -1660,6 +1703,12 @@ void Client::reset() { BrotliDecoderDestroyInstance(brotli_decoder_state); brotli_decoder_state = nullptr; } +#endif +#ifdef SW_HAVE_ZSTD + if (zstd_stream) { + ZSTD_freeDStream(zstd_stream); + zstd_stream = nullptr; + } #endif if (has_upload_files) { zend_update_property_null(swoole_http_client_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("uploadFiles")); diff --git a/ext-src/swoole_http_request.cc b/ext-src/swoole_http_request.cc index 5db8f9f6248..7d987d2abac 100644 --- a/ext-src/swoole_http_request.cc +++ b/ext-src/swoole_http_request.cc @@ -22,14 +22,6 @@ SW_EXTERN_C_BEGIN #include "thirdparty/php/main/SAPI.h" SW_EXTERN_C_END -#ifdef SW_HAVE_ZLIB -#include -#endif - -#ifdef SW_HAVE_BROTLI -#include -#endif - enum http_upload_errno { HTTP_UPLOAD_ERR_OK = 0, HTTP_UPLOAD_ERR_INI_SIZE, @@ -854,6 +846,11 @@ void HttpContext::set_compression_method(const char *accept_encoding, size_t len } else if (swoole_strnpos(accept_encoding, length, ZEND_STRL("deflate")) >= 0) { accept_compression = 1; compression_method = HTTP_COMPRESS_DEFLATE; +#ifdef SW_HAVE_ZSTD + } else if (swoole_strnpos(accept_encoding, length, ZEND_STRL("zstd")) >= 0) { + accept_compression = 1; + compression_method = HTTP_COMPRESS_ZSTD; +#endif } else { accept_compression = 0; } @@ -869,6 +866,11 @@ const char *HttpContext::get_content_encoding() { else if (compression_method == HTTP_COMPRESS_BR) { return "br"; } +#endif +#ifdef SW_HAVE_ZSTD + else if (compression_method == HTTP_COMPRESS_ZSTD) { + return "zstd"; + } #endif else { return nullptr; diff --git a/ext-src/swoole_http_response.cc b/ext-src/swoole_http_response.cc index 331c3f473af..6d10ce117e3 100644 --- a/ext-src/swoole_http_response.cc +++ b/ext-src/swoole_http_response.cc @@ -15,17 +15,8 @@ */ #include "php_swoole_http_server.h" - #include "swoole_util.h" -#ifdef SW_HAVE_ZLIB -#include -#endif - -#ifdef SW_HAVE_BROTLI -#include -#endif - BEGIN_EXTERN_C() #include "stubs/php_swoole_http_response_arginfo.h" END_EXTERN_C() @@ -565,6 +556,30 @@ bool HttpContext::compress(const char *data, size_t length) { return true; } } +#endif +#ifdef SW_HAVE_ZSTD + else if (compression_method == HTTP_COMPRESS_ZSTD) { + int zstd_compress_level = compression_level; + int zstd_max_level = ZSTD_maxCLevel(); + int zstd_min_level = ZSTD_minCLevel(); + zstd_compress_level = (zstd_compress_level > zstd_max_level) + ? zstd_max_level + : (zstd_compress_level < zstd_min_level ? zstd_min_level : zstd_compress_level); + + size_t compress_size = ZSTD_compressBound(length); + zlib_buffer = std::make_shared(compress_size);; + size_t zstd_compress_result = + ZSTD_compress((void *) zlib_buffer->str, compress_size, (void *) data, length, zstd_compress_level); + + if (ZSTD_isError(zstd_compress_result)) { + swoole_warning("ZSTD_compress() failed, Error: [%s]", ZSTD_getErrorName(zstd_compress_result)); + return false; + } + + zlib_buffer->length = zstd_compress_result; + content_compressed = 1; + return true; + } #endif else { swoole_warning("Unknown compression method"); diff --git a/ext-src/swoole_process_pool.cc b/ext-src/swoole_process_pool.cc index f3c0e444c1d..30061694b7c 100644 --- a/ext-src/swoole_process_pool.cc +++ b/ext-src/swoole_process_pool.cc @@ -34,8 +34,10 @@ static Worker *current_worker = nullptr; struct ProcessPoolObject { ProcessPool *pool; zend::Callable *onStart; + zend::Callable *onShutdown; zend::Callable *onWorkerStart; zend::Callable *onWorkerStop; + zend::Callable *onWorkerExit; zend::Callable *onMessage; zend_bool enable_coroutine; zend_bool enable_message_bus; @@ -86,6 +88,12 @@ static void process_pool_free_object(zend_object *object) { if (pp->onStart) { sw_callable_free(pp->onStart); } + if (pp->onWorkerExit) { + sw_callable_free(pp->onWorkerExit); + } + if (pp->onShutdown) { + sw_callable_free(pp->onShutdown); + } zend_object_std_dtor(object); } @@ -141,7 +149,11 @@ void php_swoole_process_pool_minit(int module_number) { swoole_process_pool, process_pool_create_object, process_pool_free_object, ProcessPoolObject, std); zend_declare_property_long(swoole_process_pool_ce, ZEND_STRL("master_pid"), -1, ZEND_ACC_PUBLIC); + zend_declare_property_long(swoole_process_pool_ce, ZEND_STRL("workerPid"), -1, ZEND_ACC_PUBLIC); + zend_declare_property_long(swoole_process_pool_ce, ZEND_STRL("workerId"), -1, ZEND_ACC_PUBLIC); zend_declare_property_null(swoole_process_pool_ce, ZEND_STRL("workers"), ZEND_ACC_PUBLIC); + zend_declare_property_bool(swoole_process_pool_ce, ZEND_STRL("workerRunning"), -1, ZEND_ACC_PUBLIC); + zend_declare_property_bool(swoole_process_pool_ce, ZEND_STRL("running"), -1, ZEND_ACC_PUBLIC); } static void process_pool_onWorkerStart(ProcessPool *pool, Worker *worker) { @@ -152,19 +164,22 @@ static void process_pool_onWorkerStart(ProcessPool *pool, Worker *worker) { current_pool = pool; current_worker = worker; - if (pp->onMessage) { - swoole_signal_set(SIGTERM, process_pool_signal_handler); - } + zend_update_property_bool(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("running"), true); + zend_update_property_bool(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("workerRunning"), true); + zend_update_property_long(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("workerPid"), getpid()); + zend_update_property_long(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("workerId"), worker->id); - if (!pp->onWorkerStart) { - return; + if (pp->onWorkerStart) { + zval args[2]; + args[0] = *zobject; + ZVAL_LONG(&args[1], worker->id); + if (UNEXPECTED(!zend::function::call(pp->onWorkerStart->ptr(), 2, args, nullptr, pp->enable_coroutine))) { + php_swoole_error(E_WARNING, "%s->onWorkerStart handler error", SW_Z_OBJCE_NAME_VAL_P(zobject)); + } } - zval args[2]; - args[0] = *zobject; - ZVAL_LONG(&args[1], worker->id); - if (UNEXPECTED(!zend::function::call(pp->onWorkerStart->ptr(), 2, args, nullptr, pp->enable_coroutine))) { - php_swoole_error(E_WARNING, "%s->onWorkerStart handler error", SW_Z_OBJCE_NAME_VAL_P(zobject)); + if (!swoole_signal_isset(SIGTERM) && (pp->onMessage || pp->enable_coroutine)) { + swoole_signal_set(SIGTERM, process_pool_signal_handler); } } @@ -201,6 +216,9 @@ static void process_pool_onWorkerStop(ProcessPool *pool, Worker *worker) { ProcessPoolObject *pp = process_pool_fetch_object(zobject); zval args[2]; + zend_update_property_bool(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("running"), false); + zend_update_property_bool(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("workerRunning"), false); + if (pp->onWorkerStop == nullptr) { return; } @@ -213,6 +231,63 @@ static void process_pool_onWorkerStop(ProcessPool *pool, Worker *worker) { } } +static void process_pool_onWorkerExit(ProcessPool *pool, Worker *worker) { + zval *zobject = (zval *) pool->ptr; + ProcessPoolObject *pp = process_pool_fetch_object(zobject); + zval args[2]; + + zend_update_property_bool(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("running"), false); + zend_update_property_bool(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("workerRunning"), false); + + if (pp->onWorkerExit == nullptr) { + return; + } + + args[0] = *zobject; + ZVAL_LONG(&args[1], worker->id); + + if (UNEXPECTED(!zend::function::call(pp->onWorkerExit->ptr(), 2, args, nullptr, false))) { + php_swoole_error(E_WARNING, "%s->onWorkerExit handler error", SW_Z_OBJCE_NAME_VAL_P(zobject)); + } +} + +static void process_pool_onStart(ProcessPool *pool) { + zval *zobject = (zval *) pool->ptr; + ProcessPoolObject *pp = process_pool_fetch_object(zobject); + zval args[1]; + + zend_update_property_long(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("master_pid"), getpid()); + zend_update_property_bool(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("running"), true); + + if (pp->onStart == nullptr) { + return; + } + + args[0] = *zobject; + if (UNEXPECTED(!zend::function::call(pp->onStart->ptr(), 1, args, nullptr, false))) { + php_swoole_error(E_WARNING, "%s->onStart handler error", SW_Z_OBJCE_NAME_VAL_P(zobject)); + } +} + +static void process_pool_onShutdown(ProcessPool *pool) { + zval *zobject = (zval *) pool->ptr; + ProcessPoolObject *pp = process_pool_fetch_object(zobject); + zval args[1]; + + zend_update_property_bool(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("running"), false); + zend_update_property_bool(swoole_process_pool_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("workerRunning"), false); + + if (pp->onShutdown == nullptr) { + return; + } + + args[0] = *zobject; + + if (UNEXPECTED(!zend::function::call(pp->onShutdown->ptr(), 1, args, nullptr, false))) { + php_swoole_error(E_WARNING, "%s->onShutdown handler error", SW_Z_OBJCE_NAME_VAL_P(zobject)); + } +} + static void process_pool_signal_handler(int sig) { if (!current_pool) { return; @@ -343,7 +418,8 @@ static PHP_METHOD(swoole_process_pool, on) { pp->onWorkerStart = sw_callable_create(zfn); } else if (SW_STRCASEEQ(name, l_name, "Message")) { if (pool->ipc_mode == SW_IPC_NONE) { - php_swoole_fatal_error(E_WARNING, "cannot set onMessage event with ipc_type=0"); + zend_throw_exception( + swoole_exception_ce, "cannot set `onMessage` event with ipc_type=0", SW_ERROR_INVALID_PARAMS); RETURN_FALSE; } if (pp->onMessage) { @@ -355,11 +431,21 @@ static PHP_METHOD(swoole_process_pool, on) { sw_callable_free(pp->onWorkerStop); } pp->onWorkerStop = sw_callable_create(zfn); + } else if (SW_STRCASEEQ(name, l_name, "WorkerExit")) { + if (pp->onWorkerExit) { + sw_callable_free(pp->onWorkerExit); + } + pp->onWorkerExit = sw_callable_create(zfn); } else if (SW_STRCASEEQ(name, l_name, "Start")) { if (pp->onStart) { sw_callable_free(pp->onStart); } pp->onStart = sw_callable_create(zfn); + } else if (SW_STRCASEEQ(name, l_name, "Shutdown")) { + if (pp->onShutdown) { + sw_callable_free(pp->onShutdown); + } + pp->onShutdown = sw_callable_create(zfn); } else { php_swoole_error(E_WARNING, "unknown event type[%s]", name); RETURN_FALSE; @@ -489,31 +575,33 @@ static PHP_METHOD(swoole_process_pool, start) { } } + if (pp->onWorkerExit && !pp->enable_coroutine) { + zend_throw_exception( + swoole_exception_ce, "cannot set `onWorkerExit` without enable_coroutine", SW_ERROR_INVALID_PARAMS); + RETURN_FALSE; + } + if (pp->onMessage) { pool->onMessage = process_pool_onMessage; } else { pool->main_loop = nullptr; } + current_pool = pool; + + pool->onStart = process_pool_onStart; + pool->onShutdown = process_pool_onShutdown; pool->onWorkerStart = process_pool_onWorkerStart; pool->onWorkerStop = process_pool_onWorkerStop; - zend_update_property_long(swoole_process_pool_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("master_pid"), getpid()); + if (pp->enable_coroutine && pp->onWorkerExit) { + pool->onWorkerExit = process_pool_onWorkerExit; + } if (pool->start() < 0) { RETURN_FALSE; } - current_pool = pool; - - if (pp->onStart) { - zval args[1]; - args[0] = *ZEND_THIS; - if (UNEXPECTED(!zend::function::call(pp->onStart->ptr(), 1, args, nullptr, 0))) { - php_swoole_error(E_WARNING, "%s->onStart handler error", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS)); - } - } - pool->wait(); pool->shutdown(); @@ -618,10 +706,13 @@ static PHP_METHOD(swoole_process_pool, stop) { } static PHP_METHOD(swoole_process_pool, shutdown) { - zval *retval = - sw_zend_read_property_ex(swoole_process_pool_ce, ZEND_THIS, SW_ZSTR_KNOWN(SW_ZEND_STR_MASTER_PID), 0); - long pid = zval_get_long(retval); - RETURN_BOOL(swoole_kill(pid, SIGTERM) == 0); + long pid = zend::object_get_long(ZEND_THIS, SW_ZSTR_KNOWN(SW_ZEND_STR_MASTER_PID)); + if (pid > 0) { + RETURN_BOOL(swoole_kill(pid, SIGTERM) == 0); + } else { + zend_throw_exception(swoole_exception_ce, "invalid master pid", SW_ERROR_INVALID_PARAMS); + RETURN_FALSE; + } } static PHP_METHOD(swoole_process_pool, __destruct) {} diff --git a/include/swoole_coroutine_system.h b/include/swoole_coroutine_system.h index dd6b3335d20..d552648e5a8 100644 --- a/include/swoole_coroutine_system.h +++ b/include/swoole_coroutine_system.h @@ -67,8 +67,8 @@ class System { static pid_t wait(int *__stat_loc, double timeout = -1); static pid_t waitpid(pid_t __pid, int *__stat_loc, int __options, double timeout = -1); /* signal */ - static bool wait_signal(int signal, double timeout = -1); - static bool wait_signal(const std::vector &signals, double timeout = -1); + static int wait_signal(int signal, double timeout = -1); + static int wait_signal(const std::vector &signals, double timeout = -1); /* event */ static int wait_event(int fd, int events, double timeout); }; diff --git a/include/swoole_process_pool.h b/include/swoole_process_pool.h index 003dacc3bfd..827f5ee0268 100644 --- a/include/swoole_process_pool.h +++ b/include/swoole_process_pool.h @@ -263,9 +263,12 @@ struct ProcessPool { uint8_t scheduler_warning; time_t warning_time; + void (*onStart)(ProcessPool *pool); + void (*onShutdown)(ProcessPool *pool); int (*onTask)(ProcessPool *pool, Worker *worker, EventData *task); void (*onWorkerStart)(ProcessPool *pool, Worker *worker); void (*onMessage)(ProcessPool *pool, RecvData *msg); + void (*onWorkerExit)(ProcessPool *pool, Worker *worker); void (*onWorkerStop)(ProcessPool *pool, Worker *worker); void (*onWorkerError)(ProcessPool *pool, Worker *worker, const ExitStatus &exit_status); void (*onWorkerMessage)(ProcessPool *pool, EventData *msg); @@ -277,7 +280,6 @@ struct ProcessPool { Worker *workers; std::vector> *pipes; std::unordered_map *map_; - Reactor *reactor; MsgQueue *queue; StreamInfo *stream_info_; Channel *message_box = nullptr; diff --git a/include/swoole_signal.h b/include/swoole_signal.h index f20a056e8b8..5416dedce5d 100644 --- a/include/swoole_signal.h +++ b/include/swoole_signal.h @@ -37,6 +37,7 @@ void swoole_signalfd_init(); #endif SW_API swSignalHandler swoole_signal_set(int signo, swSignalHandler func); +SW_API bool swoole_signal_isset(int signo); SW_API swSignalHandler swoole_signal_set(int signo, swSignalHandler func, int restart, int mask); SW_API swSignalHandler swoole_signal_get_handler(int signo); diff --git a/package.xml b/package.xml index b7eb5b7242f..b4ff8eeb475 100644 --- a/package.xml +++ b/package.xml @@ -2652,6 +2652,7 @@ + diff --git a/scripts/docker-compile-with-thread.sh b/scripts/docker-compile-with-thread.sh index 99c32bc48b3..4f0f5a6c6e4 100755 --- a/scripts/docker-compile-with-thread.sh +++ b/scripts/docker-compile-with-thread.sh @@ -13,6 +13,8 @@ cd "${__DIR__}" && cd .. ./scripts/clear.sh phpize ./configure \ +--enable-brotli \ +--enable-zstd \ --enable-openssl \ --enable-sockets \ --enable-mysqlnd \ diff --git a/scripts/docker-compile.sh b/scripts/docker-compile.sh index a7141baf0aa..d3f5f367f6a 100755 --- a/scripts/docker-compile.sh +++ b/scripts/docker-compile.sh @@ -13,6 +13,8 @@ cd "${__DIR__}" && cd .. ./scripts/clear.sh phpize ./configure \ +--enable-brotli \ +--enable-zstd \ --enable-openssl \ --enable-sockets \ --enable-mysqlnd \ diff --git a/tests/ubuntu.sh b/scripts/install-deps-on-ubuntu.sh old mode 100644 new mode 100755 similarity index 100% rename from tests/ubuntu.sh rename to scripts/install-deps-on-ubuntu.sh diff --git a/scripts/library.sh b/scripts/library.sh index fe85638c640..12d01138aba 100755 --- a/scripts/library.sh +++ b/scripts/library.sh @@ -1,6 +1,6 @@ #!/bin/sh -e apt update -apt install -y libaio-dev libaio1 sqlite3 libsqlite3-dev unixodbc unixodbc-dev odbc-mariadb +apt install -y libaio-dev libaio1 sqlite3 libsqlite3-dev unixodbc unixodbc-dev odbc-mariadb libzstd-dev wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip unzip instantclient-basiclite-linuxx64.zip && rm instantclient-basiclite-linuxx64.zip wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-sdk-linuxx64.zip diff --git a/src/coroutine/system.cc b/src/coroutine/system.cc index 90059dd6762..39c70f82f6e 100644 --- a/src/coroutine/system.cc +++ b/src/coroutine/system.cc @@ -223,7 +223,18 @@ std::vector System::getaddrinfo( return retval; } -bool System::wait_signal(int signal, double timeout) { +struct SignalListener { + Coroutine *co; + int signo; +}; + +/** + * Only the main thread should listen for signals, + * without modifying it to a thread-local variable. + */ +static SignalListener *listeners[SW_SIGNO_MAX]; + +int System::wait_signal(int signal, double timeout) { std::vector signals = {signal}; return wait_signal(signals, timeout); } @@ -231,31 +242,34 @@ bool System::wait_signal(int signal, double timeout) { /** * @error: swoole_get_last_error() */ -bool System::wait_signal(const std::vector &signals, double timeout) { - static Coroutine *listeners[SW_SIGNO_MAX]; - Coroutine *co = Coroutine::get_current_safe(); +int System::wait_signal(const std::vector &signals, double timeout) { + SignalListener listener = { + Coroutine::get_current_safe(), + -1, + }; if (SwooleTG.signal_listener_num > 0) { swoole_set_last_error(EBUSY); - return false; + return -1; } auto callback_fn = [](int signo) { - Coroutine *co = listeners[signo]; - if (co) { + auto listener = listeners[signo]; + if (listener) { listeners[signo] = nullptr; - co->resume(); + listener->signo = signo; + listener->co->resume(); } }; for (auto &signo : signals) { if (signo < 0 || signo >= SW_SIGNO_MAX || signo == SIGCHLD) { swoole_set_last_error(EINVAL); - return false; + return -1; } /* resgiter signal */ - listeners[signo] = co; + listeners[signo] = &listener; #ifdef SW_USE_THREAD_CONTEXT swoole_event_defer([signo, &callback_fn](void *) { swoole_signal_set(signo, callback_fn); }, nullptr); @@ -273,7 +287,7 @@ bool System::wait_signal(const std::vector &signals, double timeout) { SwooleTG.co_signal_listener_num++; - bool retval = co->yield_ex(timeout); + bool retval = listener.co->yield_ex(timeout); for (auto &signo : signals) { #ifdef SW_USE_THREAD_CONTEXT @@ -286,7 +300,7 @@ bool System::wait_signal(const std::vector &signals, double timeout) { SwooleTG.co_signal_listener_num--; - return retval; + return retval ? listener.signo : -1; } struct CoroPollTask { diff --git a/src/os/process_pool.cc b/src/os/process_pool.cc index 2762a979476..77233d2e509 100644 --- a/src/os/process_pool.cc +++ b/src/os/process_pool.cc @@ -265,11 +265,17 @@ int ProcessPool::start() { if (start_check() < 0) { return SW_ERR; } + + if (onStart) { + onStart(this); + } + SW_LOOP_N(worker_num) { if (spawn(&(workers[i])) < 0) { return SW_ERR; } } + return SW_OK; } @@ -417,9 +423,25 @@ bool ProcessPool::reload() { } void ProcessPool::stop(Worker *worker) { - if (async && worker->pipe_worker) { + worker->shutdown(); + + if (!swoole_event_is_available()) { + return; + } + + auto reactor = sw_reactor(); + if (worker->pipe_worker) { swoole_event_del(worker->pipe_worker); } + + if (onWorkerExit) { + reactor->set_end_callback(Reactor::PRIORITY_TRY_EXIT, [this, worker](Reactor *reactor) { + onWorkerExit(this, worker); + if (reactor->if_exit()) { + reactor->running = false; + } + }); + } } void ProcessPool::shutdown() { @@ -428,6 +450,10 @@ void ProcessPool::shutdown() { Worker *worker; running = 0; + if (onShutdown) { + onShutdown(this); + } + // concurrent kill for (i = 0; i < worker_num; i++) { worker = &workers[i]; diff --git a/src/os/signal.cc b/src/os/signal.cc index 86d1b26da5a..cab4a16e1fc 100644 --- a/src/os/signal.cc +++ b/src/os/signal.cc @@ -122,6 +122,10 @@ SignalHandler swoole_signal_set(int signo, SignalHandler func, int restart, int return oact.sa_handler; } +SW_API bool swoole_signal_isset(int signo) { + return signals[signo].handler && signals[signo].activated; +} + /** * set new signal handler and return origin signal handler */ diff --git a/tests/include/config.php b/tests/include/config.php index d54a78d3848..cc00a7d3bff 100644 --- a/tests/include/config.php +++ b/tests/include/config.php @@ -98,7 +98,7 @@ define('REDIS_SERVER_PWD', getenv('REDIS_SERVER_PWD') ?: 'root'); define('REDIS_SERVER_DB', (int)(getenv('REDIS_SERVER_DB') ?: 0)); -if (!getenv('SWOOLE_TEST_NO_DOCKER')) { +if (getenv('SWOOLE_TEST_IN_DOCKER')) { if (!empty($info = `docker ps 2>&1 | grep httpbin 2>&1`) && preg_match('/\s+?[^:]+:(\d+)->\d+\/tcp\s+/', $info, $matches) && is_numeric($matches[1])) { diff --git a/tests/swoole_client_async/enableSSL_bad_callback.phpt b/tests/swoole_client_async/enableSSL_bad_callback.phpt new file mode 100644 index 00000000000..707430db181 --- /dev/null +++ b/tests/swoole_client_async/enableSSL_bad_callback.phpt @@ -0,0 +1,16 @@ +--TEST-- +swoole_client_async: enableSSL with bad callback +--SKIPIF-- + +--FILE-- +enableSSL(); +} catch (Exception $e) { + Assert::contains($e->getMessage(), 'require `onSslReady` callback'); +} +?> +--EXPECTF-- diff --git a/tests/swoole_client_sync/enableSSL.phpt b/tests/swoole_client_sync/enableSSL.phpt new file mode 100644 index 00000000000..37e17f59d43 --- /dev/null +++ b/tests/swoole_client_sync/enableSSL.phpt @@ -0,0 +1,33 @@ +--TEST-- +swoole_client_async: enableSSL +--SKIPIF-- + +--FILE-- +connect("www.baidu.com", 443, 2.0)); + +if ($cli->enableSSL()) { + echo "SSL READY\n"; + $cli->send("GET / HTTP/1.1\r\nHost: www.baidu.com\r\nConnection: close\r\nUser-Agent: curl/7.50.1-DEV\r\nAccept: */*\r\n\r\n"); +} + +$resp = ''; +while (true) { + $data = $cli->recv(); + if ($data == false) { + break; + } + $resp .= $data; +} + +Assert::assert(strlen($resp) > 0); +Assert::contains($resp, 'www.baidu.com'); +$cli->close(); +echo "DONE\n"; +?> +--EXPECT-- +SSL READY +DONE diff --git a/tests/swoole_client_sync/enableSSL_2.phpt b/tests/swoole_client_sync/enableSSL_2.phpt new file mode 100644 index 00000000000..aa787584a8a --- /dev/null +++ b/tests/swoole_client_sync/enableSSL_2.phpt @@ -0,0 +1,18 @@ +--TEST-- +swoole_client_async: enableSSL +--SKIPIF-- + +--FILE-- +connect("www.baidu.com", 443, 2.0)); + +try { + $cli->enableSSL(function (){}); +} catch (\Throwable $e) { + Assert::contains($e->getMessage(), 'not support `onSslReady` callback'); +} +?> +--EXPECT-- diff --git a/tests/swoole_coroutine_system/waitSignal.phpt b/tests/swoole_coroutine_system/waitSignal.phpt index 9f424775b3c..44758850e31 100644 --- a/tests/swoole_coroutine_system/waitSignal.phpt +++ b/tests/swoole_coroutine_system/waitSignal.phpt @@ -32,13 +32,13 @@ Coroutine\run(function () use ($atomic) { switch_process(); $atomic->wakeup(); echo "1\n"; - Assert::true(System::waitSignal(SIGUSR1)); + Assert::eq(System::waitSignal(SIGUSR1), SIGUSR1); echo "3\n"; Assert::false(System::waitSignal(SIGUSR2, 0.01)); echo "4\n"; $atomic->wakeup(); echo "5\n"; - Assert::true(System::waitSignal(SIGUSR2)); + Assert::eq(System::waitSignal(SIGUSR2), SIGUSR2); echo "7\n"; System::wait(); echo "9\n"; diff --git a/tests/swoole_coroutine_system/waitSignal_2.phpt b/tests/swoole_coroutine_system/waitSignal_2.phpt index b8340e8efcf..09d238d23fc 100644 --- a/tests/swoole_coroutine_system/waitSignal_2.phpt +++ b/tests/swoole_coroutine_system/waitSignal_2.phpt @@ -33,13 +33,13 @@ Coroutine\run(function () use ($atomic) { $atomic->wakeup(); echo "1\n"; $list = [SIGUSR1, SIGUSR2, SIGIO]; - Assert::true(System::waitSignal($list)); + Assert::eq(System::waitSignal($list), SIGUSR1); echo "3\n"; Assert::false(System::waitSignal($list, 0.01)); echo "4\n"; $atomic->wakeup(); echo "5\n"; - Assert::true(System::waitSignal($list)); + Assert::eq(System::waitSignal($list), SIGUSR2); echo "7\n"; System::wait(); echo "9\n"; diff --git a/tests/swoole_http_server/zstd.phpt b/tests/swoole_http_server/zstd.phpt new file mode 100644 index 00000000000..79d9d1753c7 --- /dev/null +++ b/tests/swoole_http_server/zstd.phpt @@ -0,0 +1,48 @@ +--TEST-- +swoole_http_server: support zstd compress +--SKIPIF-- + +--FILE-- +parentFunc = function ($pid) use ($pm, $data) { + run(function () use ($pm, $data) { + $client = new Client('127.0.0.1', $pm->getFreePort()); + $client->setHeaders(['Accept-Encoding' => 'zstd']); + $client->get('/'); + Assert::true($client->body == $data); + Assert::true($client->headers['content-encoding'] == 'zstd'); + Assert::true($client->headers['content-length'] != strlen($client->body)); + }); + echo "DONE\n"; + $pm->kill(); +}; + +$pm->childFunc = function () use ($pm, $data) { + $serv = new Swoole\Http\Server('127.0.0.1', $pm->getFreePort()); + $serv->set([ + 'compression_level' => 20 + ]); + $serv->on("workerStart", function ($serv) use ($pm) { + $pm->wakeup(); + }); + $serv->on('request', function ($req, $resp) use ($data) { + $resp->end($data); + }); + $serv->start(); +}; +$pm->childFirst(); +$pm->run(); +?> +--EXPECT-- +DONE diff --git a/tests/swoole_process_pool/master_callback.phpt b/tests/swoole_process_pool/master_callback.phpt new file mode 100644 index 00000000000..0bfb29f95ca --- /dev/null +++ b/tests/swoole_process_pool/master_callback.phpt @@ -0,0 +1,47 @@ +--TEST-- +swoole_process_pool: master callback +--SKIPIF-- + +--FILE-- +on('workerStart', function (Swoole\Process\Pool $pool, int $workerId) { + echo "worker start\n"; + Assert::true($pool->workerRunning); + Assert::eq($pool->workerId, 0); + Assert::eq($pool->workerPid, posix_getpid()); + pcntl_signal(SIGTERM, function (){ + + }); + $pool->shutdown(); + sleep(20); + echo "worker exit\n"; +}); + +$pool->on('workerStop', function (Swoole\Process\Pool $pool, int $workerId) { + Assert::false($pool->workerRunning); + echo "worker stop\n"; +}); + +$pool->on('start', function (Swoole\Process\Pool $pool) { + Assert::true($pool->running); + echo "start\n"; +}); + +$pool->on('shutdown', function (Swoole\Process\Pool $pool) { + Assert::false($pool->running); + echo "shutdown\n"; +}); + +$pool->start(); +?> +--EXPECT-- +start +worker start +shutdown +worker exit +worker stop diff --git a/tests/swoole_process_pool/worker_exit_1.phpt b/tests/swoole_process_pool/worker_exit_1.phpt new file mode 100644 index 00000000000..2b9462eee2a --- /dev/null +++ b/tests/swoole_process_pool/worker_exit_1.phpt @@ -0,0 +1,56 @@ +--TEST-- +swoole_process_pool: worker exit +--SKIPIF-- + +--FILE-- +on('workerStart', function (Swoole\Process\Pool $pool, int $workerId) { + echo "worker start\n"; + Assert::eq($pool->workerId, $workerId); + + $count = 0; + while ($GLOBALS['running']) { + Co::sleep(0.03); + echo "sleep\n"; + if (++$count === 3) { + $pool->shutdown(); + } + } +}); + +$pool->on('workerStop', function ($pool, $data) { + echo "worker stop\n"; +}); + +$pool->on('workerExit', function ($pool, $data) { + $GLOBALS['count']++; + if ($GLOBALS['count'] == 3) { + $GLOBALS['running'] = false; + } + echo ('worker exit') . PHP_EOL; +}); + +$pool->start(); +?> +--EXPECT-- +worker start +sleep +sleep +sleep +worker exit +sleep +worker exit +sleep +worker exit +worker stop diff --git a/tests/swoole_timer/bug_4794_4.phpt b/tests/swoole_timer/bug_4794_4.phpt index c14206b363a..44be4623ad7 100644 --- a/tests/swoole_timer/bug_4794_4.phpt +++ b/tests/swoole_timer/bug_4794_4.phpt @@ -32,13 +32,13 @@ Coroutine\run(function () use ($atomic) { switch_process(); $atomic->wakeup(); echo "1\n"; - Assert::true(System::waitSignal(SIGUSR1)); + Assert::eq(System::waitSignal(SIGUSR1), SIGUSR1); echo "3\n"; Assert::false(System::waitSignal(SIGUSR2, 0.0001)); echo "4\n"; $atomic->wakeup(); echo "5\n"; - Assert::true(System::waitSignal(SIGUSR2)); + Assert::eq(System::waitSignal(SIGUSR2), SIGUSR2); echo "7\n"; System::wait(0.0001); echo "9\n";