Skip to content

Commit 18e2166

Browse files
committed
Copy the server settings before launching the worker threads, fixed #5651
1 parent 71c93fd commit 18e2166

10 files changed

+215
-10
lines changed

ext-src/php_swoole.cc

+30-2
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,34 @@ void sw_php_exit(int status) {
10481048
#endif
10491049
}
10501050

1051+
bool sw_zval_is_serializable(zval *struc) {
1052+
again:
1053+
switch (Z_TYPE_P(struc)) {
1054+
case IS_OBJECT: {
1055+
if (Z_OBJCE_P(struc)->ce_flags & ZEND_ACC_NOT_SERIALIZABLE) {
1056+
return false;
1057+
}
1058+
break;
1059+
}
1060+
case IS_ARRAY: {
1061+
zval *elem;
1062+
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(struc), elem) {
1063+
if (!sw_zval_is_serializable(elem)) {
1064+
return false;
1065+
}
1066+
}
1067+
ZEND_HASH_FOREACH_END();
1068+
break;
1069+
}
1070+
case IS_REFERENCE:
1071+
struc = Z_REFVAL_P(struc);
1072+
goto again;
1073+
default:
1074+
break;
1075+
}
1076+
return true;
1077+
}
1078+
10511079
static void sw_after_fork(void *args) {
10521080
#ifdef ZEND_MAX_EXECUTION_TIMERS
10531081
zend_max_execution_timer_init();
@@ -1478,7 +1506,7 @@ static PHP_FUNCTION(swoole_substr_unserialize) {
14781506
if ((zend_long) buf_len <= offset) {
14791507
RETURN_FALSE;
14801508
}
1481-
if (length <= 0 || length > (zend_long)(buf_len - offset)) {
1509+
if (length <= 0 || length > (zend_long) (buf_len - offset)) {
14821510
length = buf_len - offset;
14831511
}
14841512
zend::unserialize(return_value, buf + offset, length, options ? Z_ARRVAL_P(options) : NULL);
@@ -1518,7 +1546,7 @@ static PHP_FUNCTION(swoole_substr_json_decode) {
15181546
php_error_docref(nullptr, E_WARNING, "Offset must be less than the length of the string");
15191547
RETURN_NULL();
15201548
}
1521-
if (length <= 0 || length > (zend_long)(str_len - offset)) {
1549+
if (length <= 0 || length > (zend_long) (str_len - offset)) {
15221550
length = str_len - offset;
15231551
}
15241552
/* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */

ext-src/php_swoole_private.h

+2
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,8 @@ static inline bool sw_zval_is_process(zval *val) {
505505
return instanceof_function(Z_OBJCE_P(val), swoole_process_ce);
506506
}
507507

508+
bool sw_zval_is_serializable(zval *struc);
509+
508510
static inline bool sw_is_main_thread() {
509511
#ifdef SW_THREAD
510512
return tsrm_is_main_thread();

ext-src/php_swoole_server.h

+1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ struct ServerObject {
126126

127127
void register_callback();
128128
void on_before_start();
129+
void copy_setting(zval *zsetting);
129130
};
130131

131132
struct TaskCo {

ext-src/swoole_server.cc

+29
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ static void server_free_object(zend_object *object) {
235235

236236
zend_object_std_dtor(object);
237237
if (serv && serv->is_master()) {
238+
#ifdef SW_THREAD
239+
if (serv->is_thread_mode()) {
240+
zend_string_release((zend_string *) serv->private_data_4);
241+
}
242+
#endif
238243
delete serv;
239244
}
240245
}
@@ -808,6 +813,17 @@ static zval *php_swoole_server_add_port(ServerObject *server_object, ListenPort
808813
return zport;
809814
}
810815

816+
void ServerObject::copy_setting(zval *zsetting) {
817+
zend_array *new_array = zend_array_dup(Z_ARRVAL_P(zsetting));
818+
zend_hash_apply(new_array, [](zval *el) -> int {
819+
return sw_zval_is_serializable(el) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
820+
});
821+
zval znew_array;
822+
ZVAL_ARR(&znew_array, new_array);
823+
serv->private_data_4 = php_swoole_serialize(&znew_array);
824+
zval_ptr_dtor(&znew_array);
825+
}
826+
811827
void ServerObject::on_before_start() {
812828
/**
813829
* create swoole server
@@ -995,6 +1011,12 @@ void ServerObject::on_before_start() {
9951011
}
9961012
}
9971013

1014+
#ifdef SW_THREAD
1015+
if (serv->is_thread_mode()) {
1016+
copy_setting(zsetting);
1017+
}
1018+
#endif
1019+
9981020
if (SWOOLE_G(enable_library)) {
9991021
zend::function::call("\\Swoole\\Server\\Helper::onBeforeStart", 1, zobject);
10001022
}
@@ -2470,6 +2492,11 @@ static PHP_METHOD(swoole_server, getCallback) {
24702492

24712493
static PHP_METHOD(swoole_server, listen) {
24722494
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
2495+
if (serv->is_worker_thread()) {
2496+
swoole_set_last_error(SW_ERROR_SERVER_UNRELATED_THREAD);
2497+
RETURN_FALSE;
2498+
}
2499+
24732500
if (serv->is_started()) {
24742501
php_swoole_fatal_error(E_WARNING, "server is running, can't add listener");
24752502
RETURN_FALSE;
@@ -2614,6 +2641,8 @@ static PHP_METHOD(swoole_server, start) {
26142641

26152642
#ifdef SW_THREAD
26162643
if (serv->is_worker_thread()) {
2644+
zval *zsetting = sw_zend_read_and_convert_property_array(Z_OBJCE_P(ZEND_THIS), zserv, ZEND_STRL("setting"), 0);
2645+
php_swoole_unserialize((zend_string *) serv->private_data_4, zsetting);
26172646
worker_thread_fn();
26182647
RETURN_TRUE;
26192648
}

include/swoole_server.h

+1
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,7 @@ class Server {
766766
void *private_data_1 = nullptr;
767767
void *private_data_2 = nullptr;
768768
void *private_data_3 = nullptr;
769+
void *private_data_4 = nullptr;
769770

770771
Factory *factory = nullptr;
771772
Manager *manager = nullptr;

scripts/format-changed-files.sh

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
changed_files=$(git status --porcelain | grep '^[ M].*\.cc$' | awk '{print $2}')
4+
5+
if [ -z "$changed_files" ]; then
6+
exit 0
7+
fi
8+
9+
for file in $changed_files; do
10+
echo "format $file"
11+
clang-format -i "$file"
12+
done
13+
14+
echo "done"

tests/swoole_thread/server/base.phpt

+2-8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ skip_if_nts();
88
--FILE--
99
<?php
1010
require __DIR__ . '/../../include/bootstrap.php';
11+
require __DIR__ . '/functions.inc';
1112

1213
use Swoole\Thread;
1314

@@ -49,14 +50,7 @@ $serv->addProcess(new Swoole\Process(function ($process) use ($serv) {
4950
global $port;
5051
echo $queue->pop(-1);
5152
Co\run(function () use ($port) {
52-
$cli = new Co\Client(SWOOLE_SOCK_TCP);
53-
$cli->set([
54-
'open_eof_check' => true,
55-
'package_eof' => "\r\n",
56-
]);
57-
Assert::assert($cli->connect('127.0.0.1', $port, 2));
58-
$cli->send(json_encode(['type' => 'eof']) . "\r\n");
59-
Assert::eq($cli->recv(), "EOF\r\n");
53+
thread_server_test_eof_client($port);
6054
});
6155
$atomic->set(0);
6256
echo "done\n";
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
function thread_server_test_eof_client($port)
3+
{
4+
$cli = new Co\Client(SWOOLE_SOCK_TCP);
5+
$cli->set([
6+
'open_eof_check' => true,
7+
'package_eof' => "\r\n",
8+
]);
9+
Assert::assert($cli->connect('127.0.0.1', $port, 2));
10+
$cli->send(json_encode(['type' => 'eof']) . "\r\n");
11+
Assert::eq($cli->recv(), "EOF\r\n");
12+
}
+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
--TEST--
2+
swoole_thread/server: listen
3+
--SKIPIF--
4+
<?php
5+
require __DIR__ . '/../../include/skipif.inc';
6+
skip_if_nts();
7+
?>
8+
--FILE--
9+
<?php
10+
require __DIR__ . '/../../include/bootstrap.php';
11+
require __DIR__ . '/functions.inc';
12+
13+
use Swoole\Thread;
14+
15+
$port = get_constant_port(__FILE__);
16+
17+
$serv = new Swoole\Server('127.0.0.1', $port + 1, SWOOLE_THREAD);
18+
$port2 = $serv->listen('127.0.0.1', $port, SWOOLE_SOCK_TCP);
19+
$serv->set(array(
20+
'worker_num' => 2,
21+
'log_level' => SWOOLE_LOG_ERROR,
22+
'open_eof_check' => true,
23+
'package_eof' => "\r\n",
24+
'init_arguments' => function () {
25+
global $queue, $atomic;
26+
$queue = new Swoole\Thread\Queue();
27+
$atomic = new Swoole\Thread\Atomic(1);
28+
return [$queue, $atomic];
29+
}
30+
));
31+
$serv->on('WorkerStart', function (Swoole\Server $serv, $workerId) use ($port) {
32+
[$queue, $atomic] = Thread::getArguments();
33+
if ($workerId == 0) {
34+
$queue->push("begin\n", Thread\Queue::NOTIFY_ALL);
35+
}
36+
});
37+
$serv->on('receive', function (Swoole\Server $serv, $fd, $rid, $data) {
38+
$json = json_decode(rtrim($data));
39+
if ($json->type == 'eof') {
40+
$serv->send($fd, "EOF\r\n");
41+
}
42+
});
43+
$serv->on('shutdown', function () {
44+
global $queue, $atomic;
45+
echo 'shutdown', PHP_EOL;
46+
Assert::eq($atomic->get(), 0);
47+
});
48+
$serv->addProcess(new Swoole\Process(function ($process) use ($serv) {
49+
[$queue, $atomic] = Thread::getArguments();
50+
global $port;
51+
echo $queue->pop(-1);
52+
Co\run(function () use ($port) {
53+
Co::join([
54+
Co\go(function () use ($port) {
55+
thread_server_test_eof_client($port);
56+
}),
57+
Co\go(function () use ($port) {
58+
thread_server_test_eof_client($port + 1);
59+
})
60+
]);
61+
});
62+
$atomic->set(0);
63+
echo "done\n";
64+
$serv->shutdown();
65+
}));
66+
$serv->start();
67+
?>
68+
--EXPECT--
69+
begin
70+
done
71+
shutdown
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
--TEST--
2+
swoole_thread/server: setting
3+
--SKIPIF--
4+
<?php
5+
require __DIR__ . '/../../include/skipif.inc';
6+
skip_if_nts();
7+
?>
8+
--FILE--
9+
<?php
10+
require __DIR__ . '/../../include/bootstrap.php';
11+
12+
use Swoole\Thread;
13+
14+
$port = get_constant_port(__FILE__);
15+
const N = 4;
16+
17+
$serv = new Swoole\Server('127.0.0.1', $port, SWOOLE_THREAD);
18+
$serv->set(array(
19+
'worker_num' => N,
20+
'log_level' => SWOOLE_LOG_ERROR,
21+
'init_arguments' => function () {
22+
global $queue, $atomic;
23+
$queue = new Swoole\Thread\Queue();
24+
$atomic = new Swoole\Thread\Atomic(0);
25+
return [$queue, $atomic];
26+
}
27+
));
28+
$serv->on('WorkerStart', function (Swoole\Server $serv, $workerId) use ($port) {
29+
[$queue, $atomic] = Thread::getArguments();
30+
Assert::isArray($serv->setting);
31+
if ($atomic->add(1) == N) {
32+
$queue->push("begin\n", Thread\Queue::NOTIFY_ALL);
33+
}
34+
});
35+
$serv->on('receive', function (Swoole\Server $serv, $fd, $rid, $data) {
36+
});
37+
$serv->on('shutdown', function () {
38+
global $queue, $atomic;
39+
echo 'shutdown', PHP_EOL;
40+
Assert::eq($atomic->get(), N);
41+
});
42+
$serv->addProcess(new Swoole\Process(function ($process) use ($serv) {
43+
[$queue, $atomic] = Thread::getArguments();
44+
echo $queue->pop(-1);
45+
echo "done\n";
46+
$serv->shutdown();
47+
}));
48+
$serv->start();
49+
?>
50+
--EXPECT--
51+
begin
52+
done
53+
shutdown

0 commit comments

Comments
 (0)