Skip to content

Commit

Permalink
Copy the server settings before launching the worker threads, fixed #…
Browse files Browse the repository at this point in the history
  • Loading branch information
matyhtf committed Jan 3, 2025
1 parent 71c93fd commit 18e2166
Show file tree
Hide file tree
Showing 10 changed files with 215 additions and 10 deletions.
32 changes: 30 additions & 2 deletions ext-src/php_swoole.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,34 @@ void sw_php_exit(int status) {
#endif
}

bool sw_zval_is_serializable(zval *struc) {
again:
switch (Z_TYPE_P(struc)) {
case IS_OBJECT: {
if (Z_OBJCE_P(struc)->ce_flags & ZEND_ACC_NOT_SERIALIZABLE) {
return false;
}
break;
}
case IS_ARRAY: {
zval *elem;
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(struc), elem) {
if (!sw_zval_is_serializable(elem)) {
return false;
}
}
ZEND_HASH_FOREACH_END();
break;
}
case IS_REFERENCE:
struc = Z_REFVAL_P(struc);
goto again;
default:
break;
}
return true;
}

static void sw_after_fork(void *args) {
#ifdef ZEND_MAX_EXECUTION_TIMERS
zend_max_execution_timer_init();
Expand Down Expand Up @@ -1478,7 +1506,7 @@ static PHP_FUNCTION(swoole_substr_unserialize) {
if ((zend_long) buf_len <= offset) {
RETURN_FALSE;
}
if (length <= 0 || length > (zend_long)(buf_len - offset)) {
if (length <= 0 || length > (zend_long) (buf_len - offset)) {
length = buf_len - offset;
}
zend::unserialize(return_value, buf + offset, length, options ? Z_ARRVAL_P(options) : NULL);
Expand Down Expand Up @@ -1518,7 +1546,7 @@ static PHP_FUNCTION(swoole_substr_json_decode) {
php_error_docref(nullptr, E_WARNING, "Offset must be less than the length of the string");
RETURN_NULL();
}
if (length <= 0 || length > (zend_long)(str_len - offset)) {
if (length <= 0 || length > (zend_long) (str_len - offset)) {
length = str_len - offset;
}
/* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
Expand Down
2 changes: 2 additions & 0 deletions ext-src/php_swoole_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ static inline bool sw_zval_is_process(zval *val) {
return instanceof_function(Z_OBJCE_P(val), swoole_process_ce);
}

bool sw_zval_is_serializable(zval *struc);

static inline bool sw_is_main_thread() {
#ifdef SW_THREAD
return tsrm_is_main_thread();
Expand Down
1 change: 1 addition & 0 deletions ext-src/php_swoole_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ struct ServerObject {

void register_callback();
void on_before_start();
void copy_setting(zval *zsetting);
};

struct TaskCo {
Expand Down
29 changes: 29 additions & 0 deletions ext-src/swoole_server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ static void server_free_object(zend_object *object) {

zend_object_std_dtor(object);
if (serv && serv->is_master()) {
#ifdef SW_THREAD
if (serv->is_thread_mode()) {
zend_string_release((zend_string *) serv->private_data_4);
}
#endif
delete serv;
}
}
Expand Down Expand Up @@ -808,6 +813,17 @@ static zval *php_swoole_server_add_port(ServerObject *server_object, ListenPort
return zport;
}

void ServerObject::copy_setting(zval *zsetting) {
zend_array *new_array = zend_array_dup(Z_ARRVAL_P(zsetting));
zend_hash_apply(new_array, [](zval *el) -> int {
return sw_zval_is_serializable(el) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
});
zval znew_array;
ZVAL_ARR(&znew_array, new_array);
serv->private_data_4 = php_swoole_serialize(&znew_array);
zval_ptr_dtor(&znew_array);
}

void ServerObject::on_before_start() {
/**
* create swoole server
Expand Down Expand Up @@ -995,6 +1011,12 @@ void ServerObject::on_before_start() {
}
}

#ifdef SW_THREAD
if (serv->is_thread_mode()) {
copy_setting(zsetting);
}
#endif

if (SWOOLE_G(enable_library)) {
zend::function::call("\\Swoole\\Server\\Helper::onBeforeStart", 1, zobject);
}
Expand Down Expand Up @@ -2470,6 +2492,11 @@ static PHP_METHOD(swoole_server, getCallback) {

static PHP_METHOD(swoole_server, listen) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
if (serv->is_worker_thread()) {
swoole_set_last_error(SW_ERROR_SERVER_UNRELATED_THREAD);
RETURN_FALSE;
}

if (serv->is_started()) {
php_swoole_fatal_error(E_WARNING, "server is running, can't add listener");
RETURN_FALSE;
Expand Down Expand Up @@ -2614,6 +2641,8 @@ static PHP_METHOD(swoole_server, start) {

#ifdef SW_THREAD
if (serv->is_worker_thread()) {
zval *zsetting = sw_zend_read_and_convert_property_array(Z_OBJCE_P(ZEND_THIS), zserv, ZEND_STRL("setting"), 0);
php_swoole_unserialize((zend_string *) serv->private_data_4, zsetting);
worker_thread_fn();
RETURN_TRUE;
}
Expand Down
1 change: 1 addition & 0 deletions include/swoole_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ class Server {
void *private_data_1 = nullptr;
void *private_data_2 = nullptr;
void *private_data_3 = nullptr;
void *private_data_4 = nullptr;

Factory *factory = nullptr;
Manager *manager = nullptr;
Expand Down
14 changes: 14 additions & 0 deletions scripts/format-changed-files.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

changed_files=$(git status --porcelain | grep '^[ M].*\.cc$' | awk '{print $2}')

if [ -z "$changed_files" ]; then
exit 0
fi

for file in $changed_files; do
echo "format $file"
clang-format -i "$file"
done

echo "done"
10 changes: 2 additions & 8 deletions tests/swoole_thread/server/base.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ skip_if_nts();
--FILE--
<?php
require __DIR__ . '/../../include/bootstrap.php';
require __DIR__ . '/functions.inc';

use Swoole\Thread;

Expand Down Expand Up @@ -49,14 +50,7 @@ $serv->addProcess(new Swoole\Process(function ($process) use ($serv) {
global $port;
echo $queue->pop(-1);
Co\run(function () use ($port) {
$cli = new Co\Client(SWOOLE_SOCK_TCP);
$cli->set([
'open_eof_check' => true,
'package_eof' => "\r\n",
]);
Assert::assert($cli->connect('127.0.0.1', $port, 2));
$cli->send(json_encode(['type' => 'eof']) . "\r\n");
Assert::eq($cli->recv(), "EOF\r\n");
thread_server_test_eof_client($port);
});
$atomic->set(0);
echo "done\n";
Expand Down
12 changes: 12 additions & 0 deletions tests/swoole_thread/server/functions.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php
function thread_server_test_eof_client($port)
{
$cli = new Co\Client(SWOOLE_SOCK_TCP);
$cli->set([
'open_eof_check' => true,
'package_eof' => "\r\n",
]);
Assert::assert($cli->connect('127.0.0.1', $port, 2));
$cli->send(json_encode(['type' => 'eof']) . "\r\n");
Assert::eq($cli->recv(), "EOF\r\n");
}
71 changes: 71 additions & 0 deletions tests/swoole_thread/server/listen.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
--TEST--
swoole_thread/server: listen
--SKIPIF--
<?php
require __DIR__ . '/../../include/skipif.inc';
skip_if_nts();
?>
--FILE--
<?php
require __DIR__ . '/../../include/bootstrap.php';
require __DIR__ . '/functions.inc';

use Swoole\Thread;

$port = get_constant_port(__FILE__);

$serv = new Swoole\Server('127.0.0.1', $port + 1, SWOOLE_THREAD);
$port2 = $serv->listen('127.0.0.1', $port, SWOOLE_SOCK_TCP);
$serv->set(array(
'worker_num' => 2,
'log_level' => SWOOLE_LOG_ERROR,
'open_eof_check' => true,
'package_eof' => "\r\n",
'init_arguments' => function () {
global $queue, $atomic;
$queue = new Swoole\Thread\Queue();
$atomic = new Swoole\Thread\Atomic(1);
return [$queue, $atomic];
}
));
$serv->on('WorkerStart', function (Swoole\Server $serv, $workerId) use ($port) {
[$queue, $atomic] = Thread::getArguments();
if ($workerId == 0) {
$queue->push("begin\n", Thread\Queue::NOTIFY_ALL);
}
});
$serv->on('receive', function (Swoole\Server $serv, $fd, $rid, $data) {
$json = json_decode(rtrim($data));
if ($json->type == 'eof') {
$serv->send($fd, "EOF\r\n");
}
});
$serv->on('shutdown', function () {
global $queue, $atomic;
echo 'shutdown', PHP_EOL;
Assert::eq($atomic->get(), 0);
});
$serv->addProcess(new Swoole\Process(function ($process) use ($serv) {
[$queue, $atomic] = Thread::getArguments();
global $port;
echo $queue->pop(-1);
Co\run(function () use ($port) {
Co::join([
Co\go(function () use ($port) {
thread_server_test_eof_client($port);
}),
Co\go(function () use ($port) {
thread_server_test_eof_client($port + 1);
})
]);
});
$atomic->set(0);
echo "done\n";
$serv->shutdown();
}));
$serv->start();
?>
--EXPECT--
begin
done
shutdown
53 changes: 53 additions & 0 deletions tests/swoole_thread/server/setting.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
--TEST--
swoole_thread/server: setting
--SKIPIF--
<?php
require __DIR__ . '/../../include/skipif.inc';
skip_if_nts();
?>
--FILE--
<?php
require __DIR__ . '/../../include/bootstrap.php';

use Swoole\Thread;

$port = get_constant_port(__FILE__);
const N = 4;

$serv = new Swoole\Server('127.0.0.1', $port, SWOOLE_THREAD);
$serv->set(array(
'worker_num' => N,
'log_level' => SWOOLE_LOG_ERROR,
'init_arguments' => function () {
global $queue, $atomic;
$queue = new Swoole\Thread\Queue();
$atomic = new Swoole\Thread\Atomic(0);
return [$queue, $atomic];
}
));
$serv->on('WorkerStart', function (Swoole\Server $serv, $workerId) use ($port) {
[$queue, $atomic] = Thread::getArguments();
Assert::isArray($serv->setting);
if ($atomic->add(1) == N) {
$queue->push("begin\n", Thread\Queue::NOTIFY_ALL);
}
});
$serv->on('receive', function (Swoole\Server $serv, $fd, $rid, $data) {
});
$serv->on('shutdown', function () {
global $queue, $atomic;
echo 'shutdown', PHP_EOL;
Assert::eq($atomic->get(), N);
});
$serv->addProcess(new Swoole\Process(function ($process) use ($serv) {
[$queue, $atomic] = Thread::getArguments();
echo $queue->pop(-1);
echo "done\n";
$serv->shutdown();
}));
$serv->start();
?>
--EXPECT--
begin
done
shutdown

0 comments on commit 18e2166

Please sign in to comment.