diff --git a/.github/workflows/conflict-exts.yml b/.github/workflows/conflict-exts.yml
index 7ddae7bbcaf..d158869b793 100644
--- a/.github/workflows/conflict-exts.yml
+++ b/.github/workflows/conflict-exts.yml
@@ -4,11 +4,12 @@ on: [push, pull_request]
jobs:
tests:
+ if: "github.repository_owner == 'swoole' && !contains(github.event.head_commit.message, '[test]')"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
- php: ['8.0', '8.1', '8.2', '8.3']
+ php: ['8.1', '8.2', '8.3']
name: PHP ${{ matrix.php }} - Swoole
diff --git a/.github/workflows/framework.yml b/.github/workflows/framework.yml
index 1a591640c4e..ccb4ceebb5a 100644
--- a/.github/workflows/framework.yml
+++ b/.github/workflows/framework.yml
@@ -7,11 +7,12 @@ on:
jobs:
linux:
runs-on: ubuntu-latest
- if: "!contains(github.event.head_commit.message, '[test]')"
+ if: 0
+# if: "!contains(github.event.head_commit.message, '[test]')"
strategy:
fail-fast: false
matrix:
- php-version: [ '8.0', '8.1', '8.2', '8.3' ]
+ php-version: [ '8.1', '8.2', '8.3' ]
framework: [ 'Laravel Octane', 'Hyperf', 'Simps', 'imi' ]
name: ${{ matrix.framework }} - PHP ${{ matrix.php-version }}
steps:
@@ -102,7 +103,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- php-version: [ '8.0', '8.1', '8.2', '8.3' ]
+ php-version: [ '8.1', '8.2', '8.3' ]
framework: [ 'Simps' ]
name: ${{ matrix.framework }} - PHP ${{ matrix.php-version }} - macOS
steps:
diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml
index 85cdd5ab65e..bcbdc938d93 100644
--- a/.github/workflows/test-linux.yml
+++ b/.github/workflows/test-linux.yml
@@ -5,10 +5,11 @@ on: [push, pull_request]
jobs:
test-linux:
runs-on: ubuntu-latest
+ if: "!contains(github.event.head_commit.message, '[zts]')"
strategy:
fail-fast: false
matrix:
- php: ['8.0', '8.1', '8.2', '8.3']
+ php: ['8.1', '8.2', '8.3']
steps:
- uses: actions/checkout@v4
- name: Setup PHP
@@ -34,4 +35,6 @@ jobs:
- name: Run Swoole test
run: |
export SWOOLE_BRANCH=${GITHUB_REF##*/}
+ export SWOOLE_BUILD_DIR=$(realpath .)
+ export PHP_VERSION=${{ matrix.php }}
${{runner.workspace}}/swoole-src/scripts/route.sh
diff --git a/.github/workflows/thread.yml b/.github/workflows/thread.yml
new file mode 100644
index 00000000000..eb81aa23927
--- /dev/null
+++ b/.github/workflows/thread.yml
@@ -0,0 +1,41 @@
+name: Thread Support Tests
+
+on: [push, pull_request]
+
+jobs:
+ test-linux:
+ runs-on: ubuntu-latest
+ if: "!contains(github.event.head_commit.message, '[nts]')"
+ strategy:
+ fail-fast: false
+ matrix:
+ php: ['8.1-zts', '8.2-zts', '8.3-zts']
+ name: ${{ matrix.php }}
+ steps:
+ - uses: actions/checkout@v4
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: "${{ matrix.php }}"
+ coverage: none
+ env:
+ phpts: ts
+ - name: Show machine information
+ run: |
+ date
+ env
+ uname -a
+ ulimit -a
+ php -v
+ php --ini
+ ls -al
+ pwd
+ echo "`git log -20 --pretty --oneline`"
+ echo "`git log -10 --stat --pretty --oneline`"
+ - name: Run Swoole test
+ run: |
+ export SWOOLE_BRANCH=${GITHUB_REF##*/}
+ export SWOOLE_THREAD=1
+ export SWOOLE_BUILD_DIR=$(realpath .)
+ export PHP_VERSION=${{ matrix.php }}
+ ${SWOOLE_BUILD_DIR}/scripts/route.sh
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 38492c0600b..31243767f25 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,12 +1,12 @@
PROJECT(libswoole)
+cmake_minimum_required(VERSION 2.8.12)
ENABLE_LANGUAGE(ASM)
-set(SWOOLE_VERSION 5.1.2)
+set(SWOOLE_VERSION 6.0.0-dev)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
-cmake_minimum_required(VERSION 2.8)
file(READ ./config.h SWOOLE_CONFIG_FILE)
diff --git a/README.md b/README.md
index c5f0cb5e523..6c68311c15d 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,9 @@ docker run --rm phpswoole/swoole "php --ri swoole"
> For details on how to use it, see: [How to Use This Image](https://github.com/swoole/docker-swoole#how-to-use-this-image).
+## Documentation
+
+
### HTTP Service
```php
$http = new Swoole\Http\Server('127.0.0.1', 9501);
@@ -115,7 +118,6 @@ Co\run(function() {
+ __IDE Helper & API__:
+ __Twitter__:
+ __Discord__:
-+ __中文文档__:
+ __中文社区__:
## 💎 Awesome Swoole
diff --git a/config.m4 b/config.m4
index dd9cb803ff5..69e9511c9c0 100644
--- a/config.m4
+++ b/config.m4
@@ -111,6 +111,11 @@ PHP_ARG_ENABLE([thread-context],
[AS_HELP_STRING([--enable-thread-context],
[Use thread context])], [no], [no])
+PHP_ARG_ENABLE([swoole-thread],
+ [whether to enable swoole thread support],
+ [AS_HELP_STRING([--enable-swoole-thread],
+ [Enable swoole thread support])], [no], [no])
+
PHP_ARG_ENABLE([swoole-coro-time],
[whether to enable coroutine execution time ],
[AS_HELP_STRING([--enable-swoole-coro-time],
@@ -877,6 +882,10 @@ EOF
AC_DEFINE(SW_LOG_TRACE_OPEN, 1, [enable trace log])
fi
+ if test "$PHP_SWOOLE_THREAD" != "no"; then
+ AC_DEFINE(SW_THREAD, 1, [enable swoole thread support])
+ fi
+
if test "$PHP_SOCKETS" = "yes"; then
AC_MSG_CHECKING([for php_sockets.h])
@@ -1025,13 +1034,6 @@ EOF
thirdparty/swoole_http_parser.c \
thirdparty/multipart_parser.c"
- swoole_source_file="$swoole_source_file \
- thirdparty/hiredis/hiredis.c \
- thirdparty/hiredis/alloc.c \
- thirdparty/hiredis/net.c \
- thirdparty/hiredis/read.c \
- thirdparty/hiredis/sds.c"
-
if test "$PHP_NGHTTP2_DIR" = "no"; then
PHP_ADD_INCLUDE([$ext_srcdir/thirdparty])
swoole_source_file="$swoole_source_file \
@@ -1073,7 +1075,9 @@ EOF
thirdparty/php80/pdo_sqlite/sqlite_driver.c \
thirdparty/php80/pdo_sqlite/sqlite_statement.c \
thirdparty/php81/pdo_sqlite/sqlite_driver.c \
- thirdparty/php81/pdo_sqlite/sqlite_statement.c"
+ thirdparty/php81/pdo_sqlite/sqlite_statement.c \
+ thirdparty/php83/pdo_sqlite/sqlite_driver.c \
+ thirdparty/php83/pdo_sqlite/sqlite_statement.c"
fi
SW_ASM_DIR="thirdparty/boost/asm/"
@@ -1090,6 +1094,7 @@ EOF
[mips64*], [SW_CPU="mips64"],
[mips*], [SW_CPU="mips32"],
[riscv64*], [SW_CPU="riscv64"],
+ [loongarch64*], [SW_CPU="loongarch64"],
[
SW_USE_ASM_CONTEXT="no"
]
@@ -1151,6 +1156,12 @@ EOF
else
SW_USE_ASM_CONTEXT="no"
fi
+ elif test "$SW_CPU" = "loongarch64"; then
+ if test "$SW_OS" = "LINUX"; then
+ SW_CONTEXT_ASM_FILE="loongarch64_sysv_elf_gas.S"
+ else
+ SW_USE_ASM_CONTEXT="no"
+ fi
else
SW_USE_ASM_CONTEXT="no"
fi
@@ -1175,7 +1186,6 @@ EOF
PHP_ADD_INCLUDE([$ext_srcdir/include])
PHP_ADD_INCLUDE([$ext_srcdir/ext-src])
PHP_ADD_INCLUDE([$ext_srcdir/thirdparty])
- PHP_ADD_INCLUDE([$ext_srcdir/thirdparty/hiredis])
AC_MSG_CHECKING([swoole coverage])
if test "$PHP_SWOOLE_COVERAGE" != "no"; then
@@ -1190,8 +1200,7 @@ EOF
include/*.h \
stubs/*.h \
thirdparty/*.h \
- thirdparty/nghttp2/*.h \
- thirdparty/hiredis/*.h])
+ thirdparty/nghttp2/*.h])
PHP_REQUIRE_CXX()
@@ -1220,7 +1229,6 @@ EOF
PHP_ADD_BUILD_DIR($ext_builddir/src/wrapper)
PHP_ADD_BUILD_DIR($ext_builddir/thirdparty/boost)
PHP_ADD_BUILD_DIR($ext_builddir/thirdparty/boost/asm)
- PHP_ADD_BUILD_DIR($ext_builddir/thirdparty/hiredis)
PHP_ADD_BUILD_DIR($ext_builddir/thirdparty/php/sockets)
PHP_ADD_BUILD_DIR($ext_builddir/thirdparty/php/standard)
PHP_ADD_BUILD_DIR($ext_builddir/thirdparty/php/curl)
diff --git a/core-tests/CMakeLists.txt b/core-tests/CMakeLists.txt
index a9d66ebf37c..8f28da5bb47 100755
--- a/core-tests/CMakeLists.txt
+++ b/core-tests/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8.1)
+cmake_minimum_required(VERSION 2.8.12)
project(core_tests)
@@ -10,14 +10,14 @@ file(GLOB_RECURSE SOURCE_FILES FOLLOW_SYMLINKS src/*.cpp deps/llhttp/src/*.c)
add_definitions(-DHAVE_CONFIG_H)
-set(core_tests_includes ./include/ ../thirdparty ../thirdparty/hiredis ./deps/llhttp/include)
+set(core_tests_includes ./include/ ../thirdparty ../thirdparty/hiredis ./deps/llhttp/include /usr/local/include)
set(core_tests_libraries)
set(core_tests_link_directories /usr/local/lib)
-list(APPEND core_tests_libraries pthread)
+list(APPEND core_tests_libraries pthread gtest gtest_main)
# find GTest
-find_package(GTest)
+find_package(GTest REQUIRED)
if (!${GTEST_FOUND})
message(FATAL_ERROR "Not found GTest")
endif()
diff --git a/core-tests/src/os/async.cpp b/core-tests/src/os/async.cpp
index b34f5ef0052..8dad920991e 100644
--- a/core-tests/src/os/async.cpp
+++ b/core-tests/src/os/async.cpp
@@ -78,10 +78,16 @@ TEST(async, schedule) {
count--;
if (count == 0) {
swoole_timer_del(timer);
- ASSERT_EQ(SwooleTG.async_threads->get_worker_num(), 128);
+ ASSERT_GT(SwooleTG.async_threads->get_worker_num(), 16);
ASSERT_GT(SwooleTG.async_threads->get_queue_size(), 100);
ASSERT_GT(SwooleTG.async_threads->get_task_num(), 100);
break;
+ } else if (count == N - 1) {
+ ASSERT_EQ(SwooleTG.async_threads->get_worker_num(), 4);
+ ASSERT_EQ(SwooleTG.async_threads->get_queue_size(), 1);
+ ASSERT_EQ(SwooleTG.async_threads->get_task_num(), 1);
+ } else if (count < N / 2) {
+ ASSERT_GT(SwooleTG.async_threads->get_worker_num(), 4);
}
}
});
diff --git a/core-tests/src/server/server.cpp b/core-tests/src/server/server.cpp
index c66e88a64aa..0b2f5574787 100644
--- a/core-tests/src/server/server.cpp
+++ b/core-tests/src/server/server.cpp
@@ -678,7 +678,7 @@ TEST(server, task_worker4) {
serv->gs->task_workers.dispatch(&buf, &_dst_worker_id);
sleep(1);
- EventData *task_result = &(serv->task_result[SwooleG.process_id]);
+ EventData *task_result = &(serv->task_result[swoole_get_process_id()]);
sw_memset_zero(task_result, sizeof(*task_result));
memset(&buf.info, 0, sizeof(buf.info));
buf.info.len = strlen(packet);
diff --git a/examples/thread/aio.php b/examples/thread/aio.php
new file mode 100644
index 00000000000..bdb8492ad8c
--- /dev/null
+++ b/examples/thread/aio.php
@@ -0,0 +1,42 @@
+join();
+ }
+ var_dump($atomic->get());
+ sleep(2);
+
+ Co\run(function () use($atomic) {
+ $n = 1024;
+ while ($n--) {
+ $atomic->add();
+ $rs = \Swoole\Coroutine\System::readFile(__FILE__);
+ var_dump(strlen($rs));
+ }
+ });
+ var_dump($atomic->get());
+} else {
+ $atomic = $args[1];
+ Co\run(function () use($atomic) {
+ $n = 1024;
+ while ($n--) {
+ $atomic->add();
+ $rs = \Swoole\Coroutine\System::readFile(__FILE__);
+ var_dump(strlen($rs));
+ }
+ });
+}
diff --git a/examples/thread/argv.php b/examples/thread/argv.php
new file mode 100644
index 00000000000..b489c93a18b
--- /dev/null
+++ b/examples/thread/argv.php
@@ -0,0 +1,14 @@
+join();
+} else {
+ var_dump($args[0], $args[1], $args[2]);
+ sleep(1);
+}
diff --git a/examples/thread/array.php b/examples/thread/array.php
new file mode 100644
index 00000000000..1df20fb66c7
--- /dev/null
+++ b/examples/thread/array.php
@@ -0,0 +1,20 @@
+join();
+ }
+ var_dump($a1->get(), $a2->get());
+} else {
+ $a1 = $args[1];
+ $a2 = $args[2];
+
+ $a1->add(3);
+ $a2->add(7);
+}
diff --git a/examples/thread/benchmark.php b/examples/thread/benchmark.php
new file mode 100644
index 00000000000..5a52e6df5a5
--- /dev/null
+++ b/examples/thread/benchmark.php
@@ -0,0 +1,21 @@
+id);
+//var_dump($t2->id);
+echo Swoole\Thread::getId() . "\t" . 'gmap[uuid]' . "\t" . $map['uuid'] . "\n";
+
+try {
+ var_dump($list[999]);
+} catch (Swoole\Exception $e) {
+ assert(str_contains($e->getMessage(), 'out of range'));
+}
+
+try {
+ unset($list[0]);
+} catch (Swoole\Exception $e) {
+ assert(str_contains($e->getMessage(), 'unsupported'));
+}
+
+$t1->join();
+$t2->join();
+
+
diff --git a/examples/thread/lock.php b/examples/thread/lock.php
new file mode 100644
index 00000000000..7e8a1a6774e
--- /dev/null
+++ b/examples/thread/lock.php
@@ -0,0 +1,19 @@
+lock();
+ $thread = Thread::exec(__FILE__, $lock);
+ $lock->lock();
+ echo "main thread\n";
+ $thread->join();
+} else {
+ $lock = $args[0];
+ sleep(1);
+ $lock->unlock();
+}
diff --git a/examples/thread/mt.php b/examples/thread/mt.php
new file mode 100644
index 00000000000..eb63d199e7d
--- /dev/null
+++ b/examples/thread/mt.php
@@ -0,0 +1,27 @@
+keys());
+
+$list[] = uniqid('swoole');
+$list[count($list)] = uniqid('php');
+
+var_dump($args);
+
+echo Swoole\Thread::getId() . "\t" . 'glist[0]' . "\t" . $list[0] . "\n";
+var_dump(count($list));
+
+//if ($args[0] == 'thread-2') {
+// $t3 = Swoole\Thread::exec('mt.php', 'thread-3', PHP_OS);
+// $t3->join();
+//}
+
+//sleep(5);
+//echo "end\n";
diff --git a/examples/thread/pipe.php b/examples/thread/pipe.php
new file mode 100644
index 00000000000..94091a838bc
--- /dev/null
+++ b/examples/thread/pipe.php
@@ -0,0 +1,20 @@
+recv(8192), PHP_EOL;
+ $thread->join();
+ });
+} else {
+ $sockets = $args[0];
+ Co\run(function () use ($sockets) {
+ sleep(1);
+ $sockets[1]->send(uniqid());
+ });
+}
diff --git a/examples/thread/run_test.php b/examples/thread/run_test.php
new file mode 100644
index 00000000000..5ff3f9713d5
--- /dev/null
+++ b/examples/thread/run_test.php
@@ -0,0 +1,16 @@
+join();
+}
+
diff --git a/examples/thread/server.php b/examples/thread/server.php
new file mode 100644
index 00000000000..620bd49ba1a
--- /dev/null
+++ b/examples/thread/server.php
@@ -0,0 +1,25 @@
+join();
+ }
+} else {
+ $http = new Swoole\Http\Server("0.0.0.0", 9503);
+ $http->on('request', function ($req, Swoole\Http\Response $resp) {
+ $resp->end('hello world');
+ });
+ $http->start();
+}
diff --git a/examples/thread/signal.php b/examples/thread/signal.php
new file mode 100644
index 00000000000..11a3c1cb0bd
--- /dev/null
+++ b/examples/thread/signal.php
@@ -0,0 +1,36 @@
+send('exit');
+ }
+ Co\go(function () use ($parent_pipe, $thread) {
+ // 从管道中读取子线程退出的信息
+ echo $parent_pipe->recv(8192), PHP_EOL;
+ // 回收子线程
+ $thread->join();
+ });
+ });
+} else {
+ echo "child thread\n";
+ $sockets = $args[0];
+ $child_pipe = $sockets[0];
+ Co\run(function () use ($child_pipe) {
+ // 收到父线程的指令,开始退出
+ echo $child_pipe->recv(8192), PHP_EOL;
+ // 通知父线程已退出
+ $child_pipe->send('child exit');
+ });
+}
diff --git a/examples/thread/test.php b/examples/thread/test.php
new file mode 100644
index 00000000000..3c4b8bc1a20
--- /dev/null
+++ b/examples/thread/test.php
@@ -0,0 +1,17 @@
+uuid = uniqid();
+$map['obj'] = $o;
+
+var_dump($map['obj']);
+
+$s = serialize($map);
+var_dump(unserialize($s));
+
diff --git a/examples/thread/thread_pool.php b/examples/thread/thread_pool.php
new file mode 100644
index 00000000000..5bd876d09fa
--- /dev/null
+++ b/examples/thread/thread_pool.php
@@ -0,0 +1,37 @@
+push(base64_encode(random_bytes(16)), Queue::NOTIFY_ONE);
+ usleep(random_int(10000, 100000));
+ }
+ $n = 4;
+ while ($n--) {
+ $queue->push('', Queue::NOTIFY_ONE);
+ }
+ for ($i = 0; $i < $c; $i++) {
+ $threads[$i]->join();
+ }
+ var_dump($queue->count());
+} else {
+ $queue = $args[1];
+ while (1) {
+ $job = $queue->pop(-1);
+ if (!$job) {
+ break;
+ }
+ var_dump($job);
+ }
+}
diff --git a/examples/thread/thread_server.php b/examples/thread/thread_server.php
new file mode 100644
index 00000000000..bfd00fa37cf
--- /dev/null
+++ b/examples/thread/thread_server.php
@@ -0,0 +1,56 @@
+set([
+ 'worker_num' => 2,
+ 'task_worker_num' => 3,
+ 'enable_coroutine' => true,
+ 'hook_flags' => SWOOLE_HOOK_ALL,
+// 'trace_flags' => SWOOLE_TRACE_SERVER,
+// 'log_level' => SWOOLE_LOG_TRACE,
+ 'init_arguments' => function () use ($http) {
+ $map = new Swoole\Thread\Map;
+ return [$map];
+ }
+]);
+
+$http->on('Request', function ($req, $resp) use ($http) {
+// $resp->end("tid=" . \Swoole\Thread::getId() . ', fd=' . $req->fd);
+ if ($req->server['request_uri'] == '/task') {
+ $http->task(['code' => uniqid()]);
+ } elseif ($req->server['request_uri'] == '/msg') {
+ $dstWorkerId = random_int(0, 4);
+ if ($dstWorkerId != $http->getWorkerId()) {
+ $http->sendMessage('hello ' . base64_encode(random_bytes(16)), $dstWorkerId);
+ echo "[worker#" . $http->getWorkerId() . "]\tsend pipe message to " . $dstWorkerId . "\n";
+ }
+ }
+ $resp->end('hello world');
+});
+
+$http->on('pipeMessage', function ($http, $srcWorkerId, $msg) {
+ echo "[worker#" . $http->getWorkerId() . "]\treceived pipe message[$msg] from " . $srcWorkerId . "\n";
+});
+
+//$http->addProcess(new \Swoole\Process(function () {
+// echo "user process, id=" . \Swoole\Thread::getId();
+// sleep(2000);
+//}));
+
+$http->on('Task', function ($server, $taskId, $srcWorkerId, $data) {
+ var_dump($taskId, $srcWorkerId, $data);
+ return ['result' => uniqid()];
+});
+
+$http->on('Finish', function ($server, $taskId, $data) {
+ var_dump($taskId, $data);
+});
+
+$http->on('WorkerStart', function ($serv, $wid) {
+ var_dump(\Swoole\Thread::getArguments(), $wid);
+});
+
+$http->on('WorkerStop', function ($serv, $wid) {
+ var_dump('stop: T' . \Swoole\Thread::getId());
+});
+
+$http->start();
diff --git a/ext-src/php_swoole.cc b/ext-src/php_swoole.cc
index 17046b423cf..1f43867bdbf 100644
--- a/ext-src/php_swoole.cc
+++ b/ext-src/php_swoole.cc
@@ -188,7 +188,6 @@ PHP_INI_BEGIN()
/**
* enable swoole coroutine
*/
-STD_ZEND_INI_BOOLEAN("swoole.enable_coroutine", "On", PHP_INI_ALL, OnUpdateBool, enable_coroutine, zend_swoole_globals, swoole_globals)
STD_ZEND_INI_BOOLEAN("swoole.enable_library", "On", PHP_INI_ALL, OnUpdateBool, enable_library, zend_swoole_globals, swoole_globals)
STD_ZEND_INI_BOOLEAN("swoole.enable_fiber_mock", "Off", PHP_INI_ALL, OnUpdateBool, enable_fiber_mock, zend_swoole_globals, swoole_globals)
/**
@@ -211,13 +210,17 @@ PHP_INI_END()
// clang-format on
static void php_swoole_init_globals(zend_swoole_globals *swoole_globals) {
- swoole_globals->enable_coroutine = 1;
swoole_globals->enable_library = 1;
swoole_globals->enable_fiber_mock = 0;
swoole_globals->enable_preemptive_scheduler = 0;
swoole_globals->socket_buffer_size = SW_SOCKET_BUFFER_SIZE;
swoole_globals->display_errors = 1;
swoole_globals->use_shortname = 1;
+ swoole_globals->in_autoload = nullptr;
+ if (strcmp("cli", sapi_module.name) == 0 || strcmp("phpdbg", sapi_module.name) == 0 ||
+ strcmp("embed", sapi_module.name) == 0) {
+ swoole_globals->cli = 1;
+ }
}
void php_swoole_register_shutdown_function(const char *function) {
@@ -334,7 +337,7 @@ SW_API bool php_swoole_is_enable_coroutine() {
if (sw_server()) {
return sw_server()->is_enable_coroutine();
} else {
- return SWOOLE_G(enable_coroutine);
+ return SwooleG.enable_coroutine;
}
}
@@ -694,10 +697,6 @@ PHP_MINIT_FUNCTION(swoole) {
// init bug report message
bug_report_message_init();
- if (strcmp("cli", sapi_module.name) == 0 || strcmp("phpdbg", sapi_module.name) == 0 ||
- strcmp("embed", sapi_module.name) == 0) {
- SWOOLE_G(cli) = 1;
- }
SW_INIT_CLASS_ENTRY_EX2(
swoole_exception, "Swoole\\Exception", nullptr, nullptr, zend_ce_exception, zend_get_std_object_handlers());
@@ -726,8 +725,6 @@ PHP_MINIT_FUNCTION(swoole) {
php_swoole_client_coro_minit(module_number);
php_swoole_http_client_coro_minit(module_number);
php_swoole_http2_client_coro_minit(module_number);
- php_swoole_mysql_coro_minit(module_number);
- php_swoole_redis_coro_minit(module_number);
// server
php_swoole_server_minit(module_number);
php_swoole_server_port_minit(module_number);
@@ -739,20 +736,25 @@ PHP_MINIT_FUNCTION(swoole) {
php_swoole_redis_server_minit(module_number);
php_swoole_name_resolver_minit(module_number);
#ifdef SW_USE_PGSQL
- php_swoole_postgresql_coro_minit(module_number);
php_swoole_pgsql_minit(module_number);
#endif
#ifdef SW_USE_ODBC
php_swoole_odbc_minit(module_number);
#endif
-
#ifdef SW_USE_ORACLE
php_swoole_oracle_minit(module_number);
#endif
-
#ifdef SW_USE_SQLITE
php_swoole_sqlite_minit(module_number);
#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;
Socket::default_buffer_size = SWOOLE_G(socket_buffer_size);
@@ -826,6 +828,9 @@ PHP_MINFO_FUNCTION(swoole) {
#ifdef HAVE_KQUEUE
php_info_print_table_row(2, "kqueue", "enabled");
#endif
+#ifdef SW_THREAD
+ php_info_print_table_row(2, "thread", "enabled");
+#endif
#ifdef HAVE_SIGNALFD
php_info_print_table_row(2, "signalfd", "enabled");
#endif
@@ -894,7 +899,6 @@ PHP_MINFO_FUNCTION(swoole) {
#ifdef SW_USE_TCMALLOC
php_info_print_table_row(2, "tcmalloc", "enabled");
#endif
- php_info_print_table_row(2, "async_redis", "enabled");
#ifdef SW_USE_PGSQL
php_info_print_table_row(2, "coroutine_pgsql", "enabled");
#endif
@@ -1029,6 +1033,9 @@ PHP_RINIT_FUNCTION(swoole) {
#ifdef SW_USE_ORACLE
php_swoole_oracle_rinit();
#endif
+#ifdef SW_THREAD
+ php_swoole_thread_rinit();
+#endif
SWOOLE_G(req_status) = PHP_SWOOLE_RINIT_END;
@@ -1054,6 +1061,9 @@ PHP_RSHUTDOWN_FUNCTION(swoole) {
php_swoole_coroutine_scheduler_rshutdown();
php_swoole_runtime_rshutdown();
php_swoole_process_rshutdown();
+#ifdef SW_THREAD
+ php_swoole_thread_rshutdown();
+#endif
SwooleG.running = 0;
SWOOLE_G(req_status) = PHP_SWOOLE_RSHUTDOWN_END;
diff --git a/ext-src/php_swoole_coroutine.h b/ext-src/php_swoole_coroutine.h
index aebb5c94429..383aefef197 100644
--- a/ext-src/php_swoole_coroutine.h
+++ b/ext-src/php_swoole_coroutine.h
@@ -110,7 +110,7 @@ class PHPCoroutine {
bool enable_deadlock_check;
};
- static zend_array *options;
+ static SW_THREAD_LOCAL zend_array *options;
enum HookType {
HOOK_NONE = 0,
@@ -252,7 +252,7 @@ class PHPCoroutine {
}
static inline void init_main_context() {
- main_context.co = Coroutine::init_main_coroutine();
+ main_context.co = nullptr;
#ifdef SWOOLE_COROUTINE_MOCK_FIBER_CONTEXT
main_context.fiber_context = EG(main_fiber_context);
main_context.fiber_init_notified = true;
@@ -260,13 +260,17 @@ class PHPCoroutine {
save_context(&main_context);
}
+ static inline void free_main_context() {
+ main_context = {};
+ }
+
protected:
- static bool activated;
- static PHPContext main_context;
- static Config config;
+ static SW_THREAD_LOCAL bool activated;
+ static SW_THREAD_LOCAL PHPContext main_context;
+ static SW_THREAD_LOCAL Config config;
- static bool interrupt_thread_running;
- static std::thread interrupt_thread;
+ static SW_THREAD_LOCAL bool interrupt_thread_running;
+ static SW_THREAD_LOCAL std::thread interrupt_thread;
static void activate();
static void deactivate(void *ptr);
diff --git a/ext-src/php_swoole_cxx.h b/ext-src/php_swoole_cxx.h
index 68603c716a6..3cb912b49e7 100644
--- a/ext-src/php_swoole_cxx.h
+++ b/ext-src/php_swoole_cxx.h
@@ -145,6 +145,7 @@ SW_API php_stream *php_swoole_create_stream_from_socket(php_socket_t _fd,
int domain,
int type,
int protocol STREAMS_DC);
+SW_API php_stream *php_swoole_create_stream_from_pipe(int fd, const char *mode, const char *persistent_id STREAMS_DC);
SW_API php_stream_ops *php_swoole_get_ori_php_stream_stdio_ops();
SW_API void php_swoole_register_rshutdown_callback(swoole::Callback cb, void *private_data);
@@ -637,10 +638,42 @@ static inline void array_add(zval *arg, zval *zvalue) {
add_next_index_zval(arg, zvalue);
}
+/**
+ * return reference
+ */
+static inline zval *array_get(zval *arg, const char *key, size_t l_key) {
+ return zend_hash_str_find(Z_ARRVAL_P(arg), key, l_key);
+}
+
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, 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);
+ return property ? zval_get_long(property) : 0;
+}
+
+static inline zend_long object_get_long(zend_object *obj, const char *key, size_t l_key) {
+ static zval rv;
+ zval *property = zend_read_property(obj->ce, obj, key, l_key, 1, &rv);
+ return property ? zval_get_long(property) : 0;
+}
+
+static inline void object_set(zval *obj, const char *name, size_t l_name, zval *zvalue) {
+ zend_update_property(Z_OBJCE_P(obj), Z_OBJ_P(obj), name, l_name, zvalue);
+}
+
+static inline void object_set(zval *obj, const char *name, size_t l_name, const char *value) {
+ zend_update_property_string(Z_OBJCE_P(obj), Z_OBJ_P(obj), name, l_name, value);
+}
+
+static inline zval *object_get(zval *obj, const char *name, size_t l_name) {
+ static zval rv;
+ return zend_read_property(Z_OBJCE_P(obj), Z_OBJ_P(obj), name, l_name, 1, &rv);
+}
+
//-----------------------------------namespace end--------------------------------------------
} // namespace zend
diff --git a/ext-src/php_swoole_http_server.h b/ext-src/php_swoole_http_server.h
index 4d025788af4..22855ccfcbc 100644
--- a/ext-src/php_swoole_http_server.h
+++ b/ext-src/php_swoole_http_server.h
@@ -48,35 +48,35 @@ int swoole_http2_server_goaway(swoole::http::Context *ctx,
static inline void http_server_add_server_array(HashTable *ht, zend_string *key, const char *value) {
zval tmp;
ZVAL_STRING(&tmp, value);
- zend_hash_add(ht, key, &tmp);
+ zend_hash_add_new(ht, key, &tmp);
}
static inline void http_server_add_server_array(HashTable *ht, zend_string *key, const char *value, size_t length) {
zval tmp;
ZVAL_STRINGL(&tmp, value, length);
- zend_hash_add(ht, key, &tmp);
+ zend_hash_add_new(ht, key, &tmp);
}
static inline void http_server_add_server_array(HashTable *ht, zend_string *key, zend_long value) {
zval tmp;
ZVAL_LONG(&tmp, value);
- zend_hash_add(ht, key, &tmp);
+ zend_hash_add_new(ht, key, &tmp);
}
static inline void http_server_add_server_array(HashTable *ht, zend_string *key, double value) {
zval tmp;
ZVAL_DOUBLE(&tmp, value);
- zend_hash_add(ht, key, &tmp);
+ zend_hash_add_new(ht, key, &tmp);
}
static inline void http_server_add_server_array(HashTable *ht, zend_string *key, zend_string *value) {
zval tmp;
ZVAL_STR(&tmp, value);
- zend_hash_add(ht, key, &tmp);
+ zend_hash_add_new(ht, key, &tmp);
}
static inline void http_server_add_server_array(HashTable *ht, zend_string *key, zval *value) {
- zend_hash_add(ht, key, value);
+ zend_hash_add_new(ht, key, value);
}
static inline void http_server_set_object_fd_property(zend_object *object, zend_class_entry *ce, long fd) {
diff --git a/ext-src/php_swoole_library.h b/ext-src/php_swoole_library.h
index 6612eb89777..2cefd9c2947 100644
--- a/ext-src/php_swoole_library.h
+++ b/ext-src/php_swoole_library.h
@@ -14,7 +14,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: 3bc066dd5d5f3498f7bb2ef8c5a7408d0cd33149 */
+/* $Id: b1dfd92c6bcb71413e561d75fe860bfb3ca38434 */
#ifndef SWOOLE_LIBRARY_H
#define SWOOLE_LIBRARY_H
@@ -8425,178 +8425,180 @@ static const char* swoole_library_source_core_server_helper =
" public const STATS_TIMER_INTERVAL_TIME = 1000;\n"
"\n"
" public const GLOBAL_OPTIONS = [\n"
- " 'debug_mode' => true,\n"
- " 'trace_flags' => true,\n"
- " 'log_file' => true,\n"
- " 'log_level' => true,\n"
- " 'log_date_format' => true,\n"
- " 'log_date_with_microseconds' => true,\n"
- " 'log_rotation' => true,\n"
- " 'display_errors' => true,\n"
- " 'dns_server' => true,\n"
- " 'socket_dns_timeout' => true,\n"
- " 'socket_connect_timeout' => true,\n"
- " 'socket_write_timeout' => true,\n"
- " 'socket_send_timeout' => true,\n"
- " 'socket_read_timeout' => true,\n"
- " 'socket_recv_timeout' => true,\n"
- " 'socket_buffer_size' => true,\n"
- " 'socket_timeout' => true,\n"
- " 'http2_header_table_size' => true,\n"
- " 'http2_enable_push' => true,\n"
+ " 'debug_mode' => true,\n"
+ " 'trace_flags' => true,\n"
+ " 'log_file' => true,\n"
+ " 'log_level' => true,\n"
+ " 'log_date_format' => true,\n"
+ " 'log_date_with_microseconds' => true,\n"
+ " 'log_rotation' => true,\n"
+ " 'display_errors' => true,\n"
+ " 'dns_server' => true,\n"
+ " 'socket_dns_timeout' => true,\n"
+ " 'socket_connect_timeout' => true,\n"
+ " 'socket_write_timeout' => true,\n"
+ " 'socket_send_timeout' => true,\n"
+ " 'socket_read_timeout' => true,\n"
+ " 'socket_recv_timeout' => true,\n"
+ " 'socket_buffer_size' => true,\n"
+ " 'socket_timeout' => true,\n"
+ " 'http2_header_table_size' => true,\n"
+ " 'http2_enable_push' => true,\n"
" 'http2_max_concurrent_streams' => true,\n"
- " 'http2_init_window_size' => true,\n"
- " 'http2_max_frame_size' => true,\n"
- " 'http2_max_header_list_size' => true,\n"
+ " 'http2_init_window_size' => true,\n"
+ " 'http2_max_frame_size' => true,\n"
+ " 'http2_max_header_list_size' => true,\n"
" ];\n"
"\n"
" public const SERVER_OPTIONS = [\n"
- " 'chroot' => true,\n"
- " 'user' => true,\n"
- " 'group' => true,\n"
- " 'daemonize' => true,\n"
- " 'pid_file' => true,\n"
- " 'reactor_num' => true,\n"
- " 'single_thread' => true,\n"
- " 'worker_num' => true,\n"
- " 'max_wait_time' => true,\n"
- " 'max_queued_bytes' => true,\n"
- " 'max_concurrency' => true,\n"
- " 'worker_max_concurrency' => true,\n"
- " 'enable_coroutine' => true,\n"
- " 'send_timeout' => true,\n"
- " 'dispatch_mode' => true,\n"
- " 'send_yield' => true,\n"
- " 'dispatch_func' => true,\n"
- " 'discard_timeout_request' => true,\n"
- " 'enable_unsafe_event' => true,\n"
- " 'enable_delay_receive' => true,\n"
- " 'enable_reuse_port' => true,\n"
- " 'task_use_object' => true,\n"
- " 'task_object' => true,\n"
- " 'event_object' => true,\n"
- " 'task_enable_coroutine' => true,\n"
- " 'task_worker_num' => true,\n"
- " 'task_ipc_mode' => true,\n"
- " 'task_tmpdir' => true,\n"
- " 'task_max_request' => true,\n"
- " 'task_max_request_grace' => true,\n"
- " 'max_connection' => true,\n"
- " 'max_conn' => true,\n"
- " 'start_session_id' => true,\n"
- " 'heartbeat_check_interval' => true,\n"
- " 'heartbeat_idle_time' => true,\n"
- " 'max_request' => true,\n"
- " 'max_request_grace' => true,\n"
- " 'reload_async' => true,\n"
- " 'open_cpu_affinity' => true,\n"
- " 'cpu_affinity_ignore' => true,\n"
- " 'http_parse_cookie' => true,\n"
- " 'http_parse_post' => true,\n"
- " 'http_parse_files' => true,\n"
- " 'http_compression' => true,\n"
- " 'http_compression_level' => true,\n"
- " 'compression_level' => true,\n"
- " 'http_gzip_level' => true,\n"
+ " 'chroot' => true,\n"
+ " 'user' => true,\n"
+ " 'group' => true,\n"
+ " 'daemonize' => true,\n"
+ " 'pid_file' => true,\n"
+ " 'reactor_num' => true,\n"
+ " 'single_thread' => true,\n"
+ " 'worker_num' => true,\n"
+ " 'max_wait_time' => true,\n"
+ " 'max_queued_bytes' => true,\n"
+ " 'max_concurrency' => true,\n"
+ " 'worker_max_concurrency' => true,\n"
+ " 'enable_coroutine' => true,\n"
+ " 'send_timeout' => true,\n"
+ " 'dispatch_mode' => true,\n"
+ " 'send_yield' => true,\n"
+ " 'dispatch_func' => true,\n"
+ " 'discard_timeout_request' => true,\n"
+ " 'enable_unsafe_event' => true,\n"
+ " 'enable_delay_receive' => true,\n"
+ " 'enable_reuse_port' => true,\n"
+ " 'task_use_object' => true,\n"
+ " 'task_object' => true,\n"
+ " 'event_object' => true,\n"
+ " 'task_enable_coroutine' => true,\n"
+ " 'task_worker_num' => true,\n"
+ " 'task_ipc_mode' => true,\n"
+ " 'task_tmpdir' => true,\n"
+ " 'task_max_request' => true,\n"
+ " 'task_max_request_grace' => true,\n"
+ " 'max_connection' => true,\n"
+ " 'max_conn' => true,\n"
+ " 'start_session_id' => true,\n"
+ " 'heartbeat_check_interval' => true,\n"
+ " 'heartbeat_idle_time' => true,\n"
+ " 'max_request' => true,\n"
+ " 'max_request_grace' => true,\n"
+ " 'reload_async' => true,\n"
+ " 'open_cpu_affinity' => true,\n"
+ " 'cpu_affinity_ignore' => true,\n"
+ " 'http_parse_cookie' => true,\n"
+ " 'http_parse_post' => true,\n"
+ " 'http_parse_files' => true,\n"
+ " 'http_compression' => true,\n"
+ " 'http_compression_level' => true,\n"
+ " 'compression_level' => true,\n"
+ " 'http_gzip_level' => true,\n"
" 'http_compression_min_length' => true,\n"
- " 'compression_min_length' => true,\n"
- " 'websocket_compression' => true,\n"
- " 'upload_tmp_dir' => true,\n"
- " 'upload_max_filesize' => true,\n"
- " 'enable_static_handler' => true,\n"
- " 'document_root' => true,\n"
- " 'http_autoindex' => true,\n"
- " 'http_index_files' => true,\n"
- " 'http_compression_types' => true,\n"
- " 'compression_types' => true,\n"
- " 'static_handler_locations' => true,\n"
- " 'input_buffer_size' => true,\n"
- " 'buffer_input_size' => true,\n"
- " 'output_buffer_size' => true,\n"
- " 'buffer_output_size' => true,\n"
- " 'message_queue_key' => true,\n"
+ " 'compression_min_length' => true,\n"
+ " 'websocket_compression' => true,\n"
+ " 'upload_tmp_dir' => true,\n"
+ " 'upload_max_filesize' => true,\n"
+ " 'enable_static_handler' => true,\n"
+ " 'document_root' => true,\n"
+ " 'http_autoindex' => true,\n"
+ " 'http_index_files' => true,\n"
+ " 'http_compression_types' => true,\n"
+ " 'compression_types' => true,\n"
+ " 'static_handler_locations' => true,\n"
+ " 'input_buffer_size' => true,\n"
+ " 'buffer_input_size' => true,\n"
+ " 'output_buffer_size' => true,\n"
+ " 'buffer_output_size' => true,\n"
+ " 'message_queue_key' => true,\n"
+ " 'bootstrap' => true,\n"
+ " 'init_arguments' => true,\n"
" ];\n"
"\n"
" public const PORT_OPTIONS = [\n"
- " 'ssl_cert_file' => true,\n"
- " 'ssl_key_file' => true,\n"
- " 'backlog' => true,\n"
- " 'socket_buffer_size' => true,\n"
+ " 'ssl_cert_file' => true,\n"
+ " 'ssl_key_file' => true,\n"
+ " 'backlog' => true,\n"
+ " 'socket_buffer_size' => true,\n"
" 'kernel_socket_recv_buffer_size' => true,\n"
" 'kernel_socket_send_buffer_size' => true,\n"
- " 'heartbeat_idle_time' => true,\n"
- " 'buffer_high_watermark' => true,\n"
- " 'buffer_low_watermark' => true,\n"
- " 'open_tcp_nodelay' => true,\n"
- " 'tcp_defer_accept' => true,\n"
- " 'open_tcp_keepalive' => true,\n"
- " 'open_eof_check' => true,\n"
- " 'open_eof_split' => true,\n"
- " 'package_eof' => true,\n"
- " 'open_http_protocol' => true,\n"
- " 'open_websocket_protocol' => true,\n"
- " 'websocket_subprotocol' => true,\n"
- " 'open_websocket_close_frame' => true,\n"
- " 'open_websocket_ping_frame' => true,\n"
- " 'open_websocket_pong_frame' => true,\n"
- " 'open_http2_protocol' => true,\n"
- " 'open_mqtt_protocol' => true,\n"
- " 'open_redis_protocol' => true,\n"
- " 'max_idle_time' => true,\n"
- " 'tcp_keepidle' => true,\n"
- " 'tcp_keepinterval' => true,\n"
- " 'tcp_keepcount' => true,\n"
- " 'tcp_user_timeout' => true,\n"
- " 'tcp_fastopen' => true,\n"
- " 'open_length_check' => true,\n"
- " 'package_length_type' => true,\n"
- " 'package_length_offset' => true,\n"
- " 'package_body_offset' => true,\n"
- " 'package_body_start' => true,\n"
- " 'package_length_func' => true,\n"
- " 'package_max_length' => true,\n"
- " 'ssl_compress' => true,\n"
- " 'ssl_protocols' => true,\n"
- " 'ssl_verify_peer' => true,\n"
- " 'ssl_allow_self_signed' => true,\n"
- " 'ssl_client_cert_file' => true,\n"
- " 'ssl_verify_depth' => true,\n"
- " 'ssl_prefer_server_ciphers' => true,\n"
- " 'ssl_ciphers' => true,\n"
- " 'ssl_ecdh_curve' => true,\n"
- " 'ssl_dhparam' => true,\n"
- " 'ssl_sni_certs' => true,\n"
+ " 'heartbeat_idle_time' => true,\n"
+ " 'buffer_high_watermark' => true,\n"
+ " 'buffer_low_watermark' => true,\n"
+ " 'open_tcp_nodelay' => true,\n"
+ " 'tcp_defer_accept' => true,\n"
+ " 'open_tcp_keepalive' => true,\n"
+ " 'open_eof_check' => true,\n"
+ " 'open_eof_split' => true,\n"
+ " 'package_eof' => true,\n"
+ " 'open_http_protocol' => true,\n"
+ " 'open_websocket_protocol' => true,\n"
+ " 'websocket_subprotocol' => true,\n"
+ " 'open_websocket_close_frame' => true,\n"
+ " 'open_websocket_ping_frame' => true,\n"
+ " 'open_websocket_pong_frame' => true,\n"
+ " 'open_http2_protocol' => true,\n"
+ " 'open_mqtt_protocol' => true,\n"
+ " 'open_redis_protocol' => true,\n"
+ " 'max_idle_time' => true,\n"
+ " 'tcp_keepidle' => true,\n"
+ " 'tcp_keepinterval' => true,\n"
+ " 'tcp_keepcount' => true,\n"
+ " 'tcp_user_timeout' => true,\n"
+ " 'tcp_fastopen' => true,\n"
+ " 'open_length_check' => true,\n"
+ " 'package_length_type' => true,\n"
+ " 'package_length_offset' => true,\n"
+ " 'package_body_offset' => true,\n"
+ " 'package_body_start' => true,\n"
+ " 'package_length_func' => true,\n"
+ " 'package_max_length' => true,\n"
+ " 'ssl_compress' => true,\n"
+ " 'ssl_protocols' => true,\n"
+ " 'ssl_verify_peer' => true,\n"
+ " 'ssl_allow_self_signed' => true,\n"
+ " 'ssl_client_cert_file' => true,\n"
+ " 'ssl_verify_depth' => true,\n"
+ " 'ssl_prefer_server_ciphers' => true,\n"
+ " 'ssl_ciphers' => true,\n"
+ " 'ssl_ecdh_curve' => true,\n"
+ " 'ssl_dhparam' => true,\n"
+ " 'ssl_sni_certs' => true,\n"
" ];\n"
"\n"
" public const AIO_OPTIONS = [\n"
- " 'aio_core_worker_num' => true,\n"
- " 'aio_worker_num' => true,\n"
- " 'aio_max_wait_time' => true,\n"
- " 'aio_max_idle_time' => true,\n"
- " 'enable_signalfd' => true,\n"
- " 'wait_signal' => true,\n"
+ " 'aio_core_worker_num' => true,\n"
+ " 'aio_worker_num' => true,\n"
+ " 'aio_max_wait_time' => true,\n"
+ " 'aio_max_idle_time' => true,\n"
+ " 'iouring_entries' => true,\n"
+ " 'enable_signalfd' => true,\n"
+ " 'wait_signal' => true,\n"
" 'dns_cache_refresh_time' => true,\n"
- " 'thread_num' => true,\n"
- " 'min_thread_num' => true,\n"
- " 'max_thread_num' => true,\n"
- " 'socket_dontwait' => true,\n"
- " 'dns_lookup_random' => true,\n"
- " 'use_async_resolver' => true,\n"
- " 'enable_coroutine' => true,\n"
+ " 'thread_num' => true,\n"
+ " 'min_thread_num' => true,\n"
+ " 'max_thread_num' => true,\n"
+ " 'socket_dontwait' => true,\n"
+ " 'dns_lookup_random' => true,\n"
+ " 'use_async_resolver' => true,\n"
+ " 'enable_coroutine' => true,\n"
" ];\n"
"\n"
" public const COROUTINE_OPTIONS = [\n"
- " 'max_coro_num' => true,\n"
- " 'max_coroutine' => true,\n"
- " 'enable_deadlock_check' => true,\n"
- " 'hook_flags' => true,\n"
+ " 'max_coro_num' => true,\n"
+ " 'max_coroutine' => true,\n"
+ " 'enable_deadlock_check' => true,\n"
+ " 'hook_flags' => true,\n"
" 'enable_preemptive_scheduler' => true,\n"
- " 'c_stack_size' => true,\n"
- " 'stack_size' => true,\n"
- " 'name_resolver' => true,\n"
- " 'dns_cache_expire' => true,\n"
- " 'dns_cache_capacity' => true,\n"
- " 'max_concurrency' => true,\n"
+ " 'c_stack_size' => true,\n"
+ " 'stack_size' => true,\n"
+ " 'name_resolver' => true,\n"
+ " 'dns_cache_expire' => true,\n"
+ " 'dns_cache_capacity' => true,\n"
" ];\n"
"\n"
" public const HELPER_OPTIONS = [\n"
diff --git a/ext-src/php_swoole_mysql_proto.h b/ext-src/php_swoole_mysql_proto.h
deleted file mode 100644
index 62b7b19a6ed..00000000000
--- a/ext-src/php_swoole_mysql_proto.h
+++ /dev/null
@@ -1,1017 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | 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@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: Twosee |
- | Author: Tianfeng Han |
- +----------------------------------------------------------------------+
-*/
-
-#pragma once
-
-#include "php_swoole_cxx.h"
-#include "swoole_util.h"
-
-#ifdef SW_USE_OPENSSL
-#ifndef OPENSSL_NO_RSA
-#define SW_MYSQL_RSA_SUPPORT
-#include
-#include
-#include
-#endif
-#endif
-
-enum sw_mysql_command
-{
- SW_MYSQL_COM_NULL = -1,
- SW_MYSQL_COM_SLEEP = 0,
- SW_MYSQL_COM_QUIT,
- SW_MYSQL_COM_INIT_DB,
- SW_MYSQL_COM_QUERY = 3,
- SW_MYSQL_COM_FIELD_LIST,
- SW_MYSQL_COM_CREATE_DB,
- SW_MYSQL_COM_DROP_DB,
- SW_MYSQL_COM_REFRESH,
- SW_MYSQL_COM_SHUTDOWN,
- SW_MYSQL_COM_STATISTICS,
- SW_MYSQL_COM_PROCESS_INFO,
- SW_MYSQL_COM_CONNECT,
- SW_MYSQL_COM_PROCESS_KILL,
- SW_MYSQL_COM_DEBUG,
- SW_MYSQL_COM_PING,
- SW_MYSQL_COM_TIME,
- SW_MYSQL_COM_DELAYED_INSERT,
- SW_MYSQL_COM_CHANGE_USER,
- SW_MYSQL_COM_BINLOG_DUMP,
- SW_MYSQL_COM_TABLE_DUMP,
- SW_MYSQL_COM_CONNECT_OUT,
- SW_MYSQL_COM_REGISTER_SLAVE,
- SW_MYSQL_COM_STMT_PREPARE,
- SW_MYSQL_COM_STMT_EXECUTE,
- SW_MYSQL_COM_STMT_SEND_LONG_DATA,
- SW_MYSQL_COM_STMT_CLOSE,
- SW_MYSQL_COM_STMT_RESET,
- SW_MYSQL_COM_SET_OPTION,
- SW_MYSQL_COM_STMT_FETCH,
- SW_MYSQL_COM_DAEMON,
- SW_MYSQL_COM_END
-};
-
-enum sw_mysql_handshake_state
-{
- SW_MYSQL_HANDSHAKE_WAIT_REQUEST,
- SW_MYSQL_HANDSHAKE_WAIT_SWITCH,
- SW_MYSQL_HANDSHAKE_WAIT_SIGNATURE,
- SW_MYSQL_HANDSHAKE_WAIT_RSA,
- SW_MYSQL_HANDSHAKE_WAIT_RESULT,
- SW_MYSQL_HANDSHAKE_COMPLETED,
-};
-
-#define SW_MYSQL_AUTH_SIGNATRUE_PACKET_LENGTH 2
-
-enum sw_mysql_auth_signature
-{
- SW_MYSQL_AUTH_SIGNATURE_ERROR = 0x00, // get signature failed
- SW_MYSQL_AUTH_SIGNATURE = 0x01,
- SW_MYSQL_AUTH_SIGNATURE_RSA_PREPARED = 0x02,
- SW_MYSQL_AUTH_SIGNATURE_SUCCESS = 0x03,
- SW_MYSQL_AUTH_SIGNATURE_FULL_AUTH_REQUIRED = 0x04, // rsa required
-};
-
-enum sw_mysql_command_flag
-{
- SW_MYSQL_COMMAND_FLAG_QUERY = 1 << 4,
- SW_MYSQL_COMMAND_FLAG_EXECUTE = 1 << 5,
-};
-
-enum sw_mysql_state
-{
- SW_MYSQL_STATE_CLOSED = 0,
- SW_MYSQL_STATE_IDLE = 1,
- SW_MYSQL_STATE_QUERY = 2 | SW_MYSQL_COMMAND_FLAG_QUERY,
- SW_MYSQL_STATE_QUERY_FETCH = 3 | SW_MYSQL_COMMAND_FLAG_QUERY,
- SW_MYSQL_STATE_QUERY_MORE_RESULTS = 4 | SW_MYSQL_COMMAND_FLAG_QUERY,
- SW_MYSQL_STATE_PREPARE = 5 | SW_MYSQL_COMMAND_FLAG_QUERY,
- SW_MYSQL_STATE_EXECUTE = 6 | SW_MYSQL_COMMAND_FLAG_EXECUTE,
- SW_MYSQL_STATE_EXECUTE_FETCH = 7 | SW_MYSQL_COMMAND_FLAG_EXECUTE,
- SW_MYSQL_STATE_EXECUTE_MORE_RESULTS = 8 | SW_MYSQL_COMMAND_FLAG_EXECUTE,
-};
-
-enum sw_mysql_packet_types
-{
- SW_MYSQL_PACKET_OK = 0x0,
- SW_MYSQL_PACKET_AUTH_SIGNATURE_REQUEST = 0x01,
-
- /* not defined in protocol */
- SW_MYSQL_PACKET_RAW_DATA,
- SW_MYSQL_PACKET_GREETING,
- SW_MYSQL_PACKET_LOGIN,
- SW_MYSQL_PACKET_AUTH_SWITCH_RESPONSE,
- SW_MYSQL_PACKET_AUTH_SIGNATURE_RESPONSE,
- SW_MYSQL_PACKET_LCB, // length coded binary
- SW_MYSQL_PACKET_FIELD,
- SW_MYSQL_PACKET_ROW_DATA,
- SW_MYSQL_PACKET_PREPARE_STATEMENT,
- /* ======================= */
-
- SW_MYSQL_PACKET_NULL = 0xfb,
- SW_MYSQL_PACKET_EOF = 0xfe,
- SW_MYSQL_PACKET_AUTH_SWITCH_REQUEST = 0xfe,
- SW_MYSQL_PACKET_ERR = 0xff
-};
-
-enum sw_mysql_field_types
-{
- SW_MYSQL_TYPE_DECIMAL,
- SW_MYSQL_TYPE_TINY,
- SW_MYSQL_TYPE_SHORT,
- SW_MYSQL_TYPE_LONG,
- SW_MYSQL_TYPE_FLOAT,
- SW_MYSQL_TYPE_DOUBLE,
- SW_MYSQL_TYPE_NULL,
- SW_MYSQL_TYPE_TIMESTAMP,
- SW_MYSQL_TYPE_LONGLONG,
- SW_MYSQL_TYPE_INT24,
- SW_MYSQL_TYPE_DATE,
- SW_MYSQL_TYPE_TIME,
- SW_MYSQL_TYPE_DATETIME,
- SW_MYSQL_TYPE_YEAR,
- SW_MYSQL_TYPE_NEWDATE,
- SW_MYSQL_TYPE_VARCHAR,
- SW_MYSQL_TYPE_BIT,
- SW_MYSQL_TYPE_JSON = 245,
- SW_MYSQL_TYPE_NEWDECIMAL,
- SW_MYSQL_TYPE_ENUM,
- SW_MYSQL_TYPE_SET,
- SW_MYSQL_TYPE_TINY_BLOB,
- SW_MYSQL_TYPE_MEDIUM_BLOB,
- SW_MYSQL_TYPE_LONG_BLOB,
- SW_MYSQL_TYPE_BLOB,
- SW_MYSQL_TYPE_VAR_STRING,
- SW_MYSQL_TYPE_STRING,
- SW_MYSQL_TYPE_GEOMETRY
-};
-
-// ref: https://dev.mysql.com/doc/dev/mysql-server/8.0.0/group__group__cs__capabilities__flags.html
-// use regex: "\#define[ ]+(CLIENT_[A-Z_\d]+)[ ]+(\(?[\dA-Z <]+\)?)\n[ ]+?[ ]+([\s\S ]+?\.) More\.\.\.\n?"
-// to "SW_MYSQL_$1 = $2, /* $3 */"
-enum sw_mysql_client_capability_flags
-{
- SW_MYSQL_CLIENT_LONG_PASSWORD = 1, /* Use the improved version of Old Password Authentication. */
- SW_MYSQL_CLIENT_FOUND_ROWS = 2, /* Send found rows instead of affected rows in EOF_Packet. */
- SW_MYSQL_CLIENT_LONG_FLAG = 4, /* Get all column flags. */
- SW_MYSQL_CLIENT_CONNECT_WITH_DB = 8, /* Database (schema) name can be specified on connect in Handshake Response Packet. */
- SW_MYSQL_CLIENT_NO_SCHEMA = 16, /* Don't allow database.table.column. */
- SW_MYSQL_CLIENT_COMPRESS = 32, /* Compression protocol supported. */
- SW_MYSQL_CLIENT_ODBC = 64, /* Special handling of ODBC behavior. */
- SW_MYSQL_CLIENT_LOCAL_FILES = 128, /* Can use LOAD DATA LOCAL. */
- SW_MYSQL_CLIENT_IGNORE_SPACE = 256, /* Ignore spaces before '('. */
- SW_MYSQL_CLIENT_PROTOCOL_41 = 512, /* New 4.1 protocol. */
- SW_MYSQL_CLIENT_INTERACTIVE = 1024, /* This is an interactive client. */
- SW_MYSQL_CLIENT_SSL = 2048, /* Use SSL encryption for the session. */
- SW_MYSQL_CLIENT_IGNORE_SIGPIPE = 4096, /* Client only flag. */
- SW_MYSQL_CLIENT_TRANSACTIONS = 8192, /* Client knows about transactions. */
- SW_MYSQL_CLIENT_RESERVED = 16384, /* flag for 4.1 protocol. */
- SW_MYSQL_CLIENT_SECURE_CONNECTION = 32768, /* swoole custom name for RESERVED2. */
- SW_MYSQL_CLIENT_RESERVED2 = 32768, /* flag for 4.1 authentication. */
- SW_MYSQL_CLIENT_MULTI_STATEMENTS = (1UL << 16), /* Enable/disable multi-stmt support. */
- SW_MYSQL_CLIENT_MULTI_RESULTS = (1UL << 17), /* Enable/disable multi-results. */
- SW_MYSQL_CLIENT_PS_MULTI_RESULTS = (1UL << 18), /* Multi-results and OUT parameters in PS-protocol. */
- SW_MYSQL_CLIENT_PLUGIN_AUTH = (1UL << 19), /* Client supports plugin authentication. */
- SW_MYSQL_CLIENT_CONNECT_ATTRS = (1UL << 20), /* Client supports connection attributes. */
- SW_MYSQL_CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA = (1UL << 21), /* Enable authentication response packet to be larger than 255 bytes. */
- SW_MYSQL_CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS = (1UL << 22), /* Don't close the connection for a user account with expired password. */
- SW_MYSQL_CLIENT_SESSION_TRACK = (1UL << 23), /* Capable of handling server state change information. */
- SW_MYSQL_CLIENT_DEPRECATE_EOF = (1UL << 24), /* Client no longer needs EOF_Packet and will use OK_Packet instead. */
- SW_MYSQL_CLIENT_SSL_VERIFY_SERVER_CERT = (1UL << 30), /* Verify server certificate. */
- SW_MYSQL_CLIENT_REMEMBER_OPTIONS = (1UL << 31) /* Don't reset the options after an unsuccessful connect. */
-};
-
-// ref: https://dev.mysql.com/doc/internals/en/status-flags.html
-enum sw_mysql_server_status_flags
-{
- SW_MYSQL_SERVER_STATUS_IN_TRANS = 0x0001, // a transaction is active
- SW_MYSQL_SERVER_STATUS_AUTOCOMMIT = 0x0002, //auto-commit is enabled
- SW_MYSQL_SERVER_MORE_RESULTS_EXISTS = 0x0008,
- SW_MYSQL_SERVER_STATUS_NO_GOOD_INDEX_USED = 0x0010,
- SW_MYSQL_SERVER_STATUS_NO_INDEX_USED = 0x0020,
- SW_MYSQL_SERVER_STATUS_CURSOR_EXISTS = 0x0040, // Used by Binary Protocol Resultset to signal that COM_STMT_FETCH must be used to fetch the row-data.
- SW_MYSQL_SERVER_STATUS_LAST_ROW_SENT = 0x0080,
- SW_MYSQL_SERVER_STATUS_DB_DROPPED = 0x0100,
- SW_MYSQL_SERVER_STATUS_NO_BACKSLASH_ESCAPES = 0x0200,
- SW_MYSQL_SERVER_STATUS_METADATA_CHANGED = 0x0400,
- SW_MYSQL_SERVER_QUERY_WAS_SLOW = 0x0800,
- SW_MYSQL_SERVER_PS_OUT_PARAMS = 0x1000,
- SW_MYSQL_SERVER_STATUS_IN_TRANS_READONLY = 0x2000, // in a read-only transaction
- SW_MYSQL_SERVER_SESSION_STATE_CHANGED = 0x4000 // connection state information has changed
-};
-
-#define SW_MYSQL_NO_RSA_ERROR "MySQL8 caching_sha2_password authentication plugin need enable OpenSSL support"
-
-#define SW_MYSQL_NOT_NULL_FLAG 1
-#define SW_MYSQL_PRI_KEY_FLAG 2
-#define SW_MYSQL_UNIQUE_KEY_FLAG 4
-#define SW_MYSQL_MULTIPLE_KEY_FLAG 8
-#define SW_MYSQL_BLOB_FLAG 16
-#define SW_MYSQL_UNSIGNED_FLAG 32
-#define SW_MYSQL_ZEROFILL_FLAG 64
-#define SW_MYSQL_BINARY_FLAG 128
-#define SW_MYSQL_ENUM_FLAG 256
-#define SW_MYSQL_AUTO_INCREMENT_FLAG 512
-#define SW_MYSQL_TIMESTAMP_FLAG 1024
-#define SW_MYSQL_SET_FLAG 2048
-#define SW_MYSQL_NO_DEFAULT_VALUE_FLAG 4096
-#define SW_MYSQL_ON_UPDATE_NOW_FLAG 8192
-#define SW_MYSQL_PART_KEY_FLAG 16384
-#define SW_MYSQL_GROUP_FLAG 32768
-#define SW_MYSQL_NUM_FLAG 32768
-
-/* int<3> payload_length + int<1> sequence_id */
-#define SW_MYSQL_PACKET_HEADER_SIZE 4
-#define SW_MYSQL_PACKET_TYPE_OFFSET 5
-#define SW_MYSQL_PACKET_EOF_MAX_SIZE 9
-#define SW_MYSQL_PACKET_PREPARED_OK_SIZE 12
-#define SW_MYSQL_MAX_PACKET_BODY_SIZE 0x00ffffff
-#define SW_MYSQL_MAX_PACKET_SIZE (SW_MYSQL_PACKET_HEADER_SIZE + SW_MYSQL_MAX_PACKET_BODY_SIZE)
-
-// nonce: a number or bit string used only once, in security engineering
-// other names on doc: challenge/scramble/salt
-#define SW_MYSQL_NONCE_LENGTH 20
-
-// clang-format off
-#define sw_mysql_uint2korr2korr(A) (uint16_t) (((uint16_t) ((uchar) (A)[0])) +\
- ((uint16_t) ((uchar) (A)[1]) << 8))
-#define sw_mysql_uint2korr3korr(A) (uint32_t) (((uint32_t) ((uchar) (A)[0])) +\
- (((uint32_t) ((uchar) (A)[1])) << 8) +\
- (((uint32_t) ((uchar) (A)[2])) << 16))
-#define sw_mysql_uint2korr4korr(A) (uint32_t) (((uint32_t) ((uchar) (A)[0])) +\
- (((uint32_t) ((uchar) (A)[1])) << 8) +\
- (((uint32_t) ((uchar) (A)[2])) << 16) +\
- (((uint32_t) ((uchar) (A)[3])) << 24))
-#define sw_mysql_uint2korr8korr(A) ((uint64_t)(((uint32_t) ((uchar) (A)[0])) +\
- (((uint32_t) ((uchar) (A)[1])) << 8) +\
- (((uint32_t) ((uchar) (A)[2])) << 16) +\
- (((uint32_t) ((uchar) (A)[3])) << 24)) +\
- (((uint64_t) (((uint32_t) ((uchar) (A)[4])) +\
- (((uint32_t) ((uchar) (A)[5])) << 8) +\
- (((uint32_t) ((uchar) (A)[6])) << 16) +\
- (((uint32_t) ((uchar) (A)[7])) << 24))) << 32))
-
-#define sw_mysql_int1store(T,A) do { *((int8_t*) (T)) = (int8_t)(A); } while(0)
-#define sw_mysql_int2store(T,A) do { uint32_t def_temp= (uint32_t) (A) ;\
- *((uchar*) (T)) = (uchar)(def_temp); \
- *((uchar*) (T+1)) = (uchar)((def_temp >> 8)); } while (0)
-#define sw_mysql_int3store(T,A) do { /*lint -save -e734 */\
- *(((char *)(T))) = (char) ((A));\
- *(((char *)(T))+1) = (char) (((A) >> 8));\
- *(((char *)(T))+2) = (char) (((A) >> 16)); \
- /*lint -restore */} while (0)
-#define sw_mysql_int4store(T,A) do { \
- *(((char *)(T))) = (char) ((A));\
- *(((char *)(T))+1) = (char) (((A) >> 8));\
- *(((char *)(T))+2) = (char) (((A) >> 16));\
- *(((char *)(T))+3) = (char) (((A) >> 24)); } while (0)
-#define sw_mysql_int5store(T,A) do { \
- *(((char *)(T))) = (char)((A));\
- *(((char *)(T))+1) = (char)(((A) >> 8));\
- *(((char *)(T))+2) = (char)(((A) >> 16));\
- *(((char *)(T))+3) = (char)(((A) >> 24)); \
- *(((char *)(T))+4) = (char)(((A) >> 32)); } while (0)
-/* Based on int5store() from Andrey Hristov */
-#define sw_mysql_int6store(T,A) do { \
- *(((char *)(T))) = (char)((A));\
- *(((char *)(T))+1) = (char)(((A) >> 8));\
- *(((char *)(T))+2) = (char)(((A) >> 16));\
- *(((char *)(T))+3) = (char)(((A) >> 24)); \
- *(((char *)(T))+4) = (char)(((A) >> 32)); \
- *(((char *)(T))+5) = (char)(((A) >> 40)); } while (0)
-
-// clang-format on
-
-#define sw_mysql_int8store(T,A) do { \
- uint32_t def_temp= (uint32_t) (A), def_temp2= (uint32_t) ((A) >> 32); \
- sw_mysql_int4store((T),def_temp); \
- sw_mysql_int4store((T+4),def_temp2); } while (0)
-
-#define sw_mysql_doublestore(T,A) do { \
- double def_temp = (double) A; \
- memcpy(T, &def_temp, sizeof(double)); \
- } while (0)
-
-#if defined(SW_DEBUG) && defined(SW_LOG_TRACE_OPEN)
-#define swMysqlPacketDump(length, number, data, title) \
- if (SW_LOG_TRACE >= sw_logger()->get_level() && (SW_TRACE_MYSQL_CLIENT & SwooleG.trace_flags)) \
- { \
- swoole_debug("+----------+------------+-------------------------------------------------------+"); \
- swoole_debug("| P#%-6u | L%-9u | %-10u %42s |", number, SW_MYSQL_PACKET_HEADER_SIZE + length, length, title); \
- swoole_hex_dump(data, length); \
- }
-#else
-#define swMysqlPacketDump(length, number, data, title)
-#endif
-
-namespace swoole { namespace mysql {
-//-----------------------------------namespace begin--------------------------------------------
-char get_charset(const char *name);
-uint8_t get_static_type_size(uint8_t type);
-
-inline uint8_t read_lcb_size(const char *p)
-{
- switch ((uchar) p[0])
- {
- case 251:
- return 1;
- case 252:
- return 3;
- case 253:
- return 4;
- case 254:
- return 9;
- default:
- return 1;
- }
-}
-
-inline uint8_t read_lcb(const char *p, uint64_t *length, bool *nul)
-{
- switch ((uchar) p[0])
- {
- case 251: /* fb : 1 octet */
- *length = 0;
- *nul = true;
- return 1;
- case 252: /* fc : 2 octets */
- *length = sw_mysql_uint2korr2korr(p + 1);
- *nul = false;
- return 3;
- case 253: /* fd : 3 octets */
- *length = sw_mysql_uint2korr3korr(p + 1);
- *nul = false;
- return 4;
- case 254: /* fe : 8 octets */
- *length = sw_mysql_uint2korr8korr(p + 1);
- *nul = false;
- return 9;
- default:
- *length = (uchar) p[0];
- *nul = false;
- return 1;
- }
-}
-
-inline uint8_t read_lcb(const char *p, uint32_t *length, bool *nul)
-{
- uint64_t _r;
- uint8_t ret = read_lcb(p, &_r, nul);
- *length = _r;
- return ret;
-}
-
-inline uint8_t write_lcb(char *p, uint64_t length, bool nul = false)
-{
- if (nul)
- {
- sw_mysql_int1store(p++, 251);
- return 1;
- }
- if (length <= 250)
- {
- sw_mysql_int1store(p, length);
- return 1;
- }
- else if (length <= 0xffff)
- {
- sw_mysql_int1store(p++, 252);
- sw_mysql_int2store(p, length);
- return 3;
- }
- else if (length <= 0xffffff)
- {
- sw_mysql_int1store(p++, 253);
- sw_mysql_int3store(p, length);
- return 4;
- }
- else
- {
- sw_mysql_int1store(p++, 254);
- sw_mysql_int8store(p, length);
- return 9;
- }
-}
-
-class packet
-{
-public:
- static inline uint32_t get_length(const char *data)
- {
- return sw_mysql_uint2korr3korr(data);
- }
- static inline uint32_t get_number(const char *data)
- {
- return (uint8_t) data[3];
- }
- static inline void set_length(char *buffer, uint32_t length)
- {
- buffer[0] = length;
- buffer[1] = length >> 8;
- buffer[2] = length >> 16;
- }
- static inline void set_number(char *buffer, uint8_t number)
- {
- buffer[3] = number;
- }
- static inline void set_header(char *buffer, uint32_t length, uint8_t number)
- {
- set_length(buffer, length);
- set_number(buffer, number);
- }
-};
-
-class server_packet : public packet
-{
-public:
- struct header {
- uint32_t length :24;
- uint32_t number :8;
- header() : length(0), number(0) { }
- } header;
- server_packet() { }
- server_packet(const char *data)
- {
- parse(data);
- }
- inline void parse(const char *data)
- {
- header.length = packet::get_length(data);
- header.number = packet::get_number(data);
- }
- static inline uint8_t parse_type(const char *data)
- {
- if (sw_unlikely(!data))
- {
- return SW_MYSQL_PACKET_NULL;
- }
- return (uint8_t) data[SW_MYSQL_PACKET_HEADER_SIZE];
- }
- static inline bool is_eof(const char *data)
- {
- return (uint8_t) data[SW_MYSQL_PACKET_HEADER_SIZE] == SW_MYSQL_PACKET_EOF;
- }
- static inline bool is_ok(const char *data)
- {
- return (uint8_t) data[SW_MYSQL_PACKET_HEADER_SIZE] == SW_MYSQL_PACKET_OK;
- }
- static inline bool is_err(const char *data)
- {
- return (uint8_t) data[SW_MYSQL_PACKET_HEADER_SIZE] == SW_MYSQL_PACKET_ERR;
- }
-};
-
-class server_status
-{
-public:
- int16_t status = 0;
- void operator =(uint16_t status)
- {
- this->status = status;
- }
- inline bool more_results_exists()
- {
- bool b = !!(status & SW_MYSQL_SERVER_MORE_RESULTS_EXISTS);
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "More results exist = %u", b);
- return b;
- }
-};
-
-class client_packet : public packet
-{
-public:
- client_packet(size_t body_size = 1024 - SW_MYSQL_PACKET_HEADER_SIZE)
- {
- SW_ASSERT(body_size > 0);
- if (body_size <= 4)
- {
- data.header = stack_buffer;
- }
- else
- {
- data.header = new char[SW_MEM_ALIGNED_SIZE(SW_MYSQL_PACKET_HEADER_SIZE + body_size)]();
- }
- data.body = data.header + SW_MYSQL_PACKET_HEADER_SIZE;
- }
- inline const char* get_data()
- {
- return data.header;
- }
- inline uint32_t get_data_length()
- {
- return SW_MYSQL_PACKET_HEADER_SIZE + get_length();
- }
- inline uint32_t get_length()
- {
- return sw_mysql_uint2korr3korr(data.header);
- }
- inline uint8_t get_number()
- {
- return (uint8_t) data.header[3];
- }
- inline const char* get_body()
- {
- return data.body;
- }
- inline void set_header(uint32_t length, uint8_t number)
- {
- packet::set_header(data.header, length, number);
- }
- ~client_packet()
- {
- if (data.header != stack_buffer)
- {
- delete[] data.header;
- }
- }
-protected:
- struct {
- char *header = nullptr;
- char *body = nullptr;
- } data;
- char stack_buffer[SW_MYSQL_PACKET_HEADER_SIZE + 4] = {};
-};
-
-class command_packet : public client_packet
-{
-public:
- command_packet(enum sw_mysql_command command, const char *sql = nullptr, size_t length = 0) : client_packet(1 + length)
- {
- set_command(command);
- set_header(1 + length, 0);
- if (length > 0)
- {
- memcpy(data.body + 1, sql, length);
- }
- };
- inline void set_command(enum sw_mysql_command command)
- {
- data.body[0] = (char) command;
- }
-};
-
-class err_packet : public server_packet
-{
-public:
- uint16_t code;
- std::string msg;
- char sql_state[5 + 1];
- err_packet(const char *data);
-};
-
-class ok_packet : public server_packet
-{
-public:
- uint64_t affected_rows = 0;
- uint64_t last_insert_id = 0;
- mysql::server_status server_status;
- unsigned int warning_count = 0;
- ok_packet() { }
- ok_packet(const char *data);
-};
-
-class eof_packet : public server_packet
-{
-public:
- uint16_t warning_count;
- mysql::server_status server_status;
- eof_packet(const char *data);
-};
-
-class raw_data_packet : public server_packet
-{
-public:
- const char *body;
- raw_data_packet(const char *data) : server_packet(data), body(data + SW_MYSQL_PACKET_HEADER_SIZE)
- {
- swMysqlPacketDump(header.length, header.number, data, "Protocol::RawData");
- }
-};
-
-class greeting_packet : public server_packet
-{
-public:
- uint8_t protocol_version = 0;
- std::string server_version = "";
- int connection_id = 0;
- char auth_plugin_data[SW_MYSQL_NONCE_LENGTH + 1] = {}; // nonce + '\0'
- uint8_t auth_plugin_data_length = 0;
- char filler = 0;
- int capability_flags = 0;
- char charset = SW_MYSQL_DEFAULT_CHARSET;
- mysql::server_status status_flags;
- char reserved[10] = {};
- std::string auth_plugin_name = "";
- greeting_packet(const char *data);
-};
-
-class login_packet : public client_packet
-{
-public:
- login_packet(
- greeting_packet *greeting_packet,
- const std::string &user,
- const std::string &password,
- std::string database,
- char charset
- );
-};
-
-class auth_switch_request_packet : public server_packet
-{
-public:
- std::string auth_method_name = "mysql_native_password";
- char auth_method_data[SW_MYSQL_NONCE_LENGTH + 1] = {};
- auth_switch_request_packet(const char *data);
-};
-
-class auth_switch_response_packet : public client_packet
-{
-public:
- auth_switch_response_packet(auth_switch_request_packet *req, const std::string &password);
-};
-
-class auth_signature_request_packet : public server_packet
-{
-public:
- char data[2] = {};
- auth_signature_request_packet(const char *data) :server_packet(data)
- {
- swMysqlPacketDump(header.length, header.number, data, "Protocol::AuthSignatureRequest");
- memcpy(&this->data, data + SW_MYSQL_PACKET_HEADER_SIZE, 2);
- }
- inline bool is_full_auth_required()
- {
- return data[1] == SW_MYSQL_AUTH_SIGNATURE_FULL_AUTH_REQUIRED;
- }
- inline bool is_vaild()
- {
- return data[0] == SW_MYSQL_AUTH_SIGNATURE && (data[1] == SW_MYSQL_AUTH_SIGNATURE_SUCCESS || data[1] == SW_MYSQL_AUTH_SIGNATURE_FULL_AUTH_REQUIRED);
- }
-};
-
-class auth_signature_prepared_packet : public client_packet
-{
-public:
- auth_signature_prepared_packet(uint8_t number) : client_packet(1)
- {
- set_header(1, number);
- data.body[0] = SW_MYSQL_AUTH_SIGNATURE_RSA_PREPARED;
- }
-};
-
-class auth_signature_response_packet : public client_packet
-{
-public:
- auth_signature_response_packet(raw_data_packet *raw_data_pakcet, const std::string &password, const char *auth_plugin_data);
-};
-
-class lcb_packet : public server_packet
-{
-public:
- uint32_t length = 0;
- bool nul = 0;
- lcb_packet(const char *data) : server_packet(data)
- {
- swMysqlPacketDump(header.length, header.number, data, "Protocol::LengthCodedBinary");
- bytes_length = read_lcb(data + SW_MYSQL_PACKET_HEADER_SIZE, &length, &nul);
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "binary_length=%u, nul=%u", header.length, nul);
- }
- bool is_vaild()
- {
- return header.length == bytes_length;
- }
-private:
- uint8_t bytes_length;
-};
-
-class field_packet : public server_packet
-{
-public:
- char *catalog = nullptr; /* Catalog for table */
- uint32_t catalog_length = 0;
- char *database = nullptr; /* Database for table */
- uint32_t database_length = 0;
- char *table = nullptr; /* Table of column if column was a field */
- uint32_t table_length = 0;
- char *org_table = nullptr; /* Org table name, if table was an alias */
- uint32_t org_table_length = 0;
- char *name = nullptr; /* Name of column */
- uint32_t name_length = 0;
- char *org_name = nullptr; /* Original column name, if an alias */
- uint32_t org_name_length = 0;
- char charset = 0;
- uint64_t length = 0; /* Width of column (create length) */
- uint8_t type = 0; /* Type of field. See mysql_com.h for types */
- uint32_t flags = 0; /* Div flags */
- uint32_t decimals = 0; /* Number of decimals in field */
- char *def = nullptr; /* Default value (set by mysql_list_fields) */
- uint32_t def_length = 0;
- void *extension = nullptr;
- field_packet() { }
- field_packet(const char *data) {
- parse(data);
- }
- void parse(const char *data);
- ~field_packet()
- {
- if (body)
- {
- delete[] body;
- }
- }
-protected:
- char *body = nullptr;
-};
-
-typedef field_packet param_packet;
-
-class row_data
-{
-public:
- char stack_buffer[32];
- struct {
- uint64_t length; // binary code length
- bool nul; // is nul?
- } text;
- row_data(const char *data)
- {
- next_packet(data);
- }
- inline void next_packet(const char *data)
- {
- read_ptr = packet_body = data + SW_MYSQL_PACKET_HEADER_SIZE;
- packet_eof = packet_body + packet::get_length(data);
- }
- inline bool eof()
- {
- return read_ptr == packet_eof;
- }
- inline const char* read(size_t length)
- {
- if (sw_likely(read_ptr + length <= packet_eof))
- {
- const char *p = read_ptr;
- read_ptr += length;
- return p;
- }
- return nullptr;
- }
- inline uint32_t recv(char *buf, size_t size)
- {
- uint32_t readable_length = packet_eof - read_ptr;
- uint32_t read_bytes = SW_MIN(readable_length, size);
- if (sw_likely(read_bytes > 0))
- {
- memcpy(buf, read_ptr, read_bytes);
- read_ptr += read_bytes;
- }
- return read_bytes;
- }
-protected:
- const char *packet_body;
- const char *packet_eof;
- const char *read_ptr;
-};
-
-class row_data_text
-{
-public:
- uint64_t length = 0;
- bool nul = false;
- const char *body = nullptr;
- row_data_text(const char **pp)
- {
- body = *pp + read_lcb(*pp, &length, &nul);
- *pp = body + length;
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT,
- "text[%" PRIu64 "]: %.*s%s",
- length, (int) SW_MIN(64, length), body,
- nul ? "null" : ((length > 64 /*|| length > readable_length*/) ? "..." : "")
- );
- }
-};
-
-inline std::string datetime(const char *p, uint8_t length, uint32_t decimals)
-{
- uint16_t y = 0;
- uint8_t m = 0, d = 0, h = 0, i = 0, s = 0;
- uint32_t sp = 0;
- if (length != 0)
- {
- y = sw_mysql_uint2korr2korr(p);
- m = *(uint8_t *) (p + 2);
- d = *(uint8_t *) (p + 3);
- if (length > 4)
- {
- h = *(uint8_t *) (p + 4);
- i = *(uint8_t *) (p + 5);
- s = *(uint8_t *) (p + 6);
- }
- if (length > 7)
- {
- sp = sw_mysql_uint2korr4korr(p + 7);
- }
- }
- if (decimals > 0 && decimals < 7) {
- return swoole::std_string::format(
- "%04u-%02u-%02u %02u:%02u:%02u.%0*u",
- y, m, d, h, i, s, decimals, (uint32_t) (sp / ::pow(10, (double) (6 - decimals)))
- );
- } else {
- return swoole::std_string::format(
- "%04u-%02u-%02u %02u:%02u:%02u",
- y, m, d, h, i, s
- );
- }
-}
-
-inline std::string time(const char *p, uint8_t length, uint32_t decimals)
-{
- bool neg = false;
- uint32_t d = 0, sp = 0;
- uint8_t h = 0, m = 0, s = 0;
- if (length != 0)
- {
- neg = (bool) *((uint8_t *) p);
- d = sw_mysql_uint2korr4korr(p + 1);
- h = *(uint8_t *) (p + 5);
- m = *(uint8_t *) (p + 6);
- s = *(uint8_t *) (p + 7);
- if (length > 8)
- {
- sp = sw_mysql_uint2korr4korr(p + 8);
- }
- if (d != 0) {
- /* Convert days to hours at once */
- h += d * 24;
- }
- }
- if (decimals > 0 && decimals < 7) {
- return swoole::std_string::format(
- "%s%02u:%02u:%02u.%0*u",
- (neg ? "-" : ""), h, m, s, decimals, (uint32_t) (sp / ::pow(10, (double) (6 - decimals)))
- );
- } else {
- return swoole::std_string::format(
- "%s%02u:%02u:%02u",
- (neg ? "-" : ""), h, m, s
- );
- }
-}
-
-inline std::string date(const char *p, uint8_t length)
-{
- uint16_t y = 0;
- uint8_t m = 0, d = 0;
- if (length != 0)
- {
- y = sw_mysql_uint2korr2korr(p);
- m = *(uint8_t *) (p + 2);
- d = *(uint8_t *) (p + 3);
- }
- return swoole::std_string::format("%04u-%02u-%02u", y, m, d);
-}
-
-inline std::string year(const char *p, uint8_t length)
-{
- uint16_t y = 0;
- if (length != 0)
- {
- y = sw_mysql_uint2korr2korr(p);
- }
- return swoole::std_string::format("%04u", y);
-}
-
-class result_info
-{
-public:
- ok_packet ok;
-
- inline void alloc_fields(uint32_t length)
- {
- clear_fields();
- if (sw_likely(length != 0))
- {
- fields.info = new field_packet[length];
- fields.length = length;
- }
- else
- {
- fields.length = 0;
- fields.info = nullptr;
- }
- }
- inline uint32_t get_fields_length()
- {
- return fields.length;
- }
- inline field_packet* get_fields(uint32_t index)
- {
- return fields.info;
- }
- inline field_packet* get_field(uint32_t index)
- {
- return &fields.info[index];
- }
- inline void set_field(uint32_t index, const char *data)
- {
- fields.info[index].parse(data);
- }
- inline void clear_fields()
- {
- if (fields.length > 0)
- {
- delete[] fields.info;
- }
- }
- ~result_info()
- {
- clear_fields();
- }
-protected:
- struct {
- uint32_t length = 0;
- field_packet *info = nullptr;
- } fields;
-};
-
-class statement : public server_packet
-{
-public:
- uint32_t id = 0;
- uint16_t field_count = 0;
- uint16_t param_count = 0;
- uint16_t warning_count = 0;
- statement() { }
- statement(const char* data) : server_packet(data)
- {
- swMysqlPacketDump(header.length, header.number, data, "COM_STMT_PREPARE_OK_Packet");
- // skip the packet header
- data += SW_MYSQL_PACKET_HEADER_SIZE;
- // status (1) -- [00] OK
- SW_ASSERT(data[0] == SW_MYSQL_PACKET_OK);
- data += 1;
- // statement_id (4) -- statement-id
- id = sw_mysql_uint2korr4korr(data);
- data += 4;
- // num_columns (2) -- number of columns
- field_count = sw_mysql_uint2korr2korr(data);
- data += 2;
- // num_params (2) -- number of params
- param_count = sw_mysql_uint2korr2korr(data);
- data += 2;
- // reserved_1 (1) -- [00] filler
- data += 1;
- // warning_count (2) -- number of warnings
- warning_count = sw_mysql_uint2korr2korr(data);
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "statement_id=%u, field_count=%u, param_count=%u, warning_count=%u",
- id, field_count, param_count, warning_count
- );
- }
-};
-
-class null_bitmap
-{
-public:
- static uint32_t get_size(uint32_t field_length)
- {
- return ((field_length + 9) / 8) + 1;
- }
- null_bitmap(const char *p, uint32_t size) :
- size(size)
- {
- map = new char[size];
- memcpy(map, p, size);
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "null_count=%u", size);
- }
- inline bool is_null(size_t i)
- {
- return ((map + 1)[((i + 2) / 8)] & (0x01 << ((i + 2) % 8))) != 0;
- }
- ~null_bitmap()
- {
- delete[] map;
- }
-protected:
- uint32_t size;
- char *map;
-};
-//-----------------------------------namespace end--------------------------------------------
-}}
diff --git a/ext-src/php_swoole_private.h b/ext-src/php_swoole_private.h
index 2b05b58b885..85c29f945e7 100644
--- a/ext-src/php_swoole_private.h
+++ b/ext-src/php_swoole_private.h
@@ -100,8 +100,8 @@ extern PHPAPI int php_array_merge(zend_array *dest, zend_array *src);
#define SWOOLE_SOCKETS_SUPPORT
#endif
-#if PHP_VERSION_ID < 80000
-#error "require PHP version 8.0 or later"
+#if PHP_VERSION_ID < 80100
+#error "require PHP version 8.1 or later"
#endif
#if defined(ZTS) && defined(SW_USE_THREAD_CONTEXT)
@@ -112,6 +112,10 @@ extern PHPAPI int php_array_merge(zend_array *dest, zend_array *src);
#error "only linux support iouring"
#endif
+#if defined(SW_THREAD) && !defined(ZTS)
+#error "swoole thread must be used with ZTS"
+#endif
+
//--------------------------------------------------------
#define SW_MAX_FIND_COUNT 100 // for swoole_server::connection_list
#define SW_PHP_CLIENT_BUFFER_SIZE 65535
@@ -241,10 +245,7 @@ void php_swoole_client_minit(int module_number);
void php_swoole_client_coro_minit(int module_number);
void php_swoole_http_client_coro_minit(int module_number);
void php_swoole_http2_client_coro_minit(int module_number);
-void php_swoole_mysql_coro_minit(int module_number);
-void php_swoole_redis_coro_minit(int module_number);
#ifdef SW_USE_PGSQL
-void php_swoole_postgresql_coro_minit(int module_number);
void php_swoole_pgsql_minit(int module_number);
#endif
#ifdef SW_USE_ODBC
@@ -266,6 +267,14 @@ void php_swoole_http_server_coro_minit(int module_number);
void php_swoole_websocket_server_minit(int module_number);
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
/**
* RINIT
@@ -277,6 +286,7 @@ void php_swoole_runtime_rinit();
#ifdef SW_USE_ORACLE
void php_swoole_oracle_rinit();
#endif
+void php_swoole_thread_rinit();
/**
* RSHUTDOWN
@@ -290,6 +300,9 @@ void php_swoole_process_rshutdown();
void php_swoole_coroutine_scheduler_rshutdown();
void php_swoole_runtime_rshutdown();
void php_swoole_server_rshutdown();
+#ifdef SW_THREAD
+void php_swoole_thread_rshutdown();
+#endif
int php_swoole_reactor_init();
void php_swoole_set_global_option(zend_array *vht);
@@ -350,12 +363,8 @@ zend_bool php_swoole_signal_isset_handler(int signo);
#define SW_Z8_OBJ_P(zobj) Z_OBJ_P(zobj)
typedef ssize_t php_stream_size_t;
-
-#if PHP_VERSION_ID < 80100
-typedef const char error_filename_t;
-#else
typedef zend_string error_filename_t;
-#endif
+
//----------------------------------Zval API------------------------------------
// Deprecated: do not use it anymore
diff --git a/ext-src/php_swoole_server.h b/ext-src/php_swoole_server.h
index 3e422251d9a..4fc2429069a 100644
--- a/ext-src/php_swoole_server.h
+++ b/ext-src/php_swoole_server.h
@@ -62,7 +62,15 @@ enum php_swoole_server_port_callback_type {
#define PHP_SWOOLE_SERVER_PORT_CALLBACK_NUM (SW_SERVER_CB_onBufferEmpty + 1)
namespace swoole {
+struct ServerPortProperty;
struct TaskCo;
+}; // namespace swoole
+
+zval *php_swoole_server_zval_ptr(swoole::Server *serv);
+swoole::ServerPortProperty *php_swoole_server_get_port_property(swoole::ListenPort *port);
+void php_swoole_server_set_port_property(swoole::ListenPort *port, swoole::ServerPortProperty *property);
+
+namespace swoole {
struct ServerPortProperty {
zval *callbacks[PHP_SWOOLE_SERVER_PORT_CALLBACK_NUM];
@@ -76,7 +84,6 @@ struct ServerPortProperty {
struct ServerProperty {
std::vector ports;
std::vector user_processes;
- ServerPortProperty *primary_port;
zend_fcall_info_cache *callbacks[PHP_SWOOLE_SERVER_CALLBACK_NUM];
std::unordered_map task_callbacks;
std::unordered_map task_coroutine_map;
@@ -87,19 +94,16 @@ struct ServerProperty {
struct ServerObject {
Server *serv;
ServerProperty *property;
+ zval init_arguments;
zend_object std;
zend_class_entry *get_ce() {
- return Z_OBJCE_P(get_object());
- }
-
- zval *get_object() {
- return (zval *) serv->private_data_2;
+ return Z_OBJCE_P(php_swoole_server_zval_ptr(serv));
}
bool isset_callback(ListenPort *port, int event_type) {
- ServerPortProperty *port_property = (ServerPortProperty *) port->ptr;
- return (port_property->callbacks[event_type] || property->primary_port->callbacks[event_type]);
+ return (php_swoole_server_get_port_property(port)->callbacks[event_type] ||
+ php_swoole_server_get_port_property(serv->get_primary_port())->callbacks[event_type]);
}
zend_bool is_websocket_server() {
@@ -147,4 +151,4 @@ void php_swoole_server_onBufferEmpty(swServer *, swDataHead *);
swServer *php_swoole_server_get_and_check_server(zval *zobject);
void php_swoole_server_port_deref(zend_object *object);
swoole::ServerObject *php_swoole_server_get_zend_object(swoole::Server *serv);
-zval *php_swoole_server_get_zval_object(swoole::Server *serv);
+
diff --git a/ext-src/php_swoole_thread.h b/ext-src/php_swoole_thread.h
new file mode 100644
index 00000000000..405a16573d4
--- /dev/null
+++ b/ext-src/php_swoole_thread.h
@@ -0,0 +1,268 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Twosee |
+ | Author: Tianfeng Han |
+ +----------------------------------------------------------------------+
+*/
+
+#pragma once
+
+#include "php_swoole_cxx.h"
+
+#ifdef SW_THREAD
+
+#include "swoole_lock.h"
+
+typedef uint32_t ThreadResourceId;
+struct ThreadResource;
+
+ThreadResourceId php_swoole_thread_resource_insert(ThreadResource *res);
+bool php_swoole_thread_resource_free(ThreadResourceId resource_id, ThreadResource *res);
+ThreadResource *php_swoole_thread_resource_fetch(ThreadResourceId resource_id);
+
+void php_swoole_thread_start(zend_string *file, zend_string *argv);
+zend_string *php_swoole_thread_serialize(zval *zdata);
+bool php_swoole_thread_unserialize(zend_string *data, zval *zv);
+
+zval *php_swoole_thread_get_arguments();
+
+#define EMSG_NO_RESOURCE "resource not found"
+#define ECODE_NO_RESOURCE -2
+
+#define IS_STREAM_SOCKET 98
+#define IS_SERIALIZED_OBJECT 99
+
+struct ThreadResource {
+ uint32_t ref_count;
+
+ ThreadResource() {
+ ref_count = 1;
+ }
+
+ uint32_t add_ref() {
+ return ++ref_count;
+ }
+
+ uint32_t del_ref() {
+ return --ref_count;
+ }
+};
+
+
+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);
+ void fetch(zval *return_value);
+ void release();
+
+ ~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.stub.php b/ext-src/stubs/php_swoole.stub.php
index ba952951a10..bc52e6f31b5 100644
--- a/ext-src/stubs/php_swoole.stub.php
+++ b/ext-src/stubs/php_swoole.stub.php
@@ -16,7 +16,7 @@ function swoole_async_dns_lookup_coro(string $domain_name, float $timeout = 60,
{
}
-function swoole_async_set(array $settings): void
+function swoole_async_set(array $settings): bool
{
}
diff --git a/ext-src/stubs/php_swoole_arginfo.h b/ext-src/stubs/php_swoole_arginfo.h
index 64cdf7b9dfe..34aec6bcf1d 100644
--- a/ext-src/stubs/php_swoole_arginfo.h
+++ b/ext-src/stubs/php_swoole_arginfo.h
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 20f9cbe81acd5771dbf8e18dd8af8952540ead91 */
+ * Stub hash: 1ab45a47bad71a13ad16c3d92dcb8612920ae84c */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_swoole_version, 0, 0, IS_STRING, 0)
ZEND_END_ARG_INFO()
@@ -15,7 +15,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_swoole_async_dns_lookup_coro, 0,
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, type, IS_LONG, 0, "AF_INET")
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_swoole_async_set, 0, 1, IS_VOID, 0)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_swoole_async_set, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, settings, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
diff --git a/ext-src/stubs/php_swoole_lock.stub.php b/ext-src/stubs/php_swoole_lock.stub.php
index 9e9f0406275..9ad3c621b20 100644
--- a/ext-src/stubs/php_swoole_lock.stub.php
+++ b/ext-src/stubs/php_swoole_lock.stub.php
@@ -1,7 +1,7 @@
is_process_mode() && conn->reactor_id != SwooleTG.id) {
return;
}
- if (serv->is_base_mode() && SwooleWG.worker && conn->reactor_id != SwooleWG.worker->id) {
+ if (serv->is_base_mode() && sw_worker() && conn->reactor_id != sw_worker()->id) {
return;
}
list.push_back(get_connection_info(serv, conn));
diff --git a/ext-src/swoole_async_coro.cc b/ext-src/swoole_async_coro.cc
index 98466be5aba..b50f77d75b1 100644
--- a/ext-src/swoole_async_coro.cc
+++ b/ext-src/swoole_async_coro.cc
@@ -44,33 +44,40 @@ void php_swoole_async_coro_rshutdown() {
void php_swoole_set_aio_option(HashTable *vht) {
zval *ztmp;
/* AIO */
- if (php_swoole_array_get_value(vht, "aio_core_worker_num", ztmp)) {
- zend_long v = zval_get_long(ztmp);
- v = SW_MAX(1, SW_MIN(v, UINT32_MAX));
- SwooleG.aio_core_worker_num = v;
- }
- if (php_swoole_array_get_value(vht, "aio_worker_num", ztmp)) {
- zend_long v = zval_get_long(ztmp);
- v = SW_MAX(1, SW_MIN(v, UINT32_MAX));
- SwooleG.aio_worker_num = v;
- }
- if (php_swoole_array_get_value(vht, "aio_max_wait_time", ztmp)) {
- SwooleG.aio_max_wait_time = zval_get_double(ztmp);
- }
- if (php_swoole_array_get_value(vht, "aio_max_idle_time", ztmp)) {
- SwooleG.aio_max_idle_time = zval_get_double(ztmp);
- }
+ if (php_swoole_array_get_value(vht, "aio_core_worker_num", ztmp)) {
+ zend_long v = zval_get_long(ztmp);
+ v = SW_MAX(1, SW_MIN(v, UINT32_MAX));
+ SwooleG.aio_core_worker_num = v;
+ }
+ if (php_swoole_array_get_value(vht, "aio_worker_num", ztmp)) {
+ zend_long v = zval_get_long(ztmp);
+ v = SW_MAX(1, SW_MIN(v, UINT32_MAX));
+ SwooleG.aio_worker_num = v;
+ }
+ if (php_swoole_array_get_value(vht, "aio_max_wait_time", ztmp)) {
+ SwooleG.aio_max_wait_time = zval_get_double(ztmp);
+ }
+ if (php_swoole_array_get_value(vht, "aio_max_idle_time", ztmp)) {
+ SwooleG.aio_max_idle_time = zval_get_double(ztmp);
+ }
#if defined(__linux__) && defined(SW_USE_IOURING)
- if (php_swoole_array_get_value(vht, "iouring_entries", ztmp)) {
- zend_long v = zval_get_long(ztmp);
- SwooleG.iouring_entries = SW_MAX(0, SW_MIN(v, UINT32_MAX));
- }
+ if (php_swoole_array_get_value(vht, "iouring_entries", ztmp)) {
+ zend_long v = zval_get_long(ztmp);
+ SwooleG.iouring_entries = SW_MAX(0, SW_MIN(v, UINT32_MAX));
+ }
#endif
}
PHP_FUNCTION(swoole_async_set) {
+#ifdef SW_THREAD
+ if (!tsrm_is_main_thread()) {
+ swoole_set_last_error(SW_ERROR_OPERATION_NOT_SUPPORT);
+ RETURN_FALSE;
+ }
+#endif
if (sw_reactor()) {
php_swoole_fatal_error(E_ERROR, "eventLoop has already been created. unable to change settings");
+ swoole_set_last_error(SW_ERROR_OPERATION_NOT_SUPPORT);
RETURN_FALSE;
}
@@ -117,8 +124,9 @@ PHP_FUNCTION(swoole_async_set) {
SwooleG.use_async_resolver = zval_is_true(ztmp);
}
if (php_swoole_array_get_value(vht, "enable_coroutine", ztmp)) {
- SWOOLE_G(enable_coroutine) = zval_is_true(ztmp);
+ SwooleG.enable_coroutine = zval_is_true(ztmp);
}
+ RETURN_TRUE;
}
PHP_FUNCTION(swoole_async_dns_lookup_coro) {
@@ -175,5 +183,5 @@ PHP_FUNCTION(swoole_async_dns_lookup_coro) {
}
memcpy(cache->address, Z_STRVAL_P(return_value), Z_STRLEN_P(return_value));
cache->address[Z_STRLEN_P(return_value)] = '\0';
- cache->update_time = Timer::get_absolute_msec() + (int64_t)(SwooleG.dns_cache_refresh_time * 1000);
+ cache->update_time = Timer::get_absolute_msec() + (int64_t) (SwooleG.dns_cache_refresh_time * 1000);
}
diff --git a/ext-src/swoole_atomic.cc b/ext-src/swoole_atomic.cc
index e702a2b3433..90dc7f4fe81 100644
--- a/ext-src/swoole_atomic.cc
+++ b/ext-src/swoole_atomic.cc
@@ -21,68 +21,6 @@ BEGIN_EXTERN_C()
#include "stubs/php_swoole_atomic_arginfo.h"
END_EXTERN_C()
-#ifdef HAVE_FUTEX
-#include
-#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;
@@ -306,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) {
@@ -322,11 +256,7 @@ 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));
}
PHP_METHOD(swoole_atomic_long, __construct) {
diff --git a/ext-src/swoole_client_coro.cc b/ext-src/swoole_client_coro.cc
index acd38ce917a..9fe1f8c7c46 100644
--- a/ext-src/swoole_client_coro.cc
+++ b/ext-src/swoole_client_coro.cc
@@ -113,7 +113,7 @@ static void client_coro_free_object(zend_object *object) {
}
#define CLIENT_CORO_GET_SOCKET_SAFE(__sock) \
- SW_CLIENT_GET_SOCKET_SAFE(__sock, &client_coro_get_client(ZEND_THIS)->zsocket); \
+ SW_CLIENT_GET_SOCKET_SAFE(__sock, &client_coro_get_client(ZEND_THIS)->zsocket); \
if (!__sock) { \
php_swoole_socket_set_error_properties( \
ZEND_THIS, SW_ERROR_CLIENT_NO_CONNECTION, swoole_strerror(SW_ERROR_CLIENT_NO_CONNECTION)); \
diff --git a/ext-src/swoole_coroutine.cc b/ext-src/swoole_coroutine.cc
index e0e9d27799b..8d94c2cd9e3 100644
--- a/ext-src/swoole_coroutine.cc
+++ b/ext-src/swoole_coroutine.cc
@@ -57,19 +57,19 @@ static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend
enum sw_exit_flags { SW_EXIT_IN_COROUTINE = 1 << 1, SW_EXIT_IN_SERVER = 1 << 2 };
-bool PHPCoroutine::activated = false;
-zend_array *PHPCoroutine::options = nullptr;
+SW_THREAD_LOCAL bool PHPCoroutine::activated = false;
+SW_THREAD_LOCAL zend_array *PHPCoroutine::options = nullptr;
-PHPCoroutine::Config PHPCoroutine::config{
+SW_THREAD_LOCAL PHPCoroutine::Config PHPCoroutine::config{
SW_DEFAULT_MAX_CORO_NUM,
0,
false,
true,
};
-PHPContext PHPCoroutine::main_context{};
-std::thread PHPCoroutine::interrupt_thread;
-bool PHPCoroutine::interrupt_thread_running = false;
+SW_THREAD_LOCAL PHPContext PHPCoroutine::main_context{};
+SW_THREAD_LOCAL std::thread PHPCoroutine::interrupt_thread;
+SW_THREAD_LOCAL bool PHPCoroutine::interrupt_thread_running = false;
extern void php_swoole_load_library();
@@ -413,6 +413,7 @@ void PHPCoroutine::shutdown() {
zend_array_destroy(options);
options = nullptr;
}
+ free_main_context();
}
void PHPCoroutine::deadlock_check() {
@@ -858,32 +859,30 @@ void PHPCoroutine::fiber_context_switch_try_notify(PHPContext *from, PHPContext
#endif /* SWOOLE_COROUTINE_MOCK_FIBER_CONTEXT */
#ifdef ZEND_CHECK_STACK_LIMIT
-void* PHPCoroutine::stack_limit(PHPContext *ctx)
-{
+void *PHPCoroutine::stack_limit(PHPContext *ctx) {
#ifdef SW_USE_THREAD_CONTEXT
return nullptr;
#else
- zend_ulong reserve = EG(reserved_stack_size);
+ zend_ulong reserve = EG(reserved_stack_size);
#ifdef __APPLE__
- /* On Apple Clang, the stack probing function ___chkstk_darwin incorrectly
- * probes a location that is twice the entered function's stack usage away
- * from the stack pointer, when using an alternative stack.
- * https://openradar.appspot.com/radar?id=5497722702397440
- */
- reserve = reserve * 2;
+ /* On Apple Clang, the stack probing function ___chkstk_darwin incorrectly
+ * probes a location that is twice the entered function's stack usage away
+ * from the stack pointer, when using an alternative stack.
+ * https://openradar.appspot.com/radar?id=5497722702397440
+ */
+ reserve = reserve * 2;
#endif
if (!ctx->co) {
return nullptr;
}
- /* stack->pointer is the end of the stack */
- return (int8_t*)ctx->co->get_ctx().get_stack() + reserve;
+ /* stack->pointer is the end of the stack */
+ return (int8_t *) ctx->co->get_ctx().get_stack() + reserve;
#endif
}
-void* PHPCoroutine::stack_base(PHPContext *ctx)
-{
+void *PHPCoroutine::stack_base(PHPContext *ctx) {
#ifdef SW_USE_THREAD_CONTEXT
return nullptr;
#else
@@ -891,7 +890,7 @@ void* PHPCoroutine::stack_base(PHPContext *ctx)
return nullptr;
}
- return (void*)((uintptr_t)ctx->co->get_ctx().get_stack() + ctx->co->get_ctx().get_stack_size());
+ return (void *) ((uintptr_t) ctx->co->get_ctx().get_stack() + ctx->co->get_ctx().get_stack_size());
#endif
}
#endif /* ZEND_CHECK_STACK_LIMIT */
@@ -910,8 +909,7 @@ struct AutoloadQueue {
std::queue *queue;
};
-static zend_class_entry *swoole_coroutine_autoload(zend_string *name, zend_string *lc_name)
-{
+static zend_class_entry *swoole_coroutine_autoload(zend_string *name, zend_string *lc_name) {
auto current = Coroutine::get_current();
if (!current) {
return original_zend_autoload(name, lc_name);
diff --git a/ext-src/swoole_coroutine_scheduler.cc b/ext-src/swoole_coroutine_scheduler.cc
index c62ff66f583..5b4a530f672 100644
--- a/ext-src/swoole_coroutine_scheduler.cc
+++ b/ext-src/swoole_coroutine_scheduler.cc
@@ -290,11 +290,6 @@ static PHP_METHOD(swoole_coroutine_scheduler, parallel) {
static PHP_METHOD(swoole_coroutine_scheduler, start) {
SchedulerObject *s = scheduler_get_object(Z_OBJ_P(ZEND_THIS));
- if (SwooleTG.reactor) {
- php_swoole_fatal_error(
- E_WARNING, "eventLoop has already been created. unable to start %s", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS));
- RETURN_FALSE;
- }
if (s->started) {
php_swoole_fatal_error(
E_WARNING, "scheduler is started, unable to execute %s->start", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS));
diff --git a/ext-src/swoole_http2_server.cc b/ext-src/swoole_http2_server.cc
index 37acbbecdf3..b7e97c179bd 100644
--- a/ext-src/swoole_http2_server.cc
+++ b/ext-src/swoole_http2_server.cc
@@ -34,7 +34,7 @@ using HttpContext = swoole::http::Context;
using Http2Stream = Http2::Stream;
using Http2Session = Http2::Session;
-static std::unordered_map http2_sessions;
+static SW_THREAD_LOCAL std::unordered_map http2_sessions;
static bool http2_server_respond(HttpContext *ctx, const String *body);
static bool http2_server_send_range_file(HttpContext *ctx, swoole::http_server::StaticHandler *handler);
@@ -213,13 +213,8 @@ static bool http2_server_is_static_file(Server *serv, HttpContext *ctx) {
if (1 == tasks.size()) {
if (SW_HTTP_PARTIAL_CONTENT == handler.status_code) {
std::stringstream content_range;
- content_range << "bytes "
- << tasks[0].offset
- << "-"
- << (tasks[0].length + tasks[0].offset - 1)
- << "/"
- << handler.get_filesize()
- << "\r\n";
+ content_range << "bytes " << tasks[0].offset << "-" << (tasks[0].length + tasks[0].offset - 1) << "/"
+ << handler.get_filesize() << "\r\n";
auto content_range_str = content_range.str();
ctx->set_header(ZEND_STRL("Content-Range"), content_range_str.c_str(), content_range_str.length(), 0);
} else {
diff --git a/ext-src/swoole_http_response.cc b/ext-src/swoole_http_response.cc
index 9eb633d5e22..fdfe0c2b613 100644
--- a/ext-src/swoole_http_response.cc
+++ b/ext-src/swoole_http_response.cc
@@ -997,10 +997,10 @@ static void php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAMETERS, const
}
char *cookie = nullptr, *date = nullptr;
- size_t cookie_size = name_len + 1; // add 1 for null char
- cookie_size += 50; // strlen("; expires=Fri, 31-Dec-9999 23:59:59 GMT; Max-Age=0")
+ size_t cookie_size = name_len + 1; // add 1 for null char
+ cookie_size += 50; // strlen("; expires=Fri, 31-Dec-9999 23:59:59 GMT; Max-Age=0")
if (value_len == 0) {
- cookie_size += 8; // strlen("=deleted")
+ cookie_size += 8; // strlen("=deleted")
}
if (expires > 0) {
// Max-Age will be no longer than 12 digits since the
@@ -1008,22 +1008,22 @@ static void php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAMETERS, const
cookie_size += 11;
}
if (path_len > 0) {
- cookie_size += path_len + 7; // strlen("; path=")
+ cookie_size += path_len + 7; // strlen("; path=")
}
if (domain_len > 0) {
- cookie_size += domain_len + 9; // strlen("; domain=")
+ cookie_size += domain_len + 9; // strlen("; domain=")
}
if (secure) {
- cookie_size += 8; // strlen("; secure")
+ cookie_size += 8; // strlen("; secure")
}
if (httponly) {
- cookie_size += 10; // strlen("; httponly")
+ cookie_size += 10; // strlen("; httponly")
}
if (samesite_len > 0) {
- cookie_size += samesite_len + 11; // strlen("; samesite=")
+ cookie_size += samesite_len + 11; // strlen("; samesite=")
}
if (priority_len > 0) {
- cookie_size += priority_len + 11; // strlen("; priority=")
+ cookie_size += priority_len + 11; // strlen("; priority=")
}
if (value_len == 0) {
diff --git a/ext-src/swoole_http_server.cc b/ext-src/swoole_http_server.cc
index bca5454c9d7..b94b7a095ee 100644
--- a/ext-src/swoole_http_server.cc
+++ b/ext-src/swoole_http_server.cc
@@ -32,8 +32,8 @@ namespace WebSocket = swoole::websocket;
zend_class_entry *swoole_http_server_ce;
zend_object_handlers swoole_http_server_handlers;
-static std::queue queued_http_contexts;
-static std::unordered_map client_ips;
+static SW_THREAD_LOCAL std::queue queued_http_contexts;
+static SW_THREAD_LOCAL std::unordered_map client_ips;
static bool http_context_send_data(HttpContext *ctx, const char *data, size_t length);
static bool http_context_sendfile(HttpContext *ctx, const char *file, uint32_t l_file, off_t offset, size_t length);
@@ -394,10 +394,10 @@ bool swoole_http_server_onBeforeRequest(HttpContext *ctx) {
ctx->onBeforeRequest = nullptr;
ctx->onAfterResponse = swoole_http_server_onAfterResponse;
Server *serv = (Server *) ctx->private_data;
- SwooleWG.worker->concurrency++;
+ sw_worker()->concurrency++;
sw_atomic_add_fetch(&serv->gs->concurrency, 1);
swoole_trace("serv->gs->concurrency=%u, max_concurrency=%u", serv->gs->concurrency, serv->gs->max_concurrency);
- if (SwooleWG.worker->concurrency > serv->worker_max_concurrency) {
+ if (sw_worker()->concurrency > serv->worker_max_concurrency) {
swoole_trace_log(SW_TRACE_COROUTINE,
"exceed worker_max_concurrency[%u] limit, request[%p] queued",
serv->worker_max_concurrency,
@@ -412,13 +412,12 @@ bool swoole_http_server_onBeforeRequest(HttpContext *ctx) {
void swoole_http_server_onAfterResponse(HttpContext *ctx) {
ctx->onAfterResponse = nullptr;
Server *serv = (Server *) ctx->private_data;
- SwooleWG.worker->concurrency--;
+ sw_worker()->concurrency--;
sw_atomic_sub_fetch(&serv->gs->concurrency, 1);
swoole_trace("serv->gs->concurrency=%u, max_concurrency=%u", serv->gs->concurrency, serv->gs->max_concurrency);
if (!queued_http_contexts.empty()) {
HttpContext *ctx = queued_http_contexts.front();
- swoole_trace(
- "[POP 1] concurrency=%u, ctx=%p, request=%p", SwooleWG.worker->concurrency, ctx, ctx->request.zobject);
+ swoole_trace("[POP 1] concurrency=%u, ctx=%p, request=%p", sw_worker()->concurrency, ctx, ctx->request.zobject);
queued_http_contexts.pop();
swoole_event_defer(
[](void *private_data) {
diff --git a/ext-src/swoole_lock.cc b/ext-src/swoole_lock.cc
index 2c8961448c0..902dcf79535 100644
--- a/ext-src/swoole_lock.cc
+++ b/ext-src/swoole_lock.cc
@@ -50,7 +50,7 @@ static Lock *php_swoole_lock_get_ptr(zval *zobject) {
static Lock *php_swoole_lock_get_and_check_ptr(zval *zobject) {
Lock *lock = php_swoole_lock_get_ptr(zobject);
if (!lock) {
- php_swoole_fatal_error(E_ERROR, "you must call Lock constructor first");
+ php_swoole_fatal_error(E_ERROR, "must call constructor first");
}
return lock;
}
@@ -111,9 +111,7 @@ void php_swoole_lock_minit(int module_number) {
SW_SET_CLASS_CUSTOM_OBJECT(
swoole_lock, php_swoole_lock_create_object, php_swoole_lock_free_object, LockObject, std);
- zend_declare_class_constant_long(swoole_lock_ce, ZEND_STRL("FILELOCK"), Lock::FILE_LOCK);
zend_declare_class_constant_long(swoole_lock_ce, ZEND_STRL("MUTEX"), Lock::MUTEX);
- zend_declare_class_constant_long(swoole_lock_ce, ZEND_STRL("SEM"), Lock::SEM);
#ifdef HAVE_RWLOCK
zend_declare_class_constant_long(swoole_lock_ce, ZEND_STRL("RWLOCK"), Lock::RW_LOCK);
#endif
@@ -122,9 +120,7 @@ void php_swoole_lock_minit(int module_number) {
#endif
zend_declare_property_long(swoole_lock_ce, ZEND_STRL("errCode"), 0, ZEND_ACC_PUBLIC);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_FILELOCK", Lock::FILE_LOCK);
SW_REGISTER_LONG_CONSTANT("SWOOLE_MUTEX", Lock::MUTEX);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_SEM", Lock::SEM);
#ifdef HAVE_RWLOCK
SW_REGISTER_LONG_CONSTANT("SWOOLE_RWLOCK", Lock::RW_LOCK);
#endif
@@ -149,12 +145,6 @@ static PHP_METHOD(swoole_lock, __construct) {
}
switch (type) {
- case Lock::FILE_LOCK:
- case Lock::SEM:
- zend_throw_exception(
- swoole_exception_ce, "FileLock and SemLock is no longer supported, please use mutex lock", errno);
- RETURN_FALSE;
- break;
#ifdef HAVE_SPINLOCK
case Lock::SPIN_LOCK:
lock = new SpinLock(1);
@@ -166,9 +156,12 @@ static PHP_METHOD(swoole_lock, __construct) {
break;
#endif
case Lock::MUTEX:
- default:
lock = new Mutex(Mutex::PROCESS_SHARED);
break;
+ default:
+ zend_throw_exception(swoole_exception_ce, "lock type[%d] is not support", type);
+ RETURN_FALSE;
+ break;
}
php_swoole_lock_set_ptr(ZEND_THIS, lock);
RETURN_TRUE;
diff --git a/ext-src/swoole_mysql_coro.cc b/ext-src/swoole_mysql_coro.cc
deleted file mode 100644
index c388de802b1..00000000000
--- a/ext-src/swoole_mysql_coro.cc
+++ /dev/null
@@ -1,2279 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | Swoole |
- +----------------------------------------------------------------------+
- | Copyright (c) 2012-2018 The Swoole Group |
- +----------------------------------------------------------------------+
- | 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: Twosee |
- | Author: Tianfeng Han |
- +----------------------------------------------------------------------+
- */
-
-#include "php_swoole_cxx.h"
-#include "php_swoole_mysql_proto.h"
-
-#include "swoole_string.h"
-
-// see mysqlnd 'L64' macro redefined
-#undef L64
-
-SW_EXTERN_C_BEGIN
-#include "ext/hash/php_hash.h"
-#include "ext/hash/php_hash_sha.h"
-#include "ext/standard/php_math.h"
-#ifdef SW_USE_MYSQLND
-#include "ext/mysqlnd/mysqlnd.h"
-#include "ext/mysqlnd/mysqlnd_charset.h"
-#endif
-SW_EXTERN_C_END
-
-#include
-
-/* keep same with pdo and mysqli */
-#define MYSQLND_UNKNOWN_SQLSTATE "HY000"
-#define MYSQLND_SERVER_GONE "MySQL server has gone away"
-#define MYSQLND_CR_UNKNOWN_ERROR 2000
-#define MYSQLND_CR_CONNECTION_ERROR 2002
-#define MYSQLND_CR_SERVER_GONE_ERROR 2006
-#define MYSQLND_CR_OUT_OF_MEMORY 2008
-#define MYSQLND_CR_SERVER_LOST 2013
-#define MYSQLND_CR_COMMANDS_OUT_OF_SYNC 2014
-#define MYSQLND_CR_CANT_FIND_CHARSET 2019
-#define MYSQLND_CR_MALFORMED_PACKET 2027
-#define MYSQLND_CR_NOT_IMPLEMENTED 2054
-#define MYSQLND_CR_NO_PREPARE_STMT 2030
-#define MYSQLND_CR_PARAMS_NOT_BOUND 2031
-#define MYSQLND_CR_INVALID_PARAMETER_NO 2034
-#define MYSQLND_CR_INVALID_BUFFER_USE 2035
-
-using swoole::coroutine::Socket;
-
-namespace swoole {
-class MysqlStatement;
-class MysqlClient {
- public:
- /* session related {{{ */
- Socket *socket = nullptr;
- zval zsocket;
- zval zobject;
- Socket::timeout_controller *tc = nullptr;
-
- enum sw_mysql_state state = SW_MYSQL_STATE_CLOSED;
- bool quit = false;
- mysql::result_info result;
-
- std::unordered_map statements;
- MysqlStatement *statement = nullptr;
- /* }}} */
-
- std::string host = SW_MYSQL_DEFAULT_HOST;
- uint16_t port = SW_MYSQL_DEFAULT_PORT;
- bool ssl = false;
-
- std::string user = "root";
- std::string password = "root";
- std::string database = "test";
- char charset = SW_MYSQL_DEFAULT_CHARSET;
-
- double connect_timeout = network::Socket::default_connect_timeout;
- bool strict_type = false;
-
- inline int get_error_code() {
- return error_code;
- }
-
- inline const char *get_error_msg() {
- return error_msg.c_str();
- }
-
- inline void non_sql_error(int code, const char *msg) {
- error_code = code;
- error_msg = std_string::format("SQLSTATE[" MYSQLND_UNKNOWN_SQLSTATE "] [%d] %s", code, msg);
- }
-
- template
- inline void non_sql_error(int code, const char *format, Args... args) {
- error_code = code;
- error_msg = std_string::format(
- "SQLSTATE[" MYSQLND_UNKNOWN_SQLSTATE "] [%d] %s", code, std_string::format(format, args...).c_str());
- }
-
- void io_error() {
- if (state == SW_MYSQL_STATE_CLOSED) {
- non_sql_error(MYSQLND_CR_CONNECTION_ERROR, socket->errMsg);
- } else {
- non_sql_error(MYSQLND_CR_SERVER_GONE_ERROR,
- MYSQLND_SERVER_GONE "%s%s",
- socket->errCode ? " due to " : "",
- socket->errCode ? socket->errMsg : "");
- }
- /* don't send QUIT after IO error */
- quit = true;
- close();
- }
-
- void proto_error(const char *data, const enum sw_mysql_packet_types expected_type) {
- mysql::server_packet packet(data);
- non_sql_error(MYSQLND_CR_MALFORMED_PACKET,
- "Unexpected mysql packet length=%u, number=%u, type=%u, expected_type=%u",
- packet.header.length,
- packet.header.number,
- (uint8_t) data[SW_MYSQL_PACKET_HEADER_SIZE],
- expected_type);
- close();
- }
-
- void server_error(const char *data) {
- mysql::err_packet err_packet(data);
- error_code = err_packet.code;
- error_msg =
- std_string::format("SQLSTATE[%s] [%d] %s", err_packet.sql_state, err_packet.code, err_packet.msg.c_str());
- state = SW_MYSQL_STATE_IDLE;
- }
-
- inline bool get_fetch_mode() {
- return fetch_mode;
- }
-
- inline bool set_fetch_mode(bool v) {
- if (sw_unlikely(socket && v)) {
- non_sql_error(ENOTSUP, "Can not use fetch mode after the connection is established");
- return false;
- }
- fetch_mode = v;
- return true;
- }
-
- inline bool get_defer() {
- return defer;
- }
-
- inline bool set_defer(bool v) {
- // if (sw_unlikely(fetch_mode && v))
- // {
- // non_sql_error(ENOTSUP, "Can not use defer mode when fetch mode is on");
- // return false;
- // }
- defer = v;
- return true;
- }
-
- void add_timeout_controller(double timeout, const enum Socket::TimeoutType type) {
- if (sw_unlikely(!socket)) {
- return;
- }
- // Notice: `timeout > 0` is wrong, maybe -1
- if (timeout != 0) {
- SW_ASSERT(!tc);
- tc = new Socket::timeout_controller(socket, timeout, type);
- }
- }
-
- inline bool has_timedout(enum Socket::TimeoutType type) {
- return tc && tc->has_timedout(type);
- }
-
- void del_timeout_controller() {
- if (tc) {
- delete tc;
- tc = nullptr;
- }
- }
-
- bool connect(std::string host, uint16_t port, bool ssl);
-
- inline bool connect() {
- return connect(host, port, ssl);
- }
-
- inline bool is_connected() {
- return socket && socket->is_connected();
- }
-
- inline int get_fd() {
- return socket ? socket->get_fd() : -1;
- }
-
- inline bool check_connection() {
- if (sw_unlikely(!is_connected())) {
- non_sql_error(MYSQLND_CR_CONNECTION_ERROR, "%s or %s", strerror(ECONNRESET), strerror(ENOTCONN));
- return false;
- }
- return true;
- }
-
- inline bool check_liveness() {
- if (sw_unlikely(!check_connection())) {
- return false;
- }
- if (sw_unlikely(!socket->check_liveness())) {
- non_sql_error(MYSQLND_CR_SERVER_GONE_ERROR, MYSQLND_SERVER_GONE);
- close();
- return false;
- }
- return true;
- }
-
- inline bool is_writable() {
- return is_connected() && !socket->has_bound(SW_EVENT_WRITE);
- }
-
- bool is_available_for_new_request() {
- if (sw_unlikely(state != SW_MYSQL_STATE_IDLE && state != SW_MYSQL_STATE_CLOSED)) {
- if (socket) {
- socket->check_bound_co(SW_EVENT_RDWR);
- }
- non_sql_error(EINPROGRESS,
- "MySQL client is busy now on state#%d, "
- "please use recv/fetchAll/nextResult to get all unread data "
- "and wait for response then try again",
- state);
- return false;
- }
- if (sw_unlikely(!check_liveness())) {
- return false;
- } else {
- /* without unread data */
- String *buffer = socket->get_read_buffer();
- SW_ASSERT(buffer->length == (size_t) buffer->offset);
- buffer->clear();
- return true;
- }
- }
-
- const char *recv_packet();
-
- inline const char *recv_none_error_packet() {
- const char *data = recv_packet();
- if (sw_unlikely(data && mysql::server_packet::is_err(data))) {
- server_error(data);
- return nullptr;
- }
- return data;
- }
-
- inline const char *recv_eof_packet() {
- const char *data = recv_packet();
- if (sw_unlikely(data && !mysql::server_packet::is_eof(data))) {
- proto_error(data, SW_MYSQL_PACKET_EOF);
- return nullptr;
- }
-#ifdef SW_LOG_TRACE_OPEN
- mysql::eof_packet eof_packet(data);
-#endif
- return data;
- }
-
- inline bool send_raw(const char *data, size_t length) {
- if (sw_unlikely(!check_connection())) {
- return false;
- } else {
- if (sw_unlikely(has_timedout(Socket::TIMEOUT_WRITE))) {
- io_error();
- return false;
- }
- if (sw_unlikely(socket->send_all(data, length) != (ssize_t) length)) {
- io_error();
- return false;
- }
- return true;
- }
- }
-
- bool send_packet(mysql::client_packet *packet);
- bool send_command(enum sw_mysql_command command, const char *sql = nullptr, size_t length = 0);
- // just for internal
- void send_command_without_check(enum sw_mysql_command command, const char *sql = nullptr, size_t length = 0);
-
- void query(zval *return_value, const char *statement, size_t statement_length);
- void send_query_request(zval *return_value, const char *statement, size_t statement_length);
- void recv_query_response(zval *return_value);
- const char *handle_row_data_size(mysql::row_data *row_data, uint8_t size);
- bool handle_row_data_lcb(mysql::row_data *row_data);
- void handle_row_data_text(zval *return_value, mysql::row_data *row_data, mysql::field_packet *field);
- void handle_strict_type(zval *ztext, mysql::field_packet *field);
- void fetch(zval *return_value);
- void fetch_all(zval *return_value);
- void next_result(zval *return_value);
- bool recv();
-
- bool send_prepare_request(const char *statement, size_t statement_length);
- MysqlStatement *recv_prepare_response();
-
- void close();
- void socket_dtor();
-
- ~MysqlClient() {
- SW_ASSERT(statements.empty());
- close();
- }
-
- private:
- int error_code = 0;
- std::string error_msg = "";
-
- /* unable to support both features at the same time, so we have to set them by method {{{ */
- bool fetch_mode = false;
- bool defer = false;
- /* }}} */
-
- // recv data of specified length
- const char *recv_length(size_t need_length, const bool try_to_recycle = false);
- // usually mysql->connect = connect(TCP) + handshake
- bool handshake();
-};
-
-class MysqlStatement {
- public:
- std::string statement;
- mysql::statement info;
- mysql::result_info result;
-
- MysqlStatement(MysqlClient *client, const char *statement, size_t statement_length) : client(client) {
- this->statement = std::string(statement, statement_length);
- }
-
- inline MysqlClient *get_client() {
- return client;
- }
-
- inline int get_error_code() {
- return sw_likely(client) ? client->get_error_code() : error_code;
- }
-
- inline const char *get_error_msg() {
- return sw_likely(client) ? client->get_error_msg() : error_msg.c_str();
- }
-
- inline bool is_available() {
- if (sw_unlikely(!client)) {
- error_code = ECONNRESET;
- error_msg = "statement must to be recompiled after the connection is broken";
- return false;
- }
- return true;
- }
-
- inline bool is_available_for_new_request() {
- if (sw_unlikely(!is_available())) {
- return false;
- }
- if (sw_unlikely(!client->is_available_for_new_request())) {
- return false;
- }
- return true;
- }
-
- inline void add_timeout_controller(double timeout, const enum Socket::TimeoutType type) {
- if (sw_likely(client)) {
- client->add_timeout_controller(timeout, type);
- }
- }
-
- inline void del_timeout_controller() {
- if (sw_likely(client)) {
- client->del_timeout_controller();
- }
- }
-
- // [notify = false]: Client actively close
- inline void close(const bool notify = true) {
- if (client) {
- // if client point exists, socket is always available
- if (notify) {
- if (sw_likely(client->is_writable())) {
- char id[4];
- sw_mysql_int4store(id, info.id);
- client->send_command_without_check(SW_MYSQL_COM_STMT_CLOSE, id, sizeof(id));
- }
- client->statements.erase(info.id);
- } else {
- error_code = client->get_error_code();
- error_msg = client->get_error_msg();
- }
- client = nullptr;
- }
- }
-
- ~MysqlStatement() {
- close();
- }
-
- bool send_prepare_request();
- bool recv_prepare_response();
-
- void execute(zval *return_value, zval *params);
- void send_execute_request(zval *return_value, zval *params);
- void recv_execute_response(zval *return_value);
-
- void fetch(zval *return_value);
- void fetch_all(zval *return_value);
- void next_result(zval *return_value);
-
- private:
- MysqlClient *client = nullptr;
- int error_code = 0;
- std::string error_msg;
-};
-} // namespace swoole
-
-using Client = swoole::MysqlClient;
-using Statement = swoole::MysqlStatement;
-namespace mysql = swoole::mysql;
-
-static zend_class_entry *swoole_mysql_coro_ce;
-static zend_object_handlers swoole_mysql_coro_handlers;
-
-static zend_class_entry *swoole_mysql_coro_exception_ce;
-static zend_object_handlers swoole_mysql_coro_exception_handlers;
-
-static zend_class_entry *swoole_mysql_coro_statement_ce;
-static zend_object_handlers swoole_mysql_coro_statement_handlers;
-
-struct MysqlClientObject {
- Client *client;
- zend_object std;
-};
-
-struct MysqlStatementObject {
- Statement *statement;
- zend_object *zclient;
- zend_object std;
-};
-
-SW_EXTERN_C_BEGIN
-static PHP_METHOD(swoole_mysql_coro, __construct);
-static PHP_METHOD(swoole_mysql_coro, __destruct);
-static PHP_METHOD(swoole_mysql_coro, connect);
-static PHP_METHOD(swoole_mysql_coro, getDefer);
-static PHP_METHOD(swoole_mysql_coro, setDefer);
-static PHP_METHOD(swoole_mysql_coro, query);
-static PHP_METHOD(swoole_mysql_coro, fetch);
-static PHP_METHOD(swoole_mysql_coro, fetchAll);
-static PHP_METHOD(swoole_mysql_coro, nextResult);
-static PHP_METHOD(swoole_mysql_coro, prepare);
-static PHP_METHOD(swoole_mysql_coro, recv);
-static PHP_METHOD(swoole_mysql_coro, begin);
-static PHP_METHOD(swoole_mysql_coro, commit);
-static PHP_METHOD(swoole_mysql_coro, rollback);
-#ifdef SW_USE_MYSQLND
-static PHP_METHOD(swoole_mysql_coro, escape);
-#endif
-static PHP_METHOD(swoole_mysql_coro, close);
-
-static PHP_METHOD(swoole_mysql_coro_statement, execute);
-static PHP_METHOD(swoole_mysql_coro_statement, fetch);
-static PHP_METHOD(swoole_mysql_coro_statement, fetchAll);
-static PHP_METHOD(swoole_mysql_coro_statement, nextResult);
-static PHP_METHOD(swoole_mysql_coro_statement, recv);
-static PHP_METHOD(swoole_mysql_coro_statement, close);
-SW_EXTERN_C_END
-
-// clang-format off
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_void, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_optional_timeout, 0, 0, 0)
- ZEND_ARG_INFO(0, timeout)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_mysql_coro_connect, 0, 0, 0)
- ZEND_ARG_ARRAY_INFO(0, server_config, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_mysql_coro_query, 0, 0, 1)
- ZEND_ARG_INFO(0, sql)
- ZEND_ARG_INFO(0, timeout)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_mysql_coro_prepare, 0, 0, 1)
- ZEND_ARG_INFO(0, query)
- ZEND_ARG_INFO(0, timeout)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_mysql_coro_setDefer, 0, 0, 0)
- ZEND_ARG_INFO(0, defer)
-ZEND_END_ARG_INFO()
-
-#ifdef SW_USE_MYSQLND
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_mysql_coro_escape, 0, 0, 1)
- ZEND_ARG_INFO(0, string)
- ZEND_ARG_INFO(0, flags)
-ZEND_END_ARG_INFO()
-#endif
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_mysql_coro_statement_execute, 0, 0, 0)
- ZEND_ARG_INFO(0, params)
- ZEND_ARG_INFO(0, timeout)
-ZEND_END_ARG_INFO()
-
-static const zend_function_entry swoole_mysql_coro_methods[] =
-{
- PHP_ME(swoole_mysql_coro, __construct, arginfo_swoole_void, ZEND_ACC_PUBLIC | ZEND_ACC_DEPRECATED)
- PHP_ME(swoole_mysql_coro, __destruct, arginfo_swoole_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, getDefer, arginfo_swoole_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, setDefer, arginfo_swoole_mysql_coro_setDefer, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, connect, arginfo_swoole_mysql_coro_connect, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, query, arginfo_swoole_mysql_coro_query, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, fetch, arginfo_swoole_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, fetchAll, arginfo_swoole_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, nextResult, arginfo_swoole_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, prepare, arginfo_swoole_mysql_coro_prepare, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, recv, arginfo_swoole_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, begin, arginfo_swoole_optional_timeout, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, commit, arginfo_swoole_optional_timeout, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro, rollback, arginfo_swoole_optional_timeout, ZEND_ACC_PUBLIC)
-#ifdef SW_USE_MYSQLND
- PHP_ME(swoole_mysql_coro, escape, arginfo_swoole_mysql_coro_escape, ZEND_ACC_PUBLIC)
-#endif
- PHP_ME(swoole_mysql_coro, close, arginfo_swoole_void, ZEND_ACC_PUBLIC)
- PHP_FE_END
-};
-
-static const zend_function_entry swoole_mysql_coro_statement_methods[] =
-{
- PHP_ME(swoole_mysql_coro_statement, execute, arginfo_swoole_mysql_coro_statement_execute, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro_statement, fetch, arginfo_swoole_optional_timeout, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro_statement, fetchAll, arginfo_swoole_optional_timeout, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro_statement, nextResult, arginfo_swoole_optional_timeout, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro_statement, recv, arginfo_swoole_optional_timeout, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_mysql_coro_statement, close, arginfo_swoole_void, ZEND_ACC_PUBLIC)
- PHP_FE_END
-};
-// clang-format on
-
-void php_swoole_sha256(const char *str, int len, unsigned char *digest) {
- PHP_SHA256_CTX context;
- PHP_SHA256Init(&context);
- PHP_SHA256Update(&context, (unsigned char *) str, len);
- PHP_SHA256Final(digest, &context);
-}
-
-bool Client::connect(std::string host, uint16_t port, bool ssl) {
- if (socket && (host != this->host || port != this->port || ssl != this->ssl)) {
- close();
- }
- if (socket) {
- return true;
- }
- enum swSocketType socket_type;
- if (host.compare(0, 6, "unix:/", 0, 6) == 0) {
- host = host.substr(sizeof("unix:") - 1);
- host.erase(0, host.find_first_not_of('/') - 1);
- socket_type = SW_SOCK_UNIX_STREAM;
- } else if (host.find(':') != std::string::npos) {
- socket_type = SW_SOCK_TCP6;
- } else {
- socket_type = SW_SOCK_TCP;
- }
- auto object = php_swoole_create_socket(socket_type);
- if (UNEXPECTED(!object)) {
- non_sql_error(MYSQLND_CR_CONNECTION_ERROR, strerror(errno));
- return false;
- }
- ZVAL_OBJ(&zsocket, object);
- zend_update_property(Z_OBJCE_P(&zobject), SW_Z8_OBJ_P(&zobject), ZEND_STRL("socket"), &zsocket);
-
- socket = php_swoole_get_socket(&zsocket);
- socket->set_zero_copy(true);
- socket->set_dtor([this](Socket *) { socket_dtor(); });
-#ifdef SW_USE_OPENSSL
- if (ssl) {
- socket->enable_ssl_encrypt();
- }
-#endif
- socket->set_timeout(connect_timeout, Socket::TIMEOUT_CONNECT);
- add_timeout_controller(connect_timeout, Socket::TIMEOUT_ALL);
- if (!socket->connect(host, port)) {
- io_error();
- return false;
- }
- this->host = host;
- this->port = port;
-#ifdef SW_USE_OPENSSL
- this->ssl = ssl;
-#endif
- if (!handshake()) {
- close();
- return false;
- }
- state = SW_MYSQL_STATE_IDLE;
- quit = false;
- del_timeout_controller();
- return true;
-}
-
-const char *Client::recv_length(size_t need_length, const bool try_to_recycle) {
- if (sw_likely(check_connection())) {
- ssize_t retval;
- String *buffer = socket->get_read_buffer();
- off_t offset = buffer->offset; // save offset instead of buffer point (due to realloc)
- size_t read_n = buffer->length - buffer->offset; // readable bytes
- if (try_to_recycle && read_n == 0) {
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT,
- "mysql buffer will be recycled, length=%zu, offset=%jd",
- buffer->length,
- (intmax_t) offset);
- buffer->clear();
- offset = 0;
- }
- while (read_n < need_length) {
- if (sw_unlikely(has_timedout(Socket::TIMEOUT_READ))) {
- io_error();
- return nullptr;
- }
- if (sw_unlikely(buffer->length == buffer->size)) {
- /* offset + need_length = new size (min) */
- if (!buffer->extend(SW_MEM_ALIGNED_SIZE_EX(offset + need_length, swoole_pagesize()))) {
- non_sql_error(MYSQLND_CR_OUT_OF_MEMORY, strerror(ENOMEM));
- return nullptr;
- } else {
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "mysql buffer extend to %zu", buffer->size);
- }
- }
- retval = socket->recv(buffer->str + buffer->length, buffer->size - buffer->length);
- if (sw_unlikely(retval <= 0)) {
- io_error();
- return nullptr;
- }
- read_n += retval;
- buffer->length += retval;
- }
- buffer->offset += need_length;
- return buffer->str + offset;
- }
- return nullptr;
-}
-
-const char *Client::recv_packet() {
- const char *p;
- uint32_t length;
- p = recv_length(SW_MYSQL_PACKET_HEADER_SIZE, true);
- if (sw_unlikely(!p)) {
- return nullptr;
- }
- length = mysql::packet::get_length(p);
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "recv packet length=%u, number=%u", length, mysql::packet::get_number(p));
- p = recv_length(length);
- if (sw_unlikely(!p)) {
- return nullptr;
- }
- /* Notice: why we do this? because buffer maybe reallocated when recv data */
- return p - SW_MYSQL_PACKET_HEADER_SIZE;
-}
-
-bool Client::send_packet(mysql::client_packet *packet) {
- const char *data = packet->get_data();
- uint32_t length = SW_MYSQL_PACKET_HEADER_SIZE + packet->get_length();
- if (sw_likely(send_raw(data, length))) {
- return true;
- }
- return false;
-}
-
-bool Client::send_command(enum sw_mysql_command command, const char *sql, size_t length) {
- if (sw_likely(SW_MYSQL_PACKET_HEADER_SIZE + 1 + length <= swoole_pagesize())) {
- mysql::command_packet command_packet(command, sql, length);
- return send_raw(command_packet.get_data(), command_packet.get_data_length());
- } else {
- /* if the data is larger than page_size, copy memory to the kernel buffer multiple times is much faster */
- size_t send_s = SW_MIN(length, SW_MYSQL_MAX_PACKET_BODY_SIZE - 1), send_n = send_s, number = 0;
- mysql::command_packet command_packet(command);
- command_packet.set_header(1 + send_s, number++);
-
- if (sw_unlikely(!send_raw(command_packet.get_data(), SW_MYSQL_PACKET_HEADER_SIZE + 1)) ||
- !send_raw(sql, send_s)) {
- return false;
- }
- /* MySQL single packet size is 16M, we must subpackage */
- while (send_n < length) {
- send_s = length - send_n;
- send_s = SW_MIN(send_s, SW_MYSQL_MAX_PACKET_BODY_SIZE);
- command_packet.set_header(send_s, number++);
- if (sw_unlikely(!send_raw(command_packet.get_data(), SW_MYSQL_PACKET_HEADER_SIZE)) ||
- !send_raw(sql + send_n, send_s)) {
- return false;
- }
- send_n += send_s;
- }
- return true;
- }
-}
-
-void Client::send_command_without_check(enum sw_mysql_command command, const char *sql, size_t length) {
- mysql::command_packet command_packet(command, sql, length);
- (void) (socket && socket->send(command_packet.get_data(), command_packet.get_data_length()));
-}
-
-bool Client::handshake() {
- const char *data;
- // recv greeting pakcet
- if (sw_unlikely(!(data = recv_none_error_packet()))) {
- return false;
- }
- mysql::greeting_packet greeting_packet(data);
- // generate login packet
- do {
- mysql::login_packet login_packet(&greeting_packet, user, password, database, charset);
- if (sw_unlikely(!send_packet(&login_packet))) {
- return false;
- }
- } while (0);
- // recv auth switch request packet, 4 possible packet types
- switch (mysql::server_packet::parse_type(data = recv_packet())) {
- case SW_MYSQL_PACKET_AUTH_SWITCH_REQUEST: {
- mysql::auth_switch_request_packet request(data);
- mysql::auth_switch_response_packet response(&request, password);
- if (sw_unlikely(!send_packet(&response))) {
- return false;
- }
- break;
- }
- case SW_MYSQL_PACKET_AUTH_SIGNATURE_REQUEST: {
- mysql::auth_signature_request_packet request(data);
- if (sw_unlikely(!request.is_vaild())) {
- goto _proto_error;
- }
- if (sw_likely(!request.is_full_auth_required())) {
- break;
- }
- // no cache, need full auth with rsa key (openssl required)
-#ifdef SW_MYSQL_RSA_SUPPORT
- // tell the server we are prepared
- do {
- mysql::auth_signature_prepared_packet prepared(request.header.number + 1);
- if (sw_unlikely(!send_packet(&prepared))) {
- return false;
- }
- } while (0);
- // recv rsa key and encode the password
- do {
- if (sw_unlikely(!(data = recv_none_error_packet()))) {
- return false;
- }
- mysql::raw_data_packet raw_data_packet(data);
- mysql::auth_signature_response_packet response(
- &raw_data_packet, password, greeting_packet.auth_plugin_data);
- if (sw_unlikely(!send_packet(&response))) {
- return false;
- }
- } while (0);
- break;
-#else
- error_code = EPROTONOSUPPORT;
- error_msg = SW_MYSQL_NO_RSA_ERROR;
- return false;
-#endif
- }
- case SW_MYSQL_PACKET_OK: {
-#ifdef SW_LOG_TRACE_OPEN
- mysql::ok_packet ok_packet(data);
-#endif
- return true;
- }
- case SW_MYSQL_PACKET_ERR:
- server_error(data);
- return false;
- case SW_MYSQL_PACKET_NULL:
- // io_error
- return false;
- default:
- _proto_error:
- proto_error(data, SW_MYSQL_PACKET_AUTH_SWITCH_REQUEST);
- return false;
- }
- // maybe ok packet or err packet
- if (sw_unlikely(!(data = recv_none_error_packet()))) {
- return false;
- }
-#ifdef SW_LOG_TRACE_OPEN
- mysql::ok_packet ok_packet(data);
-#endif
- return true;
-}
-
-void Client::query(zval *return_value, const char *statement, size_t statement_length) {
- send_query_request(return_value, statement, statement_length);
- if (EXPECTED(!defer && Z_TYPE_P(return_value) == IS_TRUE)) {
- recv_query_response(return_value);
- }
-}
-
-void Client::send_query_request(zval *return_value, const char *statement, size_t statement_length) {
- if (sw_unlikely(!is_available_for_new_request())) {
- RETURN_FALSE;
- }
- if (sw_unlikely(!send_command(SW_MYSQL_COM_QUERY, statement, statement_length))) {
- RETURN_FALSE;
- }
- state = SW_MYSQL_STATE_QUERY;
- RETURN_TRUE;
-};
-
-void Client::recv_query_response(zval *return_value) {
- const char *data;
- if (sw_unlikely(!(data = recv_none_error_packet()))) {
- RETURN_FALSE;
- }
- if (mysql::server_packet::is_ok(data)) {
- mysql::ok_packet ok_packet(data);
- result.ok = ok_packet;
- state = ok_packet.server_status.more_results_exists() ? SW_MYSQL_STATE_QUERY_MORE_RESULTS : SW_MYSQL_STATE_IDLE;
- RETURN_TRUE;
- }
- do {
- mysql::lcb_packet lcb_packet(data);
- if (sw_unlikely(lcb_packet.length == 0)) {
- // is it possible?
- proto_error(data, SW_MYSQL_PACKET_FIELD);
- RETURN_FALSE;
- }
- result.alloc_fields(lcb_packet.length);
- for (uint32_t i = 0; i < lcb_packet.length; i++) {
- if (sw_unlikely(!(data = recv_packet()))) {
- RETURN_FALSE;
- }
- result.set_field(i, data);
- }
- } while (0);
- // expect eof
- if (sw_unlikely(!(data = recv_eof_packet()))) {
- RETURN_FALSE;
- }
- state = SW_MYSQL_STATE_QUERY_FETCH;
- if (get_fetch_mode()) {
- RETURN_TRUE;
- }
- fetch_all(return_value);
-}
-
-const char *Client::handle_row_data_size(mysql::row_data *row_data, uint8_t size) {
- const char *p, *data;
- SW_ASSERT(size < sizeof(row_data->stack_buffer));
- if (sw_unlikely(!(p = row_data->read(size)))) {
- uint8_t received = row_data->recv(row_data->stack_buffer, size);
- if (sw_unlikely(!(data = recv_packet()))) {
- return nullptr;
- }
- row_data->next_packet(data);
- received += row_data->recv(row_data->stack_buffer + received, size - received);
- if (sw_unlikely(received != size)) {
- proto_error(data, SW_MYSQL_PACKET_ROW_DATA);
- return nullptr;
- }
- p = row_data->stack_buffer;
- }
- return p;
-}
-
-bool Client::handle_row_data_lcb(mysql::row_data *row_data) {
- const char *p, *data;
- // recv 1 byte to get binary code size
- if (sw_unlikely(row_data->eof())) {
- if (sw_unlikely(!(data = recv_packet()))) {
- return false;
- }
- row_data->next_packet(data);
- if (sw_unlikely(row_data->eof())) {
- proto_error(data, SW_MYSQL_PACKET_ROW_DATA);
- return false;
- }
- }
- // decode lcb (use 0 to prevent read_ptr from moving)
- // recv "size" bytes to get binary code length
- p = handle_row_data_size(row_data, mysql::read_lcb_size(row_data->read(0)));
- if (sw_unlikely(!p)) {
- return false;
- }
- mysql::read_lcb(p, &row_data->text.length, &row_data->text.nul);
- return true;
-}
-
-void Client::handle_row_data_text(zval *return_value, mysql::row_data *row_data, mysql::field_packet *field) {
- const char *p, *data;
- if (sw_unlikely(!handle_row_data_lcb(row_data))) {
- RETURN_FALSE;
- }
- if (sw_unlikely(!(p = row_data->read(row_data->text.length)))) {
- size_t received = 0, required = row_data->text.length;
- if (required < sizeof(row_data->stack_buffer)) {
- p = handle_row_data_size(row_data, required);
- if (sw_unlikely(!p)) {
- RETURN_FALSE;
- }
- } else {
- zend_string *zstring = zend_string_alloc(required, 0);
- do {
- received += row_data->recv(ZSTR_VAL(zstring) + received, required - received);
- if (received == required) {
- break;
- }
- if (row_data->eof()) {
- if (sw_unlikely(!(data = recv_packet()))) {
- RETURN_FALSE;
- }
- row_data->next_packet(data);
- }
- } while (true);
- ZSTR_VAL(zstring)[ZSTR_LEN(zstring)] = '\0';
- RETVAL_STR(zstring);
- goto _return;
- }
- }
- if (row_data->text.nul || field->type == SW_MYSQL_TYPE_NULL) {
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "%.*s is null", field->name_length, field->name);
- RETURN_NULL();
- } else {
- RETVAL_STRINGL(p, row_data->text.length);
- _return:
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT,
- "%.*s=[%lu]%.*s%s",
- field->name_length,
- field->name,
- Z_STRLEN_P(return_value),
- (int) SW_MIN(32, Z_STRLEN_P(return_value)),
- Z_STRVAL_P(return_value),
- (Z_STRLEN_P(return_value) > 32 ? "..." : ""));
- }
-}
-
-void Client::handle_strict_type(zval *ztext, mysql::field_packet *field) {
- if (sw_likely(Z_TYPE_P(ztext) == IS_STRING)) {
- char *error;
- switch (field->type) {
- /* String */
- case SW_MYSQL_TYPE_TINY_BLOB:
- case SW_MYSQL_TYPE_MEDIUM_BLOB:
- case SW_MYSQL_TYPE_LONG_BLOB:
- case SW_MYSQL_TYPE_BLOB:
- case SW_MYSQL_TYPE_DECIMAL:
- case SW_MYSQL_TYPE_NEWDECIMAL:
- case SW_MYSQL_TYPE_BIT:
- case SW_MYSQL_TYPE_STRING:
- case SW_MYSQL_TYPE_VAR_STRING:
- case SW_MYSQL_TYPE_VARCHAR:
- case SW_MYSQL_TYPE_NEWDATE:
- case SW_MYSQL_TYPE_GEOMETRY:
- /* Date Time */
- case SW_MYSQL_TYPE_TIME:
- case SW_MYSQL_TYPE_YEAR:
- case SW_MYSQL_TYPE_TIMESTAMP:
- case SW_MYSQL_TYPE_DATETIME:
- case SW_MYSQL_TYPE_DATE:
- case SW_MYSQL_TYPE_JSON:
- return;
- /* Integer */
- case SW_MYSQL_TYPE_TINY:
- case SW_MYSQL_TYPE_SHORT:
- case SW_MYSQL_TYPE_INT24:
- case SW_MYSQL_TYPE_LONG:
- if (field->flags & SW_MYSQL_UNSIGNED_FLAG) {
- ulong_t uint = strtoul(Z_STRVAL_P(ztext), &error, 10);
- if (sw_likely(*error == '\0')) {
- zend_string_release(Z_STR_P(ztext));
- ZVAL_LONG(ztext, uint);
- }
- } else {
- long sint = strtol(Z_STRVAL_P(ztext), &error, 10);
- if (sw_likely(*error == '\0')) {
- zend_string_release(Z_STR_P(ztext));
- ZVAL_LONG(ztext, sint);
- }
- }
- break;
- case SW_MYSQL_TYPE_LONGLONG:
- if (field->flags & SW_MYSQL_UNSIGNED_FLAG) {
- unsigned long long ubigint = strtoull(Z_STRVAL_P(ztext), &error, 10);
- if (sw_likely(*error == '\0' && ubigint <= ZEND_LONG_MAX)) {
- zend_string_release(Z_STR_P(ztext));
- ZVAL_LONG(ztext, ubigint);
- }
- } else {
- long long sbigint = strtoll(Z_STRVAL_P(ztext), &error, 10);
- if (sw_likely(*error == '\0')) {
- zend_string_release(Z_STR_P(ztext));
- ZVAL_LONG(ztext, sbigint);
- }
- }
- break;
- case SW_MYSQL_TYPE_FLOAT:
- case SW_MYSQL_TYPE_DOUBLE: {
- double mdouble = strtod(Z_STRVAL_P(ztext), &error);
- if (sw_likely(*error == '\0')) {
- zend_string_release(Z_STR_P(ztext));
- ZVAL_DOUBLE(ztext, mdouble);
- }
- break;
- }
- default: {
- swoole_warning("unknown type[%d] for field [%.*s].", field->type, field->name_length, field->name);
- break;
- }
- }
- }
-}
-
-void Client::fetch(zval *return_value) {
- if (sw_unlikely(!is_connected())) {
- RETURN_FALSE;
- }
- if (sw_unlikely(state != SW_MYSQL_STATE_QUERY_FETCH)) {
- RETURN_NULL();
- }
- const char *data;
- if (sw_unlikely(!(data = recv_packet()))) {
- RETURN_FALSE;
- }
- if (mysql::server_packet::is_eof(data)) {
- mysql::eof_packet eof_packet(data);
- state =
- eof_packet.server_status.more_results_exists() ? SW_MYSQL_STATE_QUERY_MORE_RESULTS : SW_MYSQL_STATE_IDLE;
- RETURN_NULL();
- }
- do {
- mysql::row_data row_data(data);
- array_init_size(return_value, result.get_fields_length());
- for (uint32_t i = 0; i < result.get_fields_length(); i++) {
- mysql::field_packet *field = result.get_field(i);
- zval ztext;
- handle_row_data_text(&ztext, &row_data, field);
- if (sw_unlikely(Z_TYPE_P(&ztext) == IS_FALSE)) {
- zval_ptr_dtor(return_value);
- RETURN_FALSE;
- }
- if (strict_type) {
- handle_strict_type(&ztext, field);
- }
- add_assoc_zval_ex(return_value, field->name, field->name_length, &ztext);
- }
- } while (0);
-}
-
-void Client::fetch_all(zval *return_value) {
- array_init(return_value);
- while (true) {
- zval zrow;
- fetch(&zrow);
- if (sw_unlikely(ZVAL_IS_NULL(&zrow))) {
- // eof
- return;
- }
- if (sw_unlikely(Z_TYPE_P(&zrow) == IS_FALSE)) {
- // error
- zval_ptr_dtor(return_value);
- RETURN_FALSE;
- }
- (void) add_next_index_zval(return_value, &zrow);
- }
-}
-
-void Client::next_result(zval *return_value) {
- if (sw_unlikely(state == SW_MYSQL_STATE_QUERY_FETCH)) {
- // skip unread data
- fetch_all(return_value);
- zval_ptr_dtor(return_value);
- next_result(return_value);
- } else if (sw_likely(state == SW_MYSQL_STATE_QUERY_MORE_RESULTS)) {
- recv_query_response(return_value);
- } else if (state == SW_MYSQL_STATE_IDLE) {
- RETURN_NULL();
- } else {
- RETURN_FALSE;
- }
-}
-
-bool Client::send_prepare_request(const char *statement, size_t statement_length) {
- this->statement = new Statement(this, statement, statement_length);
- if (sw_unlikely(!this->statement->send_prepare_request())) {
- delete this->statement;
- this->statement = nullptr;
- return false;
- }
- return true;
-}
-
-void Client::socket_dtor() {
- zend_update_property_null(Z_OBJCE_P(&zobject), SW_Z8_OBJ_P(&zobject), ZEND_STRL("socket"));
- socket = nullptr;
- zval_ptr_dtor(&zsocket);
- ZVAL_NULL(&zsocket);
-}
-
-Statement *Client::recv_prepare_response() {
- if (sw_likely(state == SW_MYSQL_STATE_PREPARE)) {
- Statement *statement = this->statement;
- SW_ASSERT(statement != nullptr);
- this->statement = nullptr;
- if (sw_unlikely(!statement->recv_prepare_response())) {
- delete statement;
- return nullptr;
- }
- statements[statement->info.id] = statement;
- return statement;
- }
- return nullptr;
-}
-
-void Client::close() {
- state = SW_MYSQL_STATE_CLOSED;
- Socket *_socket = socket;
- if (_socket) {
- del_timeout_controller();
- if (!quit && is_writable()) {
- send_command_without_check(SW_MYSQL_COM_QUIT);
- quit = true;
- }
- // make statements non-available
- while (!statements.empty()) {
- auto i = statements.begin();
- i->second->close(false);
- statements.erase(i);
- }
- _socket->close();
- }
-}
-
-bool Statement::send_prepare_request() {
- if (sw_unlikely(!is_available_for_new_request())) {
- return false;
- }
- if (sw_unlikely(!client->send_command(SW_MYSQL_COM_STMT_PREPARE, statement.c_str(), statement.length()))) {
- return false;
- }
- client->state = SW_MYSQL_STATE_PREPARE;
- return true;
-}
-
-bool Statement::recv_prepare_response() {
- if (sw_unlikely(!is_available())) {
- return false;
- } else {
- client->state = SW_MYSQL_STATE_IDLE;
- }
- const char *data;
- if (sw_unlikely(!(data = client->recv_none_error_packet()))) {
- return false;
- }
- info = mysql::statement(data);
- if (sw_likely(info.param_count != 0)) {
- for (uint16_t i = info.param_count; i--;) {
- if (sw_unlikely(!(data = client->recv_packet()))) {
- return false;
- }
-#ifdef SW_LOG_TRACE_OPEN
- mysql::param_packet param_packet(data);
-#endif
- }
- if (sw_unlikely(!(data = client->recv_eof_packet()))) {
- return false;
- }
- }
- if (info.field_count != 0) {
- result.alloc_fields(info.field_count);
- for (uint16_t i = 0; i < info.field_count; i++) {
- if (sw_unlikely(!(data = client->recv_packet()))) {
- return false;
- }
- result.set_field(i, data);
- }
- if (sw_unlikely(!(data = client->recv_eof_packet()))) {
- return false;
- }
- }
- return true;
-}
-
-void Statement::execute(zval *return_value, zval *params) {
- send_execute_request(return_value, params);
- /* Notice: must check return_value first */
- if (EXPECTED(Z_TYPE_P(return_value) == IS_TRUE && !client->get_defer())) {
- recv_execute_response(return_value);
- }
-}
-
-void Statement::send_execute_request(zval *return_value, zval *params) {
- if (sw_unlikely(!is_available_for_new_request())) {
- RETURN_FALSE;
- }
-
- uint32_t param_count = params ? php_swoole_array_length(params) : 0;
-
- if (sw_unlikely(param_count != info.param_count)) {
- client->non_sql_error(MYSQLND_CR_INVALID_PARAMETER_NO,
- "Statement#%u expects %u parameter, %u given.",
- info.id,
- info.param_count,
- param_count);
- RETURN_FALSE;
- }
-
- String *buffer = client->socket->get_write_buffer();
- char *p = buffer->str;
-
- memset(p, 0, 5);
- // command
- buffer->str[4] = SW_MYSQL_COM_STMT_EXECUTE;
- buffer->length = 5;
- p += 5;
-
- // stmt.id
- sw_mysql_int4store(p, info.id);
- p += 4;
- // flags = CURSOR_TYPE_NO_CURSOR
- sw_mysql_int1store(p, 0);
- p += 1;
- // iteration_count
- sw_mysql_int4store(p, 1);
- p += 4;
- buffer->length += 9;
-
- // TODO: support more types
- if (param_count != 0) {
- // null bitmap
- size_t null_start_offset = p - buffer->str;
- unsigned int map_size = (param_count + 7) / 8;
- memset(p, 0, map_size);
- p += map_size;
- buffer->length += map_size;
-
- // rebind
- sw_mysql_int1store(p, 1);
- p += 1;
- buffer->length += 1;
-
- size_t type_start_offset = p - buffer->str;
- p += param_count * 2;
- buffer->length += param_count * 2;
-
- char stack_buffer[10];
- zend_ulong index = 0;
- zval *value;
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(params), value) {
- switch (client->strict_type ? Z_TYPE_P(value) : (IS_NULL == Z_TYPE_P(value) ? IS_NULL : IS_STRING)) {
- case IS_NULL:
- *((buffer->str + null_start_offset) + (index / 8)) |= (1UL << (index % 8));
- sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_NULL);
- break;
- case IS_TRUE:
- case IS_FALSE:
- case IS_LONG:
- sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_LONGLONG);
- sw_mysql_int8store(stack_buffer, zval_get_long(value));
- if (buffer->append(stack_buffer, mysql::get_static_type_size(SW_MYSQL_TYPE_LONGLONG)) < 0) {
- RETURN_FALSE;
- }
- break;
- case IS_DOUBLE:
- sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_DOUBLE);
- sw_mysql_doublestore(stack_buffer, zval_get_double(value));
- if (buffer->append(stack_buffer, mysql::get_static_type_size(SW_MYSQL_TYPE_DOUBLE)) < 0) {
- RETURN_FALSE;
- }
- break;
- default:
- zend::String str_value(value);
- uint8_t lcb_size = mysql::write_lcb(stack_buffer, str_value.len());
- sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_VAR_STRING);
- if (buffer->append(stack_buffer, lcb_size) < 0) {
- RETURN_FALSE;
- }
- if (buffer->append(str_value.val(), str_value.len()) < 0) {
- RETURN_FALSE;
- }
- }
- index++;
- }
- ZEND_HASH_FOREACH_END();
- }
- do {
- size_t length = buffer->length - SW_MYSQL_PACKET_HEADER_SIZE;
- size_t send_s = SW_MIN(length, SW_MYSQL_MAX_PACKET_BODY_SIZE);
- mysql::packet::set_header(buffer->str, send_s, 0);
- if (sw_unlikely(!client->send_raw(buffer->str, SW_MYSQL_PACKET_HEADER_SIZE + send_s))) {
- RETURN_FALSE;
- }
- if (sw_unlikely(length > SW_MYSQL_MAX_PACKET_BODY_SIZE)) {
- size_t send_n = SW_MYSQL_MAX_PACKET_BODY_SIZE, number = 1;
- /* MySQL single packet size is 16M, we must subpackage */
- while (send_n < length) {
- send_s = length - send_n;
- send_s = SW_MIN(send_s, SW_MYSQL_MAX_PACKET_BODY_SIZE);
- mysql::packet::set_header(buffer->str, send_s, number++);
- if (sw_unlikely(!client->send_raw(buffer->str, SW_MYSQL_PACKET_HEADER_SIZE)) ||
- !client->send_raw(buffer->str + SW_MYSQL_PACKET_HEADER_SIZE + send_n, send_s)) {
- RETURN_FALSE;
- }
- send_n += send_s;
- }
- }
- } while (0);
- client->state = SW_MYSQL_STATE_EXECUTE;
- RETURN_TRUE;
-}
-
-void Statement::recv_execute_response(zval *return_value) {
- if (sw_unlikely(!is_available())) {
- RETURN_FALSE;
- }
- const char *data;
- if (sw_unlikely(!(data = client->recv_none_error_packet()))) {
- RETURN_FALSE;
- }
- if (mysql::server_packet::is_ok(data)) {
- mysql::ok_packet ok_packet(data);
- result.ok = ok_packet;
- client->state =
- ok_packet.server_status.more_results_exists() ? SW_MYSQL_STATE_EXECUTE_MORE_RESULTS : SW_MYSQL_STATE_IDLE;
- RETURN_TRUE;
- }
- do {
- mysql::lcb_packet lcb_packet(data);
- if (sw_unlikely(lcb_packet.length == 0)) {
- // is it possible?
- client->proto_error(data, SW_MYSQL_PACKET_FIELD);
- RETURN_FALSE;
- }
- // although we have already known the field data when we prepared the statement,
- // we don't know if the data is always reliable, such as when we using stored procedure...
- // so we should not optimize here for the time being for stability
- result.alloc_fields(lcb_packet.length);
- for (size_t i = 0; i < result.get_fields_length(); i++) {
- if (sw_unlikely(!(data = client->recv_packet()))) {
- RETURN_FALSE;
- }
- result.set_field(i, data);
- }
- } while (0);
- // expect eof
- if (sw_unlikely(!(data = client->recv_eof_packet()))) {
- RETURN_FALSE;
- }
- client->state = SW_MYSQL_STATE_EXECUTE_FETCH;
- if (client->get_fetch_mode()) {
- RETURN_TRUE;
- }
- fetch_all(return_value);
-}
-
-void Statement::fetch(zval *return_value) {
- if (sw_unlikely(!is_available())) {
- RETURN_FALSE;
- }
- if (sw_unlikely(client->state != SW_MYSQL_STATE_EXECUTE_FETCH)) {
- RETURN_NULL();
- }
- const char *data;
- if (sw_unlikely(!(data = client->recv_packet()))) {
- RETURN_FALSE;
- }
- if (mysql::server_packet::is_eof(data)) {
- mysql::eof_packet eof_packet(data);
- client->state =
- eof_packet.server_status.more_results_exists() ? SW_MYSQL_STATE_EXECUTE_MORE_RESULTS : SW_MYSQL_STATE_IDLE;
- RETURN_NULL();
- }
- do {
- mysql::row_data row_data(data);
- uint32_t null_bitmap_size = mysql::null_bitmap::get_size(result.get_fields_length());
- mysql::null_bitmap null_bitmap(row_data.read(null_bitmap_size), null_bitmap_size);
-
- array_init_size(return_value, result.get_fields_length());
- for (uint32_t i = 0; i < result.get_fields_length(); i++) {
- mysql::field_packet *field = result.get_field(i);
-
- /* to check Null-Bitmap @see https://dev.mysql.com/doc/internals/en/null-bitmap.html */
- if (null_bitmap.is_null(i) || field->type == SW_MYSQL_TYPE_NULL) {
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "%.*s is null", field->name_length, field->name);
- add_assoc_null_ex(return_value, field->name, field->name_length);
- continue;
- }
-
- switch (field->type) {
- /* String */
- case SW_MYSQL_TYPE_TINY_BLOB:
- case SW_MYSQL_TYPE_MEDIUM_BLOB:
- case SW_MYSQL_TYPE_LONG_BLOB:
- case SW_MYSQL_TYPE_BLOB:
- case SW_MYSQL_TYPE_DECIMAL:
- case SW_MYSQL_TYPE_NEWDECIMAL:
- case SW_MYSQL_TYPE_BIT:
- case SW_MYSQL_TYPE_JSON:
- case SW_MYSQL_TYPE_STRING:
- case SW_MYSQL_TYPE_VAR_STRING:
- case SW_MYSQL_TYPE_VARCHAR:
- case SW_MYSQL_TYPE_NEWDATE:
- case SW_MYSQL_TYPE_GEOMETRY: {
- _add_string:
- zval ztext;
- client->handle_row_data_text(&ztext, &row_data, field);
- if (sw_unlikely(Z_TYPE_P(&ztext) == IS_FALSE)) {
- zval_ptr_dtor(return_value);
- RETURN_FALSE;
- }
- add_assoc_zval_ex(return_value, field->name, field->name_length, &ztext);
- break;
- }
- default: {
- const char *p = nullptr;
- uint8_t lcb = mysql::get_static_type_size(field->type);
- if (lcb == 0) {
- client->handle_row_data_lcb(&row_data);
- lcb = row_data.text.length;
- }
- p = client->handle_row_data_size(&row_data, lcb);
- if (sw_unlikely(!p)) {
- zval_ptr_dtor(return_value);
- RETURN_FALSE;
- }
- /* Date Time */
- switch (field->type) {
- case SW_MYSQL_TYPE_TIMESTAMP:
- case SW_MYSQL_TYPE_DATETIME: {
- std::string datetime = mysql::datetime(p, row_data.text.length, field->decimals);
- add_assoc_stringl_ex(
- return_value, field->name, field->name_length, (char *) datetime.c_str(), datetime.length());
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "%.*s=%s", field->name_length, field->name, datetime.c_str());
- break;
- }
- case SW_MYSQL_TYPE_TIME: {
- std::string time = mysql::time(p, row_data.text.length, field->decimals);
- add_assoc_stringl_ex(
- return_value, field->name, field->name_length, (char *) time.c_str(), time.length());
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "%.*s=%s", field->name_length, field->name, time.c_str());
- break;
- }
- case SW_MYSQL_TYPE_DATE: {
- std::string date = mysql::date(p, row_data.text.length);
- add_assoc_stringl_ex(
- return_value, field->name, field->name_length, (char *) date.c_str(), date.length());
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "%.*s=%s", field->name_length, field->name, date.c_str());
- break;
- }
- case SW_MYSQL_TYPE_YEAR: {
-#if PHP_VERSION_ID >= 80100
- std::string year = mysql::year(p, row_data.text.length);
- add_assoc_stringl_ex(
- return_value, field->name, field->name_length, (char *) year.c_str(), year.length());
-#else
- add_assoc_long_ex(return_value, field->name, field->name_length, sw_mysql_uint2korr2korr(p));
-#endif
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "%.*s=%d", field->name_length, field->name, sw_mysql_uint2korr2korr(p));
- break;
- }
- /* Number */
- case SW_MYSQL_TYPE_TINY:
- if (field->flags & SW_MYSQL_UNSIGNED_FLAG) {
- add_assoc_long_ex(return_value, field->name, field->name_length, *(uint8_t *) p);
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "%.*s=%u", field->name_length, field->name, *(uint8_t *) p);
- } else {
- add_assoc_long_ex(return_value, field->name, field->name_length, *(int8_t *) p);
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "%.*s=%d", field->name_length, field->name, *(int8_t *) p);
- }
- break;
- case SW_MYSQL_TYPE_SHORT:
- if (field->flags & SW_MYSQL_UNSIGNED_FLAG) {
- add_assoc_long_ex(return_value, field->name, field->name_length, *(uint16_t *) p);
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "%.*s=%u", field->name_length, field->name, *(uint16_t *) p);
- } else {
- add_assoc_long_ex(return_value, field->name, field->name_length, *(int16_t *) p);
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "%.*s=%d", field->name_length, field->name, *(int16_t *) p);
- }
- break;
- case SW_MYSQL_TYPE_INT24:
- case SW_MYSQL_TYPE_LONG:
- if (field->flags & SW_MYSQL_UNSIGNED_FLAG) {
- add_assoc_long_ex(return_value, field->name, field->name_length, *(uint32_t *) p);
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "%.*s=%u", field->name_length, field->name, *(uint32_t *) p);
- } else {
- add_assoc_long_ex(return_value, field->name, field->name_length, *(int32_t *) p);
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "%.*s=%d", field->name_length, field->name, *(int32_t *) p);
- }
- break;
- case SW_MYSQL_TYPE_LONGLONG:
- if (field->flags & SW_MYSQL_UNSIGNED_FLAG) {
- add_assoc_ulong_safe_ex(return_value, field->name, field->name_length, *(uint64_t *) p);
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "%.*s=%" PRIu64, field->name_length, field->name, *(uint64_t *) p);
- } else {
- add_assoc_long_ex(return_value, field->name, field->name_length, *(int64_t *) p);
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "%.*s=%" PRId64, field->name_length, field->name, *(int64_t *) p);
- }
- break;
- case SW_MYSQL_TYPE_FLOAT: {
- double dv = sw_php_math_round(*(float *) p, 7, PHP_ROUND_HALF_DOWN);
- add_assoc_double_ex(return_value, field->name, field->name_length, dv);
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "%.*s=%.7f", field->name_length, field->name, dv);
- } break;
- case SW_MYSQL_TYPE_DOUBLE: {
- add_assoc_double_ex(return_value, field->name, field->name_length, *(double *) p);
- swoole_trace_log(
- SW_TRACE_MYSQL_CLIENT, "%.*s=%.16f", field->name_length, field->name, *(double *) p);
- } break;
- default:
- swoole_warning("unknown type[%d] for field [%.*s].", field->type, field->name_length, field->name);
- goto _add_string;
- }
- }
- }
- }
- } while (0);
-}
-
-void Statement::fetch_all(zval *return_value) {
- if (sw_unlikely(!is_available())) {
- RETURN_FALSE;
- }
-
- zval zrow;
- array_init(return_value);
- while (true) {
- fetch(&zrow);
- if (sw_unlikely(ZVAL_IS_NULL(&zrow))) {
- // eof
- return;
- }
- if (sw_unlikely(Z_TYPE_P(&zrow) == IS_FALSE)) {
- // error
- zval_ptr_dtor(return_value);
- RETURN_FALSE;
- }
- (void) add_next_index_zval(return_value, &zrow);
- }
-}
-
-void Statement::next_result(zval *return_value) {
- if (sw_unlikely(!is_available())) {
- RETURN_FALSE;
- }
- if (sw_unlikely(client->state == SW_MYSQL_STATE_EXECUTE_FETCH)) {
- // skip unread data
- fetch_all(return_value);
- zval_ptr_dtor(return_value);
- next_result(return_value);
- } else if (sw_likely(client->state == SW_MYSQL_STATE_EXECUTE_MORE_RESULTS)) {
- recv_execute_response(return_value);
- } else if (client->state == SW_MYSQL_STATE_IDLE) {
- RETURN_NULL();
- } else {
- RETURN_FALSE;
- }
-}
-
-static sw_inline MysqlClientObject *mysql_coro_fetch_object(zend_object *obj) {
- return (MysqlClientObject *) ((char *) obj - swoole_mysql_coro_handlers.offset);
-}
-
-static sw_inline Client *mysql_coro_get_client(zval *zobject) {
- return mysql_coro_fetch_object(Z_OBJ_P(zobject))->client;
-}
-
-static void mysql_coro_free_object(zend_object *object) {
- MysqlClientObject *zmc = mysql_coro_fetch_object(object);
- delete zmc->client;
- zend_object_std_dtor(&zmc->std);
-}
-
-static zend_object *mysql_coro_create_object(zend_class_entry *ce) {
- MysqlClientObject *zmc = (MysqlClientObject *) zend_object_alloc(sizeof(MysqlClientObject), ce);
- zend_object_std_init(&zmc->std, ce);
- object_properties_init(&zmc->std, ce);
- zmc->std.handlers = &swoole_mysql_coro_handlers;
- zmc->client = new Client;
- ZVAL_OBJ(&zmc->client->zobject, &zmc->std);
- return &zmc->std;
-}
-
-static sw_inline MysqlStatementObject *mysql_coro_statement_fetch_object(zend_object *obj) {
- return (MysqlStatementObject *) ((char *) obj - swoole_mysql_coro_statement_handlers.offset);
-}
-
-static sw_inline Statement *mysql_coro_get_statement(zval *zobject) {
- return mysql_coro_statement_fetch_object(Z_OBJ_P(zobject))->statement;
-}
-
-static void mysql_coro_statement_free_object(zend_object *object) {
- MysqlStatementObject *zms = mysql_coro_statement_fetch_object(object);
- delete zms->statement;
- OBJ_RELEASE(zms->zclient);
- zend_object_std_dtor(&zms->std);
-}
-
-static sw_inline zend_object *mysql_coro_statement_create_object(zend_class_entry *ce,
- Statement *statement,
- zend_object *client) {
- zval zobject;
- MysqlStatementObject *zms = (MysqlStatementObject *) zend_object_alloc(sizeof(MysqlStatementObject), ce);
- zend_object_std_init(&zms->std, ce);
- object_properties_init(&zms->std, ce);
- zms->std.handlers = &swoole_mysql_coro_statement_handlers;
- ZVAL_OBJ(&zobject, &zms->std);
- zend_update_property_long(ce, SW_Z8_OBJ_P(&zobject), ZEND_STRL("id"), statement->info.id);
- zms->statement = statement;
- zms->zclient = client;
- GC_ADDREF(client);
- return &zms->std;
-}
-
-static sw_inline zend_object *mysql_coro_statement_create_object(Statement *statement, zend_object *client) {
- return mysql_coro_statement_create_object(swoole_mysql_coro_statement_ce, statement, client);
-}
-
-static zend_object *mysql_coro_statement_create_object(zend_class_entry *ce) {
- php_swoole_fatal_error(E_ERROR, "you must create mysql statement object by prepare method");
- return nullptr;
-}
-
-static sw_inline void mysql_coro_sync_error_properties(zval *zobject,
- int error_code,
- const char *error_msg,
- const bool connected = true) {
- SW_ASSERT(instanceof_function(Z_OBJCE_P(zobject), swoole_mysql_coro_ce) ||
- instanceof_function(Z_OBJCE_P(zobject), swoole_mysql_coro_statement_ce));
- zend_update_property_long(Z_OBJCE_P(zobject), SW_Z8_OBJ_P(zobject), ZEND_STRL("errno"), error_code);
- zend_update_property_string(Z_OBJCE_P(zobject), SW_Z8_OBJ_P(zobject), ZEND_STRL("error"), error_msg);
- if (!connected) {
- zend_update_property_bool(Z_OBJCE_P(zobject), SW_Z8_OBJ_P(zobject), ZEND_STRL("connected"), connected);
- }
-}
-
-static sw_inline void swoole_mysql_coro_sync_query_result_properties(zval *zobject, Client *mc, zval *return_value) {
- switch (Z_TYPE_P(return_value)) {
- case IS_TRUE: {
- mysql::ok_packet *ok_packet = &mc->result.ok;
- zend_update_property_long(
- Z_OBJCE_P(zobject), SW_Z8_OBJ_P(zobject), ZEND_STRL("affected_rows"), ok_packet->affected_rows);
- zend_update_property_long(
- Z_OBJCE_P(zobject), SW_Z8_OBJ_P(zobject), ZEND_STRL("insert_id"), ok_packet->last_insert_id);
- break;
- }
- case IS_FALSE: {
- mysql_coro_sync_error_properties(zobject, mc->get_error_code(), mc->get_error_msg());
- break;
- }
- default:
- break;
- }
-}
-
-static sw_inline void swoole_mysql_coro_sync_execute_error_properties(zval *zobject,
- int error_code,
- const char *error_msg,
- const bool connected = true) {
- mysql_coro_sync_error_properties(zobject, error_code, error_msg, connected);
-
- /* backward compatibility (sync error info to client) */
- zval zclient;
- ZVAL_OBJ(&zclient, mysql_coro_statement_fetch_object(Z_OBJ_P(zobject))->zclient);
- mysql_coro_sync_error_properties(&zclient, error_code, error_msg, connected);
-}
-
-static sw_inline void swoole_mysql_coro_sync_execute_result_properties(zval *zobject, zval *return_value) {
- MysqlStatementObject *zms = mysql_coro_statement_fetch_object(Z_OBJ_P(zobject));
- Statement *ms = zms->statement;
-
- switch (Z_TYPE_P(return_value)) {
- case IS_TRUE: {
- mysql::ok_packet *ok_packet = &ms->result.ok;
- zend_update_property_long(
- Z_OBJCE_P(zobject), SW_Z8_OBJ_P(zobject), ZEND_STRL("affected_rows"), ok_packet->affected_rows);
- zend_update_property_long(
- Z_OBJCE_P(zobject), SW_Z8_OBJ_P(zobject), ZEND_STRL("insert_id"), ok_packet->last_insert_id);
-
- /* backward compatibility (sync result info to client) */
- zval zclient;
- ZVAL_OBJ(&zclient, zms->zclient);
- zend_update_property_long(
- Z_OBJCE_P(&zclient), SW_Z8_OBJ_P(&zclient), ZEND_STRL("affected_rows"), ok_packet->affected_rows);
- zend_update_property_long(
- Z_OBJCE_P(&zclient), SW_Z8_OBJ_P(&zclient), ZEND_STRL("insert_id"), ok_packet->last_insert_id);
- break;
- }
- case IS_FALSE: {
- swoole_mysql_coro_sync_execute_error_properties(zobject, ms->get_error_code(), ms->get_error_msg());
- break;
- }
- default:
- break;
- }
-}
-
-void php_swoole_mysql_coro_minit(int module_number) {
- SW_INIT_CLASS_ENTRY(swoole_mysql_coro, "Swoole\\Coroutine\\MySQL", "Co\\MySQL", swoole_mysql_coro_methods);
- SW_SET_CLASS_NOT_SERIALIZABLE(swoole_mysql_coro);
- SW_SET_CLASS_CLONEABLE(swoole_mysql_coro, sw_zend_class_clone_deny);
- SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_mysql_coro, sw_zend_class_unset_property_deny);
- SW_SET_CLASS_CUSTOM_OBJECT(
- swoole_mysql_coro, mysql_coro_create_object, mysql_coro_free_object, MysqlClientObject, std);
-
-#if PHP_VERSION_ID >= 80200
- zend_add_parameter_attribute(
- (zend_function *) zend_hash_str_find_ptr(&swoole_mysql_coro_ce->function_table, SW_STRL("connect")),
- 0,
- ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER),
- 0);
-#endif
-
- SW_INIT_CLASS_ENTRY(swoole_mysql_coro_statement,
- "Swoole\\Coroutine\\MySQL\\Statement",
- "Co\\MySQL\\Statement",
- swoole_mysql_coro_statement_methods);
- SW_SET_CLASS_NOT_SERIALIZABLE(swoole_mysql_coro_statement);
- SW_SET_CLASS_CLONEABLE(swoole_mysql_coro_statement, sw_zend_class_clone_deny);
- SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_mysql_coro_statement, sw_zend_class_unset_property_deny);
- SW_SET_CLASS_CUSTOM_OBJECT(swoole_mysql_coro_statement,
- mysql_coro_statement_create_object,
- mysql_coro_statement_free_object,
- MysqlStatementObject,
- std);
-
- SW_INIT_CLASS_ENTRY_EX(swoole_mysql_coro_exception,
- "Swoole\\Coroutine\\MySQL\\Exception",
- "Co\\MySQL\\Exception",
- nullptr,
- swoole_exception);
- SW_SET_CLASS_NOT_SERIALIZABLE(swoole_mysql_coro_exception);
- SW_SET_CLASS_CLONEABLE(swoole_mysql_coro_exception, sw_zend_class_clone_deny);
- SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_mysql_coro_exception, sw_zend_class_unset_property_deny);
- SW_SET_CLASS_CREATE_WITH_ITS_OWN_HANDLERS(swoole_mysql_coro_exception);
-
- zend_declare_property_null(swoole_mysql_coro_ce, ZEND_STRL("socket"), ZEND_ACC_PRIVATE);
- zend_declare_property_null(swoole_mysql_coro_ce, ZEND_STRL("serverInfo"), ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_mysql_coro_ce, ZEND_STRL("sock"), -1, ZEND_ACC_PUBLIC);
- zend_declare_property_bool(swoole_mysql_coro_ce, ZEND_STRL("connected"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_mysql_coro_ce, ZEND_STRL("connect_errno"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_string(swoole_mysql_coro_ce, ZEND_STRL("connect_error"), "", ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_mysql_coro_ce, ZEND_STRL("affected_rows"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_mysql_coro_ce, ZEND_STRL("insert_id"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_string(swoole_mysql_coro_ce, ZEND_STRL("error"), "", ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_mysql_coro_ce, ZEND_STRL("errno"), 0, ZEND_ACC_PUBLIC);
-
- zend_declare_property_long(swoole_mysql_coro_statement_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_mysql_coro_statement_ce, ZEND_STRL("affected_rows"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_mysql_coro_statement_ce, ZEND_STRL("insert_id"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_string(swoole_mysql_coro_statement_ce, ZEND_STRL("error"), "", ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_mysql_coro_statement_ce, ZEND_STRL("errno"), 0, ZEND_ACC_PUBLIC);
-
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_UNKNOWN_ERROR", MYSQLND_CR_UNKNOWN_ERROR);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_CONNECTION_ERROR", MYSQLND_CR_CONNECTION_ERROR);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_SERVER_GONE_ERROR", MYSQLND_CR_SERVER_GONE_ERROR);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_OUT_OF_MEMORY", MYSQLND_CR_OUT_OF_MEMORY);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_SERVER_LOST", MYSQLND_CR_SERVER_LOST);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_COMMANDS_OUT_OF_SYNC", MYSQLND_CR_COMMANDS_OUT_OF_SYNC);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_CANT_FIND_CHARSET", MYSQLND_CR_CANT_FIND_CHARSET);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_MALFORMED_PACKET", MYSQLND_CR_MALFORMED_PACKET);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_NOT_IMPLEMENTED", MYSQLND_CR_NOT_IMPLEMENTED);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_NO_PREPARE_STMT", MYSQLND_CR_NO_PREPARE_STMT);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_PARAMS_NOT_BOUND", MYSQLND_CR_PARAMS_NOT_BOUND);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_INVALID_PARAMETER_NO", MYSQLND_CR_INVALID_PARAMETER_NO);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_MYSQLND_CR_INVALID_BUFFER_USE", MYSQLND_CR_INVALID_BUFFER_USE);
-}
-
-static PHP_METHOD(swoole_mysql_coro, __construct) {}
-static PHP_METHOD(swoole_mysql_coro, __destruct) {}
-
-static PHP_METHOD(swoole_mysql_coro, connect) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- zval *zserver_info = nullptr;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_ARRAY_EX(zserver_info, 1, 0)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- if (zserver_info) {
- HashTable *ht = Z_ARRVAL_P(zserver_info);
- zval *ztmp;
-
- if (php_swoole_array_get_value(ht, "host", ztmp)) {
- mc->host = std::string(zend::String(ztmp).val());
- } else {
- zend_throw_exception(swoole_mysql_coro_exception_ce, "Parameter [host] is required", EINVAL);
- RETURN_FALSE;
- }
- if (php_swoole_array_get_value(ht, "port", ztmp)) {
- mc->port = zval_get_long(ztmp);
- }
- if (php_swoole_array_get_value(ht, "ssl", ztmp)) {
- mc->ssl = zval_is_true(ztmp);
-#ifndef SW_USE_OPENSSL
- if (sw_unlikely(mc->ssl)) {
- zend_throw_exception_ex(
- swoole_mysql_coro_exception_ce,
- EPROTONOSUPPORT,
- "you must configure with `--enable-openssl` to support ssl connection when compiling Swoole");
- RETURN_FALSE;
- }
-#endif
- }
- if (php_swoole_array_get_value(ht, "user", ztmp)) {
- mc->user = std::string(zend::String(ztmp).val());
- } else {
- zend_throw_exception(swoole_mysql_coro_exception_ce, "Parameter [user] is required", EINVAL);
- RETURN_FALSE;
- }
- if (php_swoole_array_get_value(ht, "password", ztmp)) {
- mc->password = std::string(zend::String(ztmp).val());
- } else {
- zend_throw_exception(swoole_mysql_coro_exception_ce, "Parameter [password] is required", EINVAL);
- RETURN_FALSE;
- }
- if (php_swoole_array_get_value(ht, "database", ztmp)) {
- mc->database = std::string(zend::String(ztmp).val());
- } else {
- zend_throw_exception(swoole_mysql_coro_exception_ce, "Parameter [database] is required", EINVAL);
- RETURN_FALSE;
- }
- if (php_swoole_array_get_value(ht, "timeout", ztmp)) {
- mc->connect_timeout = zval_get_double(ztmp);
- }
- if (php_swoole_array_get_value(ht, "charset", ztmp)) {
- zend::String zstr_charset(ztmp);
- char charset = mysql::get_charset(zstr_charset.val());
- if (UNEXPECTED(charset < 0)) {
- zend_throw_exception_ex(
- swoole_mysql_coro_exception_ce, EINVAL, "Unknown charset [%s]", zstr_charset.val());
- RETURN_FALSE;
- }
- mc->charset = charset;
- }
- if (php_swoole_array_get_value(ht, "strict_type", ztmp)) {
- mc->strict_type = zval_is_true(ztmp);
- }
- if (php_swoole_array_get_value(ht, "fetch_mode", ztmp)) {
- if (UNEXPECTED(!mc->set_fetch_mode(zval_is_true(ztmp)))) {
- zend_throw_exception_ex(
- swoole_mysql_coro_exception_ce, mc->get_error_code(), "%s", mc->get_error_msg());
- RETURN_FALSE;
- }
- }
- }
- if (!mc->connect()) {
- zend_update_property_long(
- swoole_mysql_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("connect_errno"), mc->get_error_code());
- zend_update_property_string(
- swoole_mysql_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("connect_error"), mc->get_error_msg());
- RETURN_FALSE;
- }
- if (zserver_info && php_swoole_array_length(zserver_info) > 0) {
- php_array_merge(Z_ARRVAL_P(sw_zend_read_and_convert_property_array(
- swoole_mysql_coro_ce, ZEND_THIS, ZEND_STRL("serverInfo"), 0)),
- Z_ARRVAL_P(zserver_info));
- }
- zend_update_property_long(swoole_mysql_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("sock"), mc->get_fd());
- zend_update_property_bool(swoole_mysql_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("connected"), 1);
- RETURN_TRUE;
-}
-
-static PHP_METHOD(swoole_mysql_coro, getDefer) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- RETURN_BOOL(mc->get_defer());
-}
-
-static PHP_METHOD(swoole_mysql_coro, setDefer) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- zend_bool defer = 1;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_BOOL(defer)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- bool ret = mc->set_defer(defer);
- if (UNEXPECTED(!ret)) {
- zend_throw_exception_ex(swoole_mysql_coro_exception_ce, mc->get_error_code(), "%s", mc->get_error_msg());
- }
- RETURN_BOOL(ret);
-}
-
-static PHP_METHOD(swoole_mysql_coro, query) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- char *sql;
- size_t sql_length;
- double timeout = 0;
-
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_STRING(sql, sql_length)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- SW_CLIENT_PRESERVE_SOCKET(&mc->zsocket);
- mc->add_timeout_controller(timeout, Socket::TIMEOUT_RDWR);
- mc->query(return_value, sql, sql_length);
- mc->del_timeout_controller();
- swoole_mysql_coro_sync_query_result_properties(ZEND_THIS, mc, return_value);
-}
-
-static PHP_METHOD(swoole_mysql_coro, fetch) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- double timeout = 0;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- SW_CLIENT_PRESERVE_SOCKET(&mc->zsocket);
- mc->add_timeout_controller(timeout, Socket::TIMEOUT_RDWR);
- mc->fetch(return_value);
- mc->del_timeout_controller();
- if (sw_unlikely(Z_TYPE_P(return_value) == IS_FALSE)) {
- mysql_coro_sync_error_properties(ZEND_THIS, mc->get_error_code(), mc->get_error_msg(), mc->is_connected());
- }
-}
-
-static PHP_METHOD(swoole_mysql_coro, fetchAll) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- double timeout = 0;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- SW_CLIENT_PRESERVE_SOCKET(&mc->zsocket);
- mc->add_timeout_controller(timeout, Socket::TIMEOUT_RDWR);
- mc->fetch_all(return_value);
- mc->del_timeout_controller();
- if (sw_unlikely(Z_TYPE_P(return_value) == IS_FALSE)) {
- mysql_coro_sync_error_properties(ZEND_THIS, mc->get_error_code(), mc->get_error_msg(), mc->is_connected());
- }
-}
-
-static PHP_METHOD(swoole_mysql_coro, nextResult) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- double timeout = 0;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- SW_CLIENT_PRESERVE_SOCKET(&mc->zsocket);
- mc->add_timeout_controller(timeout, Socket::TIMEOUT_RDWR);
- mc->next_result(return_value);
- mc->del_timeout_controller();
- swoole_mysql_coro_sync_query_result_properties(ZEND_THIS, mc, return_value);
- if (Z_TYPE_P(return_value) == IS_TRUE) {
- if (mc->state == SW_MYSQL_STATE_IDLE) {
- // the end of procedure
- Z_TYPE_INFO_P(return_value) = mc->get_fetch_mode() ? IS_FALSE : IS_NULL;
- }
- }
-}
-
-static PHP_METHOD(swoole_mysql_coro, prepare) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- char *statement;
- size_t statement_length;
- double timeout = 0;
-
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_STRING(statement, statement_length)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- SW_CLIENT_PRESERVE_SOCKET(&mc->zsocket);
- mc->add_timeout_controller(timeout, Socket::TIMEOUT_RDWR);
- if (UNEXPECTED(!mc->send_prepare_request(statement, statement_length))) {
- _failed:
- mysql_coro_sync_error_properties(ZEND_THIS, mc->get_error_code(), mc->get_error_msg(), mc->is_connected());
- RETVAL_FALSE;
- } else if (UNEXPECTED(mc->get_defer())) {
- RETVAL_TRUE;
- } else {
- Statement *statement = mc->recv_prepare_response();
- if (UNEXPECTED(!statement)) {
- goto _failed;
- }
- RETVAL_OBJ(mysql_coro_statement_create_object(statement, Z_OBJ_P(ZEND_THIS)));
- }
- mc->del_timeout_controller();
-}
-
-static PHP_METHOD(swoole_mysql_coro, recv) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- double timeout = 0;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- if (UNEXPECTED(!mc->check_connection())) {
- mysql_coro_sync_error_properties(ZEND_THIS, mc->get_error_code(), mc->get_error_msg(), false);
- RETURN_FALSE;
- }
- SW_CLIENT_PRESERVE_SOCKET(&mc->zsocket);
- mc->add_timeout_controller(timeout, Socket::TIMEOUT_READ);
- switch (mc->state) {
- case SW_MYSQL_STATE_IDLE:
- mysql_coro_sync_error_properties(ZEND_THIS, ENOMSG, "no message to receive");
- RETVAL_FALSE;
- break;
- case SW_MYSQL_STATE_QUERY:
- mc->recv_query_response(return_value);
- break;
- case SW_MYSQL_STATE_PREPARE: {
- Statement *statement = mc->recv_prepare_response();
- if (UNEXPECTED(!statement)) {
- RETVAL_FALSE;
- } else {
- RETVAL_OBJ(mysql_coro_statement_create_object(statement, Z_OBJ_P(ZEND_THIS)));
- }
- break;
- }
- default:
- if (UNEXPECTED(mc->state & SW_MYSQL_COMMAND_FLAG_EXECUTE)) {
- mysql_coro_sync_error_properties(ZEND_THIS, EPERM, "please use statement to receive data");
- } else {
- mysql_coro_sync_error_properties(ZEND_THIS, EPERM, "please use fetch/fetchAll/nextResult to get result");
- }
- RETVAL_FALSE;
- }
- mc->del_timeout_controller();
-}
-
-static void swoole_mysql_coro_query_transcation(INTERNAL_FUNCTION_PARAMETERS,
- const char *command,
- size_t command_length) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- double timeout = 0;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- if (UNEXPECTED(mc->get_defer())) {
- zend_throw_exception_ex(
- swoole_mysql_coro_exception_ce,
- EPERM,
- "you should not query transaction when defer mode is on, if you want, please use `query('%s')` instead",
- command);
- RETURN_FALSE;
- }
- SW_CLIENT_PRESERVE_SOCKET(&mc->zsocket);
- mc->add_timeout_controller(timeout, Socket::TIMEOUT_RDWR);
- mc->query(return_value, command, command_length);
- mc->del_timeout_controller();
- swoole_mysql_coro_sync_query_result_properties(ZEND_THIS, mc, return_value);
-}
-
-static PHP_METHOD(swoole_mysql_coro, begin) {
- swoole_mysql_coro_query_transcation(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("BEGIN"));
-}
-
-static PHP_METHOD(swoole_mysql_coro, commit) {
- swoole_mysql_coro_query_transcation(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("COMMIT"));
-}
-
-static PHP_METHOD(swoole_mysql_coro, rollback) {
- swoole_mysql_coro_query_transcation(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("ROLLBACK"));
-}
-
-#ifdef SW_USE_MYSQLND
-static PHP_METHOD(swoole_mysql_coro, escape) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- char *str;
- size_t str_length;
- zend_long flags = 0;
-
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_STRING(str, str_length)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(flags)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- char *newstr = (char *) safe_emalloc(2, str_length + 1, 1);
- const MYSQLND_CHARSET *cset = mysqlnd_find_charset_nr(mc->charset);
- if (!cset) {
- php_swoole_fatal_error(E_ERROR, "unknown mysql charset[%d]", mc->charset);
- RETURN_FALSE;
- }
- zend_ulong newstr_len = mysqlnd_cset_escape_slashes(cset, newstr, str, str_length);
- if (newstr_len == (zend_ulong) ~0) {
- php_swoole_fatal_error(E_ERROR, "mysqlnd_cset_escape_slashes() failed");
- RETURN_FALSE;
- }
- RETVAL_STRINGL(newstr, newstr_len);
- efree(newstr);
- return;
-}
-#endif
-
-static PHP_METHOD(swoole_mysql_coro, close) {
- Client *mc = mysql_coro_get_client(ZEND_THIS);
- SW_CLIENT_PRESERVE_SOCKET(&mc->zsocket);
- mc->close();
- zend_update_property_bool(swoole_mysql_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("connected"), 0);
- RETURN_TRUE;
-}
-
-static PHP_METHOD(swoole_mysql_coro_statement, execute) {
- Statement *ms = mysql_coro_get_statement(ZEND_THIS);
- zval *params = nullptr;
- double timeout = 0;
-
- ZEND_PARSE_PARAMETERS_START(0, 2)
- Z_PARAM_OPTIONAL
- Z_PARAM_ARRAY_EX(params, 1, 0)
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- if (UNEXPECTED(!ms->is_available())) {
- swoole_mysql_coro_sync_execute_error_properties(ZEND_THIS, ms->get_error_code(), ms->get_error_msg(), false);
- RETURN_FALSE;
- }
-
- SW_CLIENT_PRESERVE_SOCKET(&ms->get_client()->zsocket);
-
- ms->add_timeout_controller(timeout, Socket::TIMEOUT_RDWR);
- ms->execute(return_value, params);
- ms->del_timeout_controller();
- swoole_mysql_coro_sync_execute_result_properties(ZEND_THIS, return_value);
-}
-
-static PHP_METHOD(swoole_mysql_coro_statement, fetch) {
- Statement *ms = mysql_coro_get_statement(ZEND_THIS);
- double timeout = 0;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- if (UNEXPECTED(!ms->is_available())) {
- swoole_mysql_coro_sync_execute_error_properties(ZEND_THIS, ms->get_error_code(), ms->get_error_msg(), false);
- RETURN_FALSE;
- }
-
- SW_CLIENT_PRESERVE_SOCKET(&ms->get_client()->zsocket);
-
- ms->add_timeout_controller(timeout, Socket::TIMEOUT_RDWR);
- ms->fetch(return_value);
- ms->del_timeout_controller();
- if (sw_unlikely(Z_TYPE_P(return_value) == IS_FALSE)) {
- swoole_mysql_coro_sync_execute_error_properties(ZEND_THIS, ms->get_error_code(), ms->get_error_msg());
- }
-}
-
-static PHP_METHOD(swoole_mysql_coro_statement, fetchAll) {
- Statement *ms = mysql_coro_get_statement(ZEND_THIS);
- double timeout = 0;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- if (UNEXPECTED(!ms->is_available())) {
- swoole_mysql_coro_sync_execute_error_properties(ZEND_THIS, ms->get_error_code(), ms->get_error_msg(), false);
- RETURN_FALSE;
- }
-
- SW_CLIENT_PRESERVE_SOCKET(&ms->get_client()->zsocket);
-
- ms->add_timeout_controller(timeout, Socket::TIMEOUT_RDWR);
- ms->fetch_all(return_value);
- ms->del_timeout_controller();
- if (sw_unlikely(Z_TYPE_P(return_value) == IS_FALSE)) {
- swoole_mysql_coro_sync_execute_error_properties(ZEND_THIS, ms->get_error_code(), ms->get_error_msg());
- }
-}
-
-static PHP_METHOD(swoole_mysql_coro_statement, nextResult) {
- Statement *ms = mysql_coro_get_statement(ZEND_THIS);
- double timeout = 0;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- if (UNEXPECTED(!ms->is_available())) {
- swoole_mysql_coro_sync_execute_error_properties(ZEND_THIS, ms->get_error_code(), ms->get_error_msg(), false);
- RETURN_FALSE;
- }
-
- SW_CLIENT_PRESERVE_SOCKET(&ms->get_client()->zsocket);
-
- ms->add_timeout_controller(timeout, Socket::TIMEOUT_RDWR);
- ms->next_result(return_value);
- ms->del_timeout_controller();
- swoole_mysql_coro_sync_execute_result_properties(ZEND_THIS, return_value);
- if (Z_TYPE_P(return_value) == IS_TRUE) {
- Client *mc = ms->get_client();
- if (mc->state == SW_MYSQL_STATE_IDLE) {
- // the end of procedure
- Z_TYPE_INFO_P(return_value) = mc->get_fetch_mode() ? IS_FALSE : IS_NULL;
- }
- }
-}
-
-static PHP_METHOD(swoole_mysql_coro_statement, recv) {
- Statement *ms = mysql_coro_get_statement(ZEND_THIS);
- double timeout = 0;
- enum sw_mysql_state state;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- if (UNEXPECTED(!ms->is_available())) {
- swoole_mysql_coro_sync_execute_error_properties(ZEND_THIS, ms->get_error_code(), ms->get_error_msg(), false);
- RETURN_FALSE;
- }
-
- SW_CLIENT_PRESERVE_SOCKET(&ms->get_client()->zsocket);
-
- ms->add_timeout_controller(timeout, Socket::TIMEOUT_READ);
- switch ((state = ms->get_client()->state)) {
- case SW_MYSQL_STATE_IDLE:
- swoole_mysql_coro_sync_execute_error_properties(ZEND_THIS, ENOMSG, "no message to receive");
- RETVAL_FALSE;
- break;
- case SW_MYSQL_STATE_EXECUTE:
- ms->recv_execute_response(return_value);
- break;
- default:
- if (UNEXPECTED(state & SW_MYSQL_COMMAND_FLAG_QUERY)) {
- swoole_mysql_coro_sync_execute_error_properties(ZEND_THIS, EPERM, "please use client to receive data");
- } else {
- swoole_mysql_coro_sync_execute_error_properties(
- ZEND_THIS, EPERM, "please use fetch/fetchAll/nextResult to get result");
- }
- RETVAL_FALSE;
- }
- ms->del_timeout_controller();
-}
-
-static PHP_METHOD(swoole_mysql_coro_statement, close) {
- Statement *ms = mysql_coro_get_statement(ZEND_THIS);
- if (UNEXPECTED(!ms->is_available())) {
- swoole_mysql_coro_sync_execute_error_properties(ZEND_THIS, ms->get_error_code(), ms->get_error_msg(), false);
- RETURN_FALSE;
- }
- SW_CLIENT_PRESERVE_SOCKET(&ms->get_client()->zsocket);
- ms->close();
- RETURN_TRUE;
-}
diff --git a/ext-src/swoole_mysql_proto.cc b/ext-src/swoole_mysql_proto.cc
deleted file mode 100644
index 61978817ddb..00000000000
--- a/ext-src/swoole_mysql_proto.cc
+++ /dev/null
@@ -1,744 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | Swoole |
- +----------------------------------------------------------------------+
- | Copyright (c) 2012-2015 The Swoole Group |
- +----------------------------------------------------------------------+
- | 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: Twosee |
- | Author: Tianfeng Han |
- +----------------------------------------------------------------------+
- */
-
-#include "php_swoole_mysql_proto.h"
-
-using namespace swoole::mysql;
-
-namespace swoole {
-namespace mysql {
-struct charset_t {
- uint nr;
- const char *name;
- const char *collation;
-};
-
-char get_charset(const char *name) {
- static const charset_t charsets[] = {
- {1, "big5", "big5_chinese_ci"},
- {3, "dec8", "dec8_swedish_ci"},
- {4, "cp850", "cp850_general_ci"},
- {6, "hp8", "hp8_english_ci"},
- {7, "koi8r", "koi8r_general_ci"},
- {8, "latin1", "latin1_swedish_ci"},
- {5, "latin1", "latin1_german1_ci"},
- {9, "latin2", "latin2_general_ci"},
- {2, "latin2", "latin2_czech_cs"},
- {10, "swe7", "swe7_swedish_ci"},
- {11, "ascii", "ascii_general_ci"},
- {12, "ujis", "ujis_japanese_ci"},
- {13, "sjis", "sjis_japanese_ci"},
- {16, "hebrew", "hebrew_general_ci"},
- {17, "filename", "filename"},
- {18, "tis620", "tis620_thai_ci"},
- {19, "euckr", "euckr_korean_ci"},
- {21, "latin2", "latin2_hungarian_ci"},
- {27, "latin2", "latin2_croatian_ci"},
- {22, "koi8u", "koi8u_general_ci"},
- {24, "gb2312", "gb2312_chinese_ci"},
- {25, "greek", "greek_general_ci"},
- {26, "cp1250", "cp1250_general_ci"},
- {28, "gbk", "gbk_chinese_ci"},
- {30, "latin5", "latin5_turkish_ci"},
- {31, "latin1", "latin1_german2_ci"},
- {15, "latin1", "latin1_danish_ci"},
- {32, "armscii8", "armscii8_general_ci"},
- {33, "utf8", "utf8_general_ci"},
- {35, "ucs2", "ucs2_general_ci"},
- {36, "cp866", "cp866_general_ci"},
- {37, "keybcs2", "keybcs2_general_ci"},
- {38, "macce", "macce_general_ci"},
- {39, "macroman", "macroman_general_ci"},
- {40, "cp852", "cp852_general_ci"},
- {41, "latin7", "latin7_general_ci"},
- {20, "latin7", "latin7_estonian_cs"},
- {57, "cp1256", "cp1256_general_ci"},
- {59, "cp1257", "cp1257_general_ci"},
- {63, "binary", "binary"},
- {97, "eucjpms", "eucjpms_japanese_ci"},
- {29, "cp1257", "cp1257_lithuanian_ci"},
- {31, "latin1", "latin1_german2_ci"},
- {34, "cp1250", "cp1250_czech_cs"},
- {42, "latin7", "latin7_general_cs"},
- {43, "macce", "macce_bin"},
- {44, "cp1250", "cp1250_croatian_ci"},
- {45, "utf8mb4", "utf8mb4_general_ci"},
- {46, "utf8mb4", "utf8mb4_bin"},
- {47, "latin1", "latin1_bin"},
- {48, "latin1", "latin1_general_ci"},
- {49, "latin1", "latin1_general_cs"},
- {51, "cp1251", "cp1251_general_ci"},
- {14, "cp1251", "cp1251_bulgarian_ci"},
- {23, "cp1251", "cp1251_ukrainian_ci"},
- {50, "cp1251", "cp1251_bin"},
- {52, "cp1251", "cp1251_general_cs"},
- {53, "macroman", "macroman_bin"},
- {54, "utf16", "utf16_general_ci"},
- {55, "utf16", "utf16_bin"},
- {56, "utf16le", "utf16le_general_ci"},
- {58, "cp1257", "cp1257_bin"},
- {60, "utf32", "utf32_general_ci"},
- {61, "utf32", "utf32_bin"},
- {62, "utf16le", "utf16le_bin"},
- {64, "armscii8", "armscii8_bin"},
- {65, "ascii", "ascii_bin"},
- {66, "cp1250", "cp1250_bin"},
- {67, "cp1256", "cp1256_bin"},
- {68, "cp866", "cp866_bin"},
- {69, "dec8", "dec8_bin"},
- {70, "greek", "greek_bin"},
- {71, "hebrew", "hebrew_bin"},
- {72, "hp8", "hp8_bin"},
- {73, "keybcs2", "keybcs2_bin"},
- {74, "koi8r", "koi8r_bin"},
- {75, "koi8u", "koi8u_bin"},
- {77, "latin2", "latin2_bin"},
- {78, "latin5", "latin5_bin"},
- {79, "latin7", "latin7_bin"},
- {80, "cp850", "cp850_bin"},
- {81, "cp852", "cp852_bin"},
- {82, "swe7", "swe7_bin"},
- {83, "utf8", "utf8_bin"},
- {84, "big5", "big5_bin"},
- {85, "euckr", "euckr_bin"},
- {86, "gb2312", "gb2312_bin"},
- {87, "gbk", "gbk_bin"},
- {88, "sjis", "sjis_bin"},
- {89, "tis620", "tis620_bin"},
- {90, "ucs2", "ucs2_bin"},
- {91, "ujis", "ujis_bin"},
- {92, "geostd8", "geostd8_general_ci"},
- {93, "geostd8", "geostd8_bin"},
- {94, "latin1", "latin1_spanish_ci"},
- {95, "cp932", "cp932_japanese_ci"},
- {96, "cp932", "cp932_bin"},
- {97, "eucjpms", "eucjpms_japanese_ci"},
- {98, "eucjpms", "eucjpms_bin"},
- {99, "cp1250", "cp1250_polish_ci"},
- {128, "ucs2", "ucs2_unicode_ci"},
- {129, "ucs2", "ucs2_icelandic_ci"},
- {130, "ucs2", "ucs2_latvian_ci"},
- {131, "ucs2", "ucs2_romanian_ci"},
- {132, "ucs2", "ucs2_slovenian_ci"},
- {133, "ucs2", "ucs2_polish_ci"},
- {134, "ucs2", "ucs2_estonian_ci"},
- {135, "ucs2", "ucs2_spanish_ci"},
- {136, "ucs2", "ucs2_swedish_ci"},
- {137, "ucs2", "ucs2_turkish_ci"},
- {138, "ucs2", "ucs2_czech_ci"},
- {139, "ucs2", "ucs2_danish_ci"},
- {140, "ucs2", "ucs2_lithuanian_ci"},
- {141, "ucs2", "ucs2_slovak_ci"},
- {142, "ucs2", "ucs2_spanish2_ci"},
- {143, "ucs2", "ucs2_roman_ci"},
- {144, "ucs2", "ucs2_persian_ci"},
- {145, "ucs2", "ucs2_esperanto_ci"},
- {146, "ucs2", "ucs2_hungarian_ci"},
- {147, "ucs2", "ucs2_sinhala_ci"},
- {148, "ucs2", "ucs2_german2_ci"},
- {149, "ucs2", "ucs2_croatian_ci"},
- {150, "ucs2", "ucs2_unicode_520_ci"},
- {151, "ucs2", "ucs2_vietnamese_ci"},
- {160, "utf32", "utf32_unicode_ci"},
- {161, "utf32", "utf32_icelandic_ci"},
- {162, "utf32", "utf32_latvian_ci"},
- {163, "utf32", "utf32_romanian_ci"},
- {164, "utf32", "utf32_slovenian_ci"},
- {165, "utf32", "utf32_polish_ci"},
- {166, "utf32", "utf32_estonian_ci"},
- {167, "utf32", "utf32_spanish_ci"},
- {168, "utf32", "utf32_swedish_ci"},
- {169, "utf32", "utf32_turkish_ci"},
- {170, "utf32", "utf32_czech_ci"},
- {171, "utf32", "utf32_danish_ci"},
- {172, "utf32", "utf32_lithuanian_ci"},
- {173, "utf32", "utf32_slovak_ci"},
- {174, "utf32", "utf32_spanish2_ci"},
- {175, "utf32", "utf32_roman_ci"},
- {176, "utf32", "utf32_persian_ci"},
- {177, "utf32", "utf32_esperanto_ci"},
- {178, "utf32", "utf32_hungarian_ci"},
- {179, "utf32", "utf32_sinhala_ci"},
- {180, "utf32", "utf32_german2_ci"},
- {181, "utf32", "utf32_croatian_ci"},
- {182, "utf32", "utf32_unicode_520_ci"},
- {183, "utf32", "utf32_vietnamese_ci"},
- {192, "utf8", "utf8_unicode_ci"},
- {193, "utf8", "utf8_icelandic_ci"},
- {194, "utf8", "utf8_latvian_ci"},
- {195, "utf8", "utf8_romanian_ci"},
- {196, "utf8", "utf8_slovenian_ci"},
- {197, "utf8", "utf8_polish_ci"},
- {198, "utf8", "utf8_estonian_ci"},
- {199, "utf8", "utf8_spanish_ci"},
- {200, "utf8", "utf8_swedish_ci"},
- {201, "utf8", "utf8_turkish_ci"},
- {202, "utf8", "utf8_czech_ci"},
- {203, "utf8", "utf8_danish_ci"},
- {204, "utf8", "utf8_lithuanian_ci"},
- {205, "utf8", "utf8_slovak_ci"},
- {206, "utf8", "utf8_spanish2_ci"},
- {207, "utf8", "utf8_roman_ci"},
- {208, "utf8", "utf8_persian_ci"},
- {209, "utf8", "utf8_esperanto_ci"},
- {210, "utf8", "utf8_hungarian_ci"},
- {211, "utf8", "utf8_sinhala_ci"},
- {212, "utf8", "utf8_german2_ci"},
- {213, "utf8", "utf8_croatian_ci"},
- {214, "utf8", "utf8_unicode_520_ci"},
- {215, "utf8", "utf8_vietnamese_ci"},
- {224, "utf8mb4", "utf8mb4_unicode_ci"},
- {225, "utf8mb4", "utf8mb4_icelandic_ci"},
- {226, "utf8mb4", "utf8mb4_latvian_ci"},
- {227, "utf8mb4", "utf8mb4_romanian_ci"},
- {228, "utf8mb4", "utf8mb4_slovenian_ci"},
- {229, "utf8mb4", "utf8mb4_polish_ci"},
- {230, "utf8mb4", "utf8mb4_estonian_ci"},
- {231, "utf8mb4", "utf8mb4_spanish_ci"},
- {232, "utf8mb4", "utf8mb4_swedish_ci"},
- {233, "utf8mb4", "utf8mb4_turkish_ci"},
- {234, "utf8mb4", "utf8mb4_czech_ci"},
- {235, "utf8mb4", "utf8mb4_danish_ci"},
- {236, "utf8mb4", "utf8mb4_lithuanian_ci"},
- {237, "utf8mb4", "utf8mb4_slovak_ci"},
- {238, "utf8mb4", "utf8mb4_spanish2_ci"},
- {239, "utf8mb4", "utf8mb4_roman_ci"},
- {240, "utf8mb4", "utf8mb4_persian_ci"},
- {241, "utf8mb4", "utf8mb4_esperanto_ci"},
- {242, "utf8mb4", "utf8mb4_hungarian_ci"},
- {243, "utf8mb4", "utf8mb4_sinhala_ci"},
- {244, "utf8mb4", "utf8mb4_german2_ci"},
- {245, "utf8mb4", "utf8mb4_croatian_ci"},
- {246, "utf8mb4", "utf8mb4_unicode_520_ci"},
- {247, "utf8mb4", "utf8mb4_vietnamese_ci"},
- {248, "gb18030", "gb18030_chinese_ci"},
- {249, "gb18030", "gb18030_bin"},
- {254, "utf8", "utf8_general_cs"},
- {0, nullptr, nullptr},
- };
- const charset_t *c = charsets;
- while (c[0].nr) {
- if (!strcasecmp(c->name, name)) {
- return c->nr;
- }
- ++c;
- }
- return -1;
-}
-
-// clang-format off
-uint8_t get_static_type_size(uint8_t type)
-{
- static const uint8_t map[] =
- {
- 0, // SW_MYSQL_TYPE_DECIMAL 0
- sizeof(int8_t), // SW_MYSQL_TYPE_TINY 1
- sizeof(int16_t), // SW_MYSQL_TYPE_SHORT 2
- sizeof(int32_t), // SW_MYSQL_TYPE_LONG 3
- sizeof(float), // SW_MYSQL_TYPE_FLOAT 4
- sizeof(double), // SW_MYSQL_TYPE_DOUBLE 5
- 0, // SW_MYSQL_TYPE_NULL 6
- 0, // SW_MYSQL_TYPE_TIMESTAMP 7
- sizeof(int64_t), // SW_MYSQL_TYPE_LONGLONG 8
- sizeof(int32_t), // SW_MYSQL_TYPE_INT24 9
- 0, // SW_MYSQL_TYPE_DATE 10
- 0, // SW_MYSQL_TYPE_TIME 11
- 0, // SW_MYSQL_TYPE_DATETIME 12
- sizeof(int16_t), // SW_MYSQL_TYPE_YEAR 13
- 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0
- };
- SW_ASSERT(sizeof(map) == UINT8_MAX + 1);
- return map[type];
-}
-// clang-format on
-
-static uint32_t sha1_password_with_nonce(char *buf, const char *nonce, const char *password) {
- char hash_0[20] = {};
- php_swoole_sha1(password, strlen(password), (uchar *) hash_0);
-
- char hash_1[20] = {};
- php_swoole_sha1(hash_0, sizeof(hash_0), (uchar *) hash_1);
-
- char str[40];
- memcpy(str, nonce, 20);
- memcpy(str + 20, hash_1, 20);
-
- char hash_2[20];
- php_swoole_sha1(str, sizeof(str), (uchar *) hash_2);
-
- char hash_3[20];
-
- int *a = (int *) hash_2;
- int *b = (int *) hash_0;
- int *c = (int *) hash_3;
-
- int i;
- for (i = 0; i < 5; i++) {
- c[i] = a[i] ^ b[i];
- }
- memcpy(buf, hash_3, 20);
- return 20;
-}
-
-static uint32_t sha256_password_with_nonce(char *buf, const char *nonce, const char *password) {
- // XOR(SHA256(password), SHA256(SHA256(SHA256(password)), nonce))
- char hashed[32], double_hashed[32];
- php_swoole_sha256(password, strlen(password), (unsigned char *) hashed);
- php_swoole_sha256(hashed, 32, (unsigned char *) double_hashed);
- char combined[32 + SW_MYSQL_NONCE_LENGTH]; // double-hashed + nonce
- memcpy(combined, double_hashed, 32);
- memcpy(combined + 32, nonce, SW_MYSQL_NONCE_LENGTH);
- char xor_bytes[32];
- php_swoole_sha256(combined, 32 + SW_MYSQL_NONCE_LENGTH, (unsigned char *) xor_bytes);
- int i;
- for (i = 0; i < 32; i++) {
- hashed[i] ^= xor_bytes[i];
- }
- memcpy(buf, hashed, 32);
- return 32;
-}
-
-/** @return: password length */
-static sw_inline uint32_t mysql_auth_encrypt_dispatch(char *buf,
- const std::string auth_plugin_name,
- const char *nonce,
- const char *password) {
- if (auth_plugin_name.length() == 0 || auth_plugin_name == "mysql_native_password") {
- // mysql_native_password is default
- return sha1_password_with_nonce(buf, nonce, password);
- } else if (auth_plugin_name == "caching_sha2_password") {
- return sha256_password_with_nonce(buf, nonce, password);
- } else {
- swoole_warning("Unknown auth plugin: %s", auth_plugin_name.c_str());
- return 0;
- }
-}
-
-eof_packet::eof_packet(const char *data) : server_packet(data) {
- swMysqlPacketDump(header.length, header.number, data, "EOF_Packet");
- // EOF_Packet = Packet header (4 bytes) + 0xFE + warning(2byte) + status(2byte)
- data += SW_MYSQL_PACKET_HEADER_SIZE;
- // int<1> header [fe] EOF header
- data += 1;
- // int<2> warnings number of warnings
- warning_count = sw_mysql_uint2korr2korr(data);
- data += 2;
- // int<2> status_flags Status Flags
- server_status = sw_mysql_uint2korr2korr(data);
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "EOF_Packet, warnings=%u, status_code=%u", warning_count, server_status.status);
-}
-
-ok_packet::ok_packet(const char *data) : server_packet(data) {
- swMysqlPacketDump(header.length, header.number, data, "OK_Packet");
- bool nul;
- data += SW_MYSQL_PACKET_HEADER_SIZE;
- // int<1> header [00] or [fe] the OK packet header
- data += 1;
- // int affected_rows affected rows
- data += read_lcb(data, &affected_rows, &nul);
- // int last_insert_id last insert id
- data += read_lcb(data, &last_insert_id, &nul);
- // int<2> status_flags status Flags
- server_status = sw_mysql_uint2korr2korr(data);
- data += 2;
- // int<2> warnings number of warnings
- warning_count = sw_mysql_uint2korr2korr(data);
- // p += 2;
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT,
- "OK_Packet, affected_rows=%" PRIu64 ", insert_id=%" PRIu64 ", status_flags=0x%08x, warnings=%u",
- affected_rows,
- last_insert_id,
- server_status.status,
- warning_count);
-}
-
-err_packet::err_packet(const char *data) : server_packet(data) {
- swMysqlPacketDump(header.length, header.number, data, "ERR_Packet");
- // ERR Packet = Packet header (4 bytes) + ERR Payload
- data += SW_MYSQL_PACKET_HEADER_SIZE;
- // int<1> header [ff] header of the ERR packet
- data += 1;
- // int<2> error_code error-code
- code = sw_mysql_uint2korr2korr(data);
- data += 2;
- // string[1] sql_state_marker # marker of the SQL State
- data += 1;
- // string[5] sql_state SQL State
- memcpy(sql_state, data, 5);
- sql_state[5] = '\0';
- data += 5;
- // string error_message human readable error message
- msg = std::string(data, header.length - 9);
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT,
- "ERR_Packet, error_code=%u, sql_state=%s, status_msg=[%s]",
- code,
- sql_state,
- msg.c_str());
-};
-
-greeting_packet::greeting_packet(const char *data) : server_packet(data) {
- swMysqlPacketDump(header.length, header.number, data, "Protocol::HandshakeGreeting");
- /**
- 1 [0a] protocol version
- string[NUL] server version
- 4 connection id
- string[8] auth-plugin-data-part-1
- 1 [00] filler
- 2 capability flags (lower 2 bytes)
- if more data in the packet:
- 1 character set
- 2 status flags
- 2 capability flags (upper 2 bytes)
- if capabilities & CLIENT_PLUGIN_AUTH {
- 1 length of auth-plugin-data
- } else {
- 1 [00]
- }
- string[10] reserved (all [00])
- if capabilities & CLIENT_SECURE_CONNECTION {
- string[$len] auth-plugin-data-part-2 ($len=MAX(13, length of auth-plugin-data - 8))
- if capabilities & CLIENT_PLUGIN_AUTH {
- string[NUL] auth-plugin name
- }
- */
- const char *p = data + SW_MYSQL_PACKET_HEADER_SIZE;
- // 1 [0a] protocol version
- protocol_version = *p;
- p++;
- // x server version
- server_version = std::string(p);
- p += server_version.length() + 1;
- // 4 connection id
- connection_id = *((int *) p);
- p += 4;
- // string[8] auth-plugin-data-part-1
- memcpy(auth_plugin_data, p, 8);
- p += 8;
- // 1 [00] filler
- filler = *p;
- p += 1;
- // 2 capability flags (lower 2 bytes)
- memcpy(((char *) (&capability_flags)), p, 2);
- p += 2;
-
- if (p < data + header.length) {
- // 1 character set
- charset = *p;
- p += 1;
- // 2 status flags
- memcpy(&status_flags, p, 2);
- p += 2;
- // 2 capability flags (upper 2 bytes)
- memcpy(((char *) (&capability_flags) + 2), p, 2);
- p += 2;
- // 1 auth plugin data length
- auth_plugin_data_length = (uint8_t) *p;
- p += 1;
- // x reserved
- memcpy(&reserved, p, sizeof(reserved));
- p += sizeof(reserved);
- if (capability_flags & SW_MYSQL_CLIENT_SECURE_CONNECTION) {
- uint8_t len = SW_MAX(13, auth_plugin_data_length - 8);
- memcpy(auth_plugin_data + 8, p, len);
- p += len;
- }
- if (capability_flags & SW_MYSQL_CLIENT_PLUGIN_AUTH) {
- auth_plugin_name = std::string(p, strlen(p));
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "use %s auth plugin", auth_plugin_name.c_str());
- }
- }
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT,
- "Server protocol=%d, version=%s, connection_id=%d, capabilites=0x%08x, status=%u, auth_plugin_name=%s, "
- "auth_plugin_data=L%u[%s]",
- protocol_version,
- server_version.c_str(),
- connection_id,
- capability_flags,
- status_flags.status,
- auth_plugin_name.c_str(),
- auth_plugin_data_length,
- auth_plugin_data);
-};
-
-login_packet::login_packet(greeting_packet *greeting_packet,
- const std::string &user,
- const std::string &password,
- std::string database,
- char charset) {
- char *p = data.body;
- uint32_t tint;
- // capability flags, CLIENT_PROTOCOL_41 always set
- tint = SW_MYSQL_CLIENT_LONG_PASSWORD | SW_MYSQL_CLIENT_PROTOCOL_41 | SW_MYSQL_CLIENT_SECURE_CONNECTION |
- SW_MYSQL_CLIENT_CONNECT_WITH_DB | SW_MYSQL_CLIENT_PLUGIN_AUTH | SW_MYSQL_CLIENT_MULTI_RESULTS;
- memcpy(p, &tint, sizeof(tint));
- p += sizeof(tint);
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "Client capabilites=0x%08x", tint);
- // max-packet size
- tint = 300;
- memcpy(p, &tint, sizeof(tint));
- p += sizeof(tint);
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "Client max packet=%u", tint);
- // use the server character_set when the character_set is not set.
- *p = charset ? charset : greeting_packet->charset;
- p += 1;
- // string[23] reserved (all [0])
- p += 23;
- // string[NUL] username
- strcpy(p, user.c_str());
- p += (user.length() + 1);
- // string[NUL] password
- if (password.length() > 0) {
- *p = mysql_auth_encrypt_dispatch(
- p + 1, greeting_packet->auth_plugin_name, greeting_packet->auth_plugin_data, password.c_str());
- } else {
- *p = 0;
- }
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT,
- "Client charset=%u, user=%s, password=%s, hased=L%d[%.*s], database=%s, auth_plugin_name=%s",
- charset,
- user.c_str(),
- password.c_str(),
- (int) *p,
- (int) *p,
- p + 1,
- database.c_str(),
- greeting_packet->auth_plugin_name.c_str());
- p += (((uint32_t) *p) + 1);
- // string[NUL] database
- strcpy(p, database.c_str());
- p += (database.length() + 1);
- // string[NUL] auth plugin name
- strcpy(p, greeting_packet->auth_plugin_name.c_str());
- p += (greeting_packet->auth_plugin_name.length() + 1);
- // packet header
- set_header(p - data.body, greeting_packet->header.number + 1);
- swMysqlPacketDump(get_length(), get_number(), get_data(), "Protocol::HandshakeLogin");
-}
-
-auth_switch_request_packet::auth_switch_request_packet(const char *data) : server_packet(data) {
- swMysqlPacketDump(header.length, header.number, data, "Protocol::AuthSwitchRequest");
- // 4 header
- data += SW_MYSQL_PACKET_HEADER_SIZE;
- // 1 type
- data += 1;
- // string[NUL] auth_method_name
- auth_method_name = std::string(data);
- data += (auth_method_name.length() + 1);
- // string[NUL] auth_method_data
- strlcpy(auth_method_data, data, sizeof(auth_method_data));
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "auth switch plugin name=%s", auth_method_name.c_str());
-}
-
-auth_switch_response_packet::auth_switch_response_packet(auth_switch_request_packet *req, const std::string &password) {
- // if auth switch is triggered, password can't be empty
- // create auth switch response packet
- set_header(mysql_auth_encrypt_dispatch(data.body, req->auth_method_name, req->auth_method_data, password.c_str()),
- req->header.number + 1);
- swMysqlPacketDump(get_length(), get_number(), get_data(), "Protocol::AuthSignatureResponse");
-}
-
-// Caching sha2 authentication. Public key request and send encrypted password
-// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
-auth_signature_response_packet::auth_signature_response_packet(raw_data_packet *raw_data_pakcet,
- const std::string &password,
- const char *auth_plugin_data) {
-#ifndef SW_MYSQL_RSA_SUPPORT
- {
- swoole_warning(SW_MYSQL_NO_RSA_ERROR);
-#else
- if (0) {
- _error:
-#endif
- data.body[0] = SW_MYSQL_AUTH_SIGNATURE_ERROR;
- set_header(1, raw_data_pakcet->header.number + 1);
- return;
- }
-#ifdef SW_MYSQL_RSA_SUPPORT
- const char *tmp = raw_data_pakcet->body;
- uint32_t rsa_public_key_length = raw_data_pakcet->header.length;
- while (tmp[0] != 0x2d) {
- tmp++; // ltrim
- rsa_public_key_length--;
- }
- char rsa_public_key[rsa_public_key_length + 1]; // rsa + '\0'
- memcpy((char *) rsa_public_key, tmp, rsa_public_key_length);
- rsa_public_key[rsa_public_key_length] = '\0';
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT,
- "rsa_public_key_length=%d;\nrsa_public_key=[%.*s]",
- rsa_public_key_length,
- rsa_public_key_length,
- rsa_public_key);
-
- size_t password_bytes_length = password.length() + 1;
- unsigned char password_bytes[password_bytes_length];
- // copy NUL terminator to password to stack
- strcpy((char *) password_bytes, password.c_str());
- // XOR the password bytes with the challenge
- for (size_t i = 0; i < password_bytes_length; i++) // include '\0' byte
- {
- password_bytes[i] ^= auth_plugin_data[i % SW_MYSQL_NONCE_LENGTH];
- }
-
- // prepare RSA public key
- BIO *bio = nullptr;
- RSA *public_rsa = nullptr;
- if (sw_unlikely((bio = BIO_new_mem_buf((void *) rsa_public_key, -1)) == nullptr)) {
- swoole_warning("BIO_new_mem_buf publicKey error!");
- goto _error;
- }
- // PEM_read_bio_RSA_PUBKEY
- ERR_clear_error();
- if (sw_unlikely((public_rsa = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr)) == nullptr)) {
- char err_buf[512];
- ERR_load_crypto_strings();
- ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf));
- swoole_warning("[PEM_read_bio_RSA_PUBKEY ERROR]: %s", err_buf);
- goto _error;
- }
- BIO_free_all(bio);
- // encrypt with RSA public key
- int rsa_len = RSA_size(public_rsa);
- unsigned char encrypt_msg[rsa_len];
- // RSA_public_encrypt
- ERR_clear_error();
- size_t flen = rsa_len - 42;
- flen = password_bytes_length > flen ? flen : password_bytes_length;
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT, "rsa_len=%d", rsa_len);
- if (sw_unlikely(RSA_public_encrypt(flen,
- (const unsigned char *) password_bytes,
- (unsigned char *) encrypt_msg,
- public_rsa,
- RSA_PKCS1_OAEP_PADDING) < 0)) {
- char err_buf[512];
- ERR_load_crypto_strings();
- ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf));
- swoole_warning("[RSA_public_encrypt ERROR]: %s", err_buf);
- goto _error;
- }
- RSA_free(public_rsa);
- memcpy(data.body, (char *) encrypt_msg, rsa_len); // copy rsa to buf
- set_header(rsa_len, raw_data_pakcet->header.number + 1);
- swMysqlPacketDump(get_length(), get_number(), get_data(), "Protocol::AuthSignatureResponse");
-#endif
-}
-
-void field_packet::parse(const char *data) {
- server_packet::parse(data);
- bool nul = false;
- char *p = body = new char[header.length];
- memcpy(body, data + SW_MYSQL_PACKET_HEADER_SIZE, header.length);
- // catalog
- p += read_lcb(p, &catalog_length, &nul);
- catalog = p;
- p += catalog_length;
- // database
- p += read_lcb(p, &database_length, &nul);
- database = p;
- p += database_length;
- // table
- p += read_lcb(p, &table_length, &nul);
- table = p;
- p += table_length;
- // origin table
- p += read_lcb(p, &org_table_length, &nul);
- org_table = p;
- p += org_table_length;
- // name
- p += read_lcb(p, &name_length, &nul);
- name = p;
- p += name_length;
- // origin table
- p += read_lcb(p, &org_name_length, &nul);
- org_name = p;
- p += org_name_length;
- // filler
- p += 1;
- // charset
- charset = sw_mysql_uint2korr2korr(p);
- p += 2;
- // binary length
- length = sw_mysql_uint2korr4korr(p);
- p += 4;
- // field type
- type = (uint8_t) *p;
- p += 1;
- // flags
- flags = sw_mysql_uint2korr2korr(p);
- p += 2;
- /* decimals */
- decimals = *p;
- p += 1;
- /* filler */
- p += 2;
- /* default - a priori facultatif */
- if (p < body + header.length) {
- p += read_lcb(p, &def_length, &nul);
- def = p;
- p += def_length;
- }
- swMysqlPacketDump(header.length, header.number, data, (*name == '?' ? "Protocol::Param" : "Protocol::Field"));
- swoole_trace_log(SW_TRACE_MYSQL_CLIENT,
- "catalog=%.*s, database=%.*s, table=%.*s, org_table=%.*s, name=%.*s, org_name=%.*s,"
- "charset=%u, binary_length=%" PRIu64 ", type=%u, flags=0x%08x, decimals=%u, def=[%.*s]",
- catalog_length,
- catalog,
- database_length,
- database,
- table_length,
- table,
- org_table_length,
- org_table,
- name_length,
- name,
- org_name_length,
- org_name,
- charset,
- length,
- type,
- flags,
- decimals,
- def_length,
- def);
-}
-} // namespace mysql
-} // namespace swoole
diff --git a/ext-src/swoole_oracle.cc b/ext-src/swoole_oracle.cc
index af7d90e4e92..d426d956977 100644
--- a/ext-src/swoole_oracle.cc
+++ b/ext-src/swoole_oracle.cc
@@ -49,7 +49,8 @@ sword swoole_oci_stmt_prepare(
OCIStmt *stmtp, OCIError *errhp, const OraText *stmt, ub4 stmt_len, ub4 language, ub4 mode) {
swoole_trace_log(SW_TRACE_CO_ORACLE, "oci_stmt_prepare");
sword result = 0;
- php_swoole_async(swoole_oracle_blocking, [&]() { result = OCIStmtPrepare(stmtp, errhp, stmt, stmt_len, language, mode); });
+ php_swoole_async(swoole_oracle_blocking,
+ [&]() { result = OCIStmtPrepare(stmtp, errhp, stmt, stmt_len, language, mode); });
return result;
}
@@ -64,7 +65,8 @@ sword swoole_oci_stmt_execute(OCISvcCtx *svchp,
ub4 mode) {
swoole_trace_log(SW_TRACE_CO_ORACLE, "oci_stmt_execute");
sword result = 0;
- php_swoole_async(swoole_oracle_blocking, [&]() { result = OCIStmtExecute(svchp, stmtp, errhp, iters, rowoff, snap_in, snap_out, mode); });
+ php_swoole_async(swoole_oracle_blocking,
+ [&]() { result = OCIStmtExecute(svchp, stmtp, errhp, iters, rowoff, snap_in, snap_out, mode); });
return result;
}
@@ -80,7 +82,8 @@ sword swoole_oci_stmt_fetch(OCIStmt *stmtp, OCIError *errhp, ub4 nrows, ub2 orie
sword swoole_oci_stmt_fetch2(OCIStmt *stmtp, OCIError *errhp, ub4 nrows, ub2 orientation, sb4 scrollOffset, ub4 mode) {
swoole_trace_log(SW_TRACE_CO_ORACLE, "oci_stmt_fetch2");
sword result = 0;
- php_swoole_async(swoole_oracle_blocking, [&]() { result = OCIStmtFetch2(stmtp, errhp, nrows, orientation, scrollOffset, mode); });
+ php_swoole_async(swoole_oracle_blocking,
+ [&]() { result = OCIStmtFetch2(stmtp, errhp, nrows, orientation, scrollOffset, mode); });
return result;
}
diff --git a/ext-src/swoole_pgsql.cc b/ext-src/swoole_pgsql.cc
index 08aa243713b..12f5d10400b 100644
--- a/ext-src/swoole_pgsql.cc
+++ b/ext-src/swoole_pgsql.cc
@@ -188,7 +188,8 @@ void swoole_pgsql_set_blocking(bool blocking) {
}
void php_swoole_pgsql_minit(int module_id) {
- if (zend_hash_str_find(&php_pdo_get_dbh_ce()->constants_table, ZEND_STRL("PGSQL_ATTR_DISABLE_PREPARES")) == nullptr) {
+ if (zend_hash_str_find(&php_pdo_get_dbh_ce()->constants_table, ZEND_STRL("PGSQL_ATTR_DISABLE_PREPARES")) ==
+ nullptr) {
REGISTER_PDO_CLASS_CONST_LONG("PGSQL_ATTR_DISABLE_PREPARES", PDO_PGSQL_ATTR_DISABLE_PREPARES);
REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_IDLE", (zend_long) PGSQL_TRANSACTION_IDLE);
REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_ACTIVE", (zend_long) PGSQL_TRANSACTION_ACTIVE);
diff --git a/ext-src/swoole_postgresql_coro.cc b/ext-src/swoole_postgresql_coro.cc
deleted file mode 100644
index e07d601b815..00000000000
--- a/ext-src/swoole_postgresql_coro.cc
+++ /dev/null
@@ -1,1945 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | 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: Zhenyu Wu <936321732@qq.com> |
- | Tianfeng Han |
- +----------------------------------------------------------------------+
- */
-
-#include "php_swoole_cxx.h"
-#include "swoole_reactor.h"
-#include "swoole_socket.h"
-
-#include
-
-#ifdef SW_USE_PGSQL
-
-#include
-#include
-
-BEGIN_EXTERN_C()
-#include "stubs/php_swoole_postgresql_coro_arginfo.h"
-END_EXTERN_C()
-
-namespace swoole {
-namespace postgresql {
-
-enum QueryType { NORMAL_QUERY, META_DATA, PREPARE };
-
-class Statement;
-
-class Object {
- public:
- PGconn *conn;
- network::Socket *socket;
- Coroutine *co;
- PGresult *result;
- zval *return_value;
- zval *object;
- zval _object;
- ConnStatusType status;
- Statement *statement;
- enum QueryType request_type;
- bool connected;
- bool ignore_notices;
- bool log_notices;
- size_t stmt_counter;
- bool request_success;
- HashTable *lob_streams;
-
- bool yield(zval *_return_value, EventType event, double timeout);
- bool wait_write_ready();
-};
-
-class Statement {
- public:
- zval *object;
- zval _object;
- Object *pg_object;
- PGresult *result;
- char *name;
- char *query;
- int row;
-};
-} // namespace postgresql
-} // namespace swoole
-
-#define PGSQL_ASSOC 1 << 0
-#define PGSQL_NUM 1 << 1
-#define PGSQL_BOTH (PGSQL_ASSOC | PGSQL_NUM)
-
-/* from postgresql/src/include/catalog/pg_type.h */
-#define BOOLOID 16
-#define BYTEAOID 17
-#define INT2OID 21
-#define INT4OID 23
-#define INT8OID 20
-#define TEXTOID 25
-#define OIDOID 26
-#define FLOAT4OID 700
-#define FLOAT8OID 701
-
-// extension part
-
-using swoole::Coroutine;
-using swoole::Event;
-using swoole::Reactor;
-using swoole::coroutine::System;
-using swoole::network::Socket;
-using PGObject = swoole::postgresql::Object;
-using PGStatement = swoole::postgresql::Statement;
-using PGQueryType = swoole::postgresql::QueryType;
-
-static zend_class_entry *swoole_postgresql_coro_ce, *swoole_postgresql_coro_statement_ce;
-static zend_object_handlers swoole_postgresql_coro_handlers, swoole_postgresql_coro_statement_handlers;
-
-struct PostgreSQLObject {
- PGObject *object;
- zend_object std;
-};
-
-static sw_inline PostgreSQLObject *php_swoole_postgresql_coro_fetch_object(zend_object *obj) {
- return (PostgreSQLObject *) ((char *) obj - swoole_postgresql_coro_handlers.offset);
-}
-
-static sw_inline PGObject *php_swoole_postgresql_coro_get_object(zval *zobject) {
- return php_swoole_postgresql_coro_fetch_object(Z_OBJ_P(zobject))->object;
-}
-
-static sw_inline zend_object *php_swoole_postgresql_coro_get_zend_object(PostgreSQLObject *obj) {
- return (zend_object *) ((char *) obj + swoole_postgresql_coro_handlers.offset);
-}
-
-struct PostgreSQLStatementObject {
- PGStatement *object;
- zend_object std;
-};
-
-static sw_inline PostgreSQLStatementObject *php_swoole_postgresql_coro_statement_fetch_object(zend_object *obj) {
- return (PostgreSQLStatementObject *) ((char *) obj - swoole_postgresql_coro_statement_handlers.offset);
-}
-
-static sw_inline PGStatement *php_swoole_postgresql_coro_statement_get_object(zval *zobject) {
- return php_swoole_postgresql_coro_statement_fetch_object(Z_OBJ_P(zobject))->object;
-}
-
-static int swoole_postgresql_coro_close(zval *zobject);
-
-static void php_swoole_postgresql_coro_free_object(zend_object *object) {
- PostgreSQLObject *postgresql_coro = php_swoole_postgresql_coro_fetch_object(object);
- if (postgresql_coro->object->conn) {
- zval zobject;
- ZVAL_OBJ(&zobject, object);
- swoole_postgresql_coro_close(&zobject);
- }
- delete postgresql_coro->object;
- zend_object_std_dtor(&postgresql_coro->std);
-}
-
-static zend_object *php_swoole_postgresql_coro_create_object(zend_class_entry *ce) {
- PostgreSQLObject *postgresql_coro = (PostgreSQLObject *) zend_object_alloc(sizeof(*postgresql_coro), ce);
- zend_object_std_init(&postgresql_coro->std, ce);
- object_properties_init(&postgresql_coro->std, ce);
- postgresql_coro->std.handlers = &swoole_postgresql_coro_handlers;
-
- Coroutine::get_current_safe();
-
- do {
- postgresql_coro->object = new PGObject();
- PGObject *object = postgresql_coro->object;
- object->object = &object->_object;
- ZVAL_OBJ(object->object, &postgresql_coro->std);
- } while (0);
-
- return &postgresql_coro->std;
-}
-
-static void php_swoole_postgresql_coro_statement_dtor_object(zend_object *object) {
- PGresult *pgsql_result;
- PostgreSQLStatementObject *postgresql_coro_statement = php_swoole_postgresql_coro_statement_fetch_object(object);
- PGStatement *statement = postgresql_coro_statement->object;
- if (statement->result) {
- PQclear(statement->result);
- statement->result = nullptr;
- }
-
- if (swoole_coroutine_is_in() && statement->pg_object->conn && statement->pg_object->connected && statement->name) {
- while ((pgsql_result = PQgetResult(statement->pg_object->conn))) {
- PQclear(pgsql_result);
- }
-
- statement->pg_object->request_type = PGQueryType::NORMAL_QUERY;
- if (0 == PQsendQuery(statement->pg_object->conn,
- swoole::std_string::format("DEALLOCATE %s", statement->name).c_str())) {
- char *err_msg = PQerrorMessage(statement->pg_object->conn);
- swoole_warning("error:[%s]", err_msg);
- }
- zval zv;
- if (statement->pg_object->wait_write_ready() &&
- statement->pg_object->yield(&zv, SW_EVENT_READ, Socket::default_read_timeout) &&
- statement->pg_object->result) {
- PQclear(statement->pg_object->result);
- statement->pg_object->result = nullptr;
- }
- }
-}
-
-static void php_swoole_postgresql_coro_statement_free_object(zend_object *object) {
- PostgreSQLStatementObject *postgresql_coro_statement = php_swoole_postgresql_coro_statement_fetch_object(object);
- PGStatement *statement = postgresql_coro_statement->object;
-
- if (statement->name) {
- efree(statement->name);
- statement->name = nullptr;
- }
- if (statement->query) {
- efree(statement->query);
- statement->query = nullptr;
- }
- OBJ_RELEASE(SW_Z8_OBJ_P(statement->pg_object->object));
- delete statement;
- zend_object_std_dtor(&postgresql_coro_statement->std);
-}
-
-static zend_object *php_swoole_postgresql_coro_statement_create_object(zend_class_entry *ce) {
- php_swoole_fatal_error(E_ERROR, "you must create postgresql statement object by prepare method");
- return nullptr;
-}
-
-static zend_object *php_swoole_postgresql_coro_statement_create_object(PGObject *pg_object) {
- PostgreSQLStatementObject *postgresql_coro_statement = (PostgreSQLStatementObject *) zend_object_alloc(
- sizeof(*postgresql_coro_statement), swoole_postgresql_coro_statement_ce);
- zend_object_std_init(&postgresql_coro_statement->std, swoole_postgresql_coro_statement_ce);
- object_properties_init(&postgresql_coro_statement->std, swoole_postgresql_coro_statement_ce);
- postgresql_coro_statement->std.handlers = &swoole_postgresql_coro_statement_handlers;
-
- Coroutine::get_current_safe();
-
- do {
- postgresql_coro_statement->object = new PGStatement();
- PGStatement *object = postgresql_coro_statement->object;
- object->pg_object = pg_object;
- object->object = &object->_object;
- ZVAL_OBJ(object->object, &postgresql_coro_statement->std);
- } while (0);
-
- GC_ADDREF(SW_Z8_OBJ_P(pg_object->object));
- return &postgresql_coro_statement->std;
-}
-
-static zend_object *php_swoole_postgresql_coro_statement_create_object(PGObject *pg_object, const char *query) {
- zend_object *zobject = php_swoole_postgresql_coro_statement_create_object(pg_object);
- PGStatement *stmt = php_swoole_postgresql_coro_statement_fetch_object(zobject)->object;
- stmt->query = estrdup(query);
- stmt->result = stmt->pg_object->result;
- return zobject;
-}
-
-static zend_object *php_swoole_postgresql_coro_statement_create_object(PGObject *pg_object,
- const char *stmtname,
- const char *query) {
- zend_object *zobject = php_swoole_postgresql_coro_statement_create_object(pg_object);
- PGStatement *stmt = php_swoole_postgresql_coro_statement_fetch_object(zobject)->object;
- stmt->name = estrdup(stmtname);
- stmt->query = estrdup(query);
- return zobject;
-}
-
-/* {{{ pdo_pgsql_create_lob_stream */
-struct swoole_pgsql_lob_self {
- zval zobject;
- PGconn *conn;
- int lfd;
- Oid oid;
-};
-
-static ssize_t pgsql_lob_write(php_stream *stream, const char *buf, size_t count) {
- struct swoole_pgsql_lob_self *self = (struct swoole_pgsql_lob_self *) stream->abstract;
- int result = 0;
- swoole::coroutine::async([&]() { result = lo_write(self->conn, self->lfd, (char *) buf, count); });
- if (result < 0) {
- php_swoole_error(E_WARNING, "lo_write() failed. %s", PQerrorMessage(self->conn));
- }
- return result;
-}
-
-static ssize_t pgsql_lob_read(php_stream *stream, char *buf, size_t count) {
- struct swoole_pgsql_lob_self *self = (struct swoole_pgsql_lob_self *) stream->abstract;
- int result = 0;
- swoole::coroutine::async([&]() { result = lo_read(self->conn, self->lfd, buf, count); });
- if (result < 0) {
- php_swoole_error(E_WARNING, "lo_read() failed. %s", PQerrorMessage(self->conn));
- }
- return result;
-}
-
-static int pgsql_lob_close(php_stream *stream, int close_handle) {
- struct swoole_pgsql_lob_self *self = (struct swoole_pgsql_lob_self *) stream->abstract;
- PGObject *object = php_swoole_postgresql_coro_get_object(&self->zobject);
-
- if (close_handle) {
- swoole::coroutine::async([&]() { lo_close(self->conn, self->lfd); });
- }
- zend_hash_index_del(object->lob_streams, php_stream_get_resource_id(stream));
- zval_ptr_dtor(&self->zobject);
- efree(self);
- return 0;
-}
-
-static int pgsql_lob_flush(php_stream *stream) {
- return 0;
-}
-
-static int pgsql_lob_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset) {
- struct swoole_pgsql_lob_self *self = (struct swoole_pgsql_lob_self *) stream->abstract;
- zend_off_t pos = 0;
- swoole::coroutine::async([&]() {
-#if defined(HAVE_PG_LO64) && defined(ZEND_ENABLE_ZVAL_LONG64)
- pos = lo_lseek64(self->conn, self->lfd, offset, whence);
-#else
- pos = lo_lseek(self->conn, self->lfd, offset, whence);
-#endif
- });
- *newoffset = pos;
- return pos >= 0 ? 0 : -1;
-}
-
-const php_stream_ops swoole_pgsql_lob_stream_ops = {pgsql_lob_write,
- pgsql_lob_read,
- pgsql_lob_close,
- pgsql_lob_flush,
- "swoole pgsql lob stream",
- pgsql_lob_seek,
- NULL,
- NULL,
- NULL};
-
-php_stream *swoole_pgsql_create_lob_stream(zval *zobject, int lfd, Oid oid) {
- php_stream *stm;
- struct swoole_pgsql_lob_self *self = (struct swoole_pgsql_lob_self *) ecalloc(1, sizeof(swoole_pgsql_lob_self));
- PGObject *object = php_swoole_postgresql_coro_get_object(zobject);
-
- ZVAL_COPY_VALUE(&self->zobject, object->object);
- self->lfd = lfd;
- self->oid = oid;
- self->conn = object->conn;
-
- stm = php_stream_alloc(&swoole_pgsql_lob_stream_ops, self, 0, "r+b");
-
- if (stm) {
- Z_ADDREF_P(&self->zobject);
- zend_hash_index_add_ptr(object->lob_streams, php_stream_get_resource_id(stm), stm->res);
- return stm;
- }
-
- efree(self);
- return NULL;
-}
-/* }}} */
-
-static PHP_METHOD(swoole_postgresql_coro, __construct);
-static PHP_METHOD(swoole_postgresql_coro, __destruct);
-static PHP_METHOD(swoole_postgresql_coro, connect);
-static PHP_METHOD(swoole_postgresql_coro, escape);
-static PHP_METHOD(swoole_postgresql_coro, escapeLiteral);
-static PHP_METHOD(swoole_postgresql_coro, escapeIdentifier);
-static PHP_METHOD(swoole_postgresql_coro, query);
-static PHP_METHOD(swoole_postgresql_coro, prepare);
-static PHP_METHOD(swoole_postgresql_coro, metaData);
-static PHP_METHOD(swoole_postgresql_coro, createLOB);
-static PHP_METHOD(swoole_postgresql_coro, openLOB);
-static PHP_METHOD(swoole_postgresql_coro, unlinkLOB);
-
-static PHP_METHOD(swoole_postgresql_coro_statement, execute);
-static PHP_METHOD(swoole_postgresql_coro_statement, fetchAll);
-static PHP_METHOD(swoole_postgresql_coro_statement, affectedRows);
-static PHP_METHOD(swoole_postgresql_coro_statement, numRows);
-static PHP_METHOD(swoole_postgresql_coro_statement, fieldCount);
-static PHP_METHOD(swoole_postgresql_coro_statement, fetchObject);
-static PHP_METHOD(swoole_postgresql_coro_statement, fetchAssoc);
-static PHP_METHOD(swoole_postgresql_coro_statement, fetchArray);
-static PHP_METHOD(swoole_postgresql_coro_statement, fetchRow);
-
-static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_type, int into_object);
-
-static int swoole_pgsql_coro_onReadable(Reactor *reactor, Event *event);
-static int swoole_pgsql_coro_onWritable(Reactor *reactor, Event *event);
-static int swoole_pgsql_coro_onError(Reactor *reactor, Event *event);
-static int swoole_postgresql_coro_close(zval *zobject);
-static int query_result_parse(PGObject *object);
-static int prepare_result_parse(PGObject *object);
-static int meta_data_result_parse(PGObject *object);
-static void _php_pgsql_free_params(char **params, int num_params);
-
-static void swoole_pgsql_result2array(PGresult *pg_result, zval *ret_array, long result_type);
-static PGresult *swoole_pgsql_get_result(PGObject *object);
-static void swoole_pgsql_close_lob_streams(PGObject *object);
-static inline bool swoole_pgsql_in_transaction(PGObject *object);
-
-// clang-format off
-static const zend_function_entry swoole_postgresql_coro_methods[] =
-{
- PHP_ME(swoole_postgresql_coro, __construct, arginfo_class_Swoole_Coroutine_PostgreSQL___construct, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro, connect, arginfo_class_Swoole_Coroutine_PostgreSQL_connect, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro, query, arginfo_class_Swoole_Coroutine_PostgreSQL_query, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro, prepare, arginfo_class_Swoole_Coroutine_PostgreSQL_prepare, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro, metaData, arginfo_class_Swoole_Coroutine_PostgreSQL_metaData, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro, escape, arginfo_class_Swoole_Coroutine_PostgreSQL_escape, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro, escapeLiteral, arginfo_class_Swoole_Coroutine_PostgreSQL_escapeLiteral, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro, escapeIdentifier, arginfo_class_Swoole_Coroutine_PostgreSQL_escapeIdentifier, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro, createLOB, arginfo_class_Swoole_Coroutine_PostgreSQL_createLOB, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro, openLOB, arginfo_class_Swoole_Coroutine_PostgreSQL_openLOB, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro, unlinkLOB, arginfo_class_Swoole_Coroutine_PostgreSQL_unlinkLOB, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro, __destruct, arginfo_class_Swoole_Coroutine_PostgreSQL___destruct, ZEND_ACC_PUBLIC)
- PHP_FE_END
-};
-// clang-format on
-
-// clang-format off
-static const zend_function_entry swoole_postgresql_coro_statement_methods[] =
-{
- PHP_ME(swoole_postgresql_coro_statement, execute, arginfo_class_Swoole_Coroutine_PostgreSQLStatement_execute, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro_statement, fetchAll, arginfo_class_Swoole_Coroutine_PostgreSQLStatement_fetchAll, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro_statement, affectedRows, arginfo_class_Swoole_Coroutine_PostgreSQLStatement_affectedRows, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro_statement, numRows, arginfo_class_Swoole_Coroutine_PostgreSQLStatement_numRows, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro_statement, fieldCount, arginfo_class_Swoole_Coroutine_PostgreSQLStatement_fieldCount, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro_statement, fetchObject, arginfo_class_Swoole_Coroutine_PostgreSQLStatement_fetchObject, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro_statement, fetchAssoc, arginfo_class_Swoole_Coroutine_PostgreSQLStatement_fetchAssoc, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro_statement, fetchArray, arginfo_class_Swoole_Coroutine_PostgreSQLStatement_fetchArray, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_postgresql_coro_statement, fetchRow, arginfo_class_Swoole_Coroutine_PostgreSQLStatement_fetchRow, ZEND_ACC_PUBLIC)
- PHP_FE_END
-};
-// clang-format on
-
-void php_swoole_postgresql_coro_minit(int module_number) {
- SW_INIT_CLASS_ENTRY(
- swoole_postgresql_coro, "Swoole\\Coroutine\\PostgreSQL", "Co\\PostgreSQL", swoole_postgresql_coro_methods);
- SW_SET_CLASS_NOT_SERIALIZABLE(swoole_postgresql_coro);
- SW_SET_CLASS_CLONEABLE(swoole_postgresql_coro, sw_zend_class_clone_deny);
- SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_postgresql_coro, sw_zend_class_unset_property_deny);
- SW_SET_CLASS_CUSTOM_OBJECT(swoole_postgresql_coro,
- php_swoole_postgresql_coro_create_object,
- php_swoole_postgresql_coro_free_object,
- PostgreSQLObject,
- std);
-
- zend_declare_property_null(swoole_postgresql_coro_ce, ZEND_STRL("error"), ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_postgresql_coro_ce, ZEND_STRL("errCode"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_postgresql_coro_ce, ZEND_STRL("resultStatus"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_null(swoole_postgresql_coro_ce, ZEND_STRL("resultDiag"), ZEND_ACC_PUBLIC);
- zend_declare_property_null(swoole_postgresql_coro_ce, ZEND_STRL("notices"), ZEND_ACC_PUBLIC);
-
- SW_INIT_CLASS_ENTRY(swoole_postgresql_coro_statement,
- "Swoole\\Coroutine\\PostgreSQLStatement",
- nullptr,
- swoole_postgresql_coro_statement_methods);
- SW_SET_CLASS_NOT_SERIALIZABLE(swoole_postgresql_coro_statement);
- SW_SET_CLASS_CLONEABLE(swoole_postgresql_coro_statement, sw_zend_class_clone_deny);
- SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_postgresql_coro_statement, sw_zend_class_unset_property_deny);
- SW_SET_CLASS_CUSTOM_OBJECT(swoole_postgresql_coro_statement,
- php_swoole_postgresql_coro_statement_create_object,
- php_swoole_postgresql_coro_statement_free_object,
- PostgreSQLStatementObject,
- std);
- SW_SET_CLASS_DTOR(swoole_postgresql_coro_statement, php_swoole_postgresql_coro_statement_dtor_object);
-
- zend_declare_property_null(swoole_postgresql_coro_statement_ce, ZEND_STRL("error"), ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_postgresql_coro_statement_ce, ZEND_STRL("errCode"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_postgresql_coro_statement_ce, ZEND_STRL("resultStatus"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_null(swoole_postgresql_coro_statement_ce, ZEND_STRL("resultDiag"), ZEND_ACC_PUBLIC);
- zend_declare_property_null(swoole_postgresql_coro_statement_ce, ZEND_STRL("notices"), ZEND_ACC_PUBLIC);
-
- SW_REGISTER_LONG_CONSTANT("SW_PGSQL_ASSOC", PGSQL_ASSOC);
- SW_REGISTER_LONG_CONSTANT("SW_PGSQL_NUM", PGSQL_NUM);
- SW_REGISTER_LONG_CONSTANT("SW_PGSQL_BOTH", PGSQL_BOTH);
-}
-
-static char *_php_pgsql_trim_message(const char *message, size_t *len) {
- size_t i = strlen(message);
- if (i > 2 && (message[i - 2] == '\r' || message[i - 2] == '\n') && message[i - 1] == '.') {
- --i;
- }
- while (i > 1 && (message[i - 1] == '\r' || message[i - 1] == '\n')) {
- --i;
- }
- if (len) {
- *len = i;
- }
- return estrndup(message, i);
-}
-
-static void _php_pgsql_notice_handler(void *resource_id, const char *message) {
- zval *notices;
- char *trimed_message;
- size_t trimed_message_len;
- PGObject *object = (PGObject *) resource_id;
-
- if (!object->ignore_notices) {
- notices = sw_zend_read_and_convert_property_array(
- swoole_postgresql_coro_ce, &object->_object, ZEND_STRL("notices"), 0);
-
- trimed_message = _php_pgsql_trim_message(message, &trimed_message_len);
- if (object->log_notices) {
- php_error_docref(nullptr, E_NOTICE, "%s", trimed_message);
- }
- add_next_index_stringl(notices, trimed_message, trimed_message_len);
- efree(trimed_message);
- }
-}
-
-static PHP_METHOD(swoole_postgresql_coro, __construct) {}
-
-static PHP_METHOD(swoole_postgresql_coro, connect) {
- zval *conninfo;
- double timeout = Socket::default_connect_timeout;
-
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_ZVAL(conninfo)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(timeout)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- PGObject *object = php_swoole_postgresql_coro_get_object(ZEND_THIS);
- if (object->conn) {
- RETURN_FALSE;
- }
-
- zend::String dsn(conninfo);
- char *p = dsn.val();
- for (size_t i = 0; i < dsn.len(); i++) {
- if (*p == ';') {
- *p = ' ';
- }
- p++;
- }
-
- PGconn *pgsql = PQconnectStart(dsn.val());
- if (!pgsql) {
- RETURN_FALSE;
- }
-
- int fd = PQsocket(pgsql);
- if (sw_unlikely(fd < 0)) {
- RETURN_FALSE;
- }
-
- php_swoole_check_reactor();
-
- if (!swoole_event_isset_handler(PHP_SWOOLE_FD_POSTGRESQL)) {
- swoole_event_set_handler(PHP_SWOOLE_FD_POSTGRESQL | SW_EVENT_READ, swoole_pgsql_coro_onReadable);
- swoole_event_set_handler(PHP_SWOOLE_FD_POSTGRESQL | SW_EVENT_WRITE, swoole_pgsql_coro_onWritable);
- swoole_event_set_handler(PHP_SWOOLE_FD_POSTGRESQL | SW_EVENT_ERROR, swoole_pgsql_coro_onError);
- }
-
- object->socket = swoole::make_socket(fd, (enum swFdType) PHP_SWOOLE_FD_POSTGRESQL);
- object->socket->object = object;
- object->conn = pgsql;
- object->status = CONNECTION_STARTED;
- object->connected = false;
-
- ON_SCOPE_EXIT {
- if (!object->connected) {
- object->conn = nullptr;
- object->socket->fd = -1;
- object->socket->free();
- }
- };
-
- PQsetnonblocking(pgsql, 1);
- PQsetNoticeProcessor(pgsql, _php_pgsql_notice_handler, object);
-
- if (pgsql == nullptr || PQstatus(pgsql) == CONNECTION_BAD) {
- swoole_warning("Unable to connect to PostgreSQL server: [%s]", PQhost(pgsql));
- if (pgsql) {
- PQfinish(pgsql);
- }
- RETURN_FALSE;
- }
-
- if (!object->yield(return_value, SW_EVENT_WRITE, timeout)) {
- const char *feedback;
-
- switch (PQstatus(pgsql)) {
- case CONNECTION_STARTED:
- feedback = "connection time out...please make sure your host,dbname,user and password is correct ";
- break;
- case CONNECTION_MADE:
- feedback = "Connected to server..";
- break;
- default:
- feedback = " time out..";
- break;
- }
-
- char *err_msg = PQerrorMessage(object->conn);
- zend_update_property_string(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("error"), err_msg);
-
- if (pgsql == nullptr || PQstatus(pgsql) == CONNECTION_STARTED) {
- swoole_warning(" [%s, %s] ", feedback, err_msg);
- } else {
- PQfinish(pgsql);
- }
-
- RETURN_FALSE;
- }
-
- ZVAL_BOOL(return_value, object->connected);
-}
-
-static void connect_callback(PGObject *object, Reactor *reactor, Event *event) {
- PGconn *conn = object->conn;
- ConnStatusType status = PQstatus(conn);
- int events = 0;
- char *err_msg;
-
- swoole_event_del(object->socket);
-
- if (status != CONNECTION_OK) {
- PostgresPollingStatusType flag = PQconnectPoll(conn);
- switch (flag) {
- case PGRES_POLLING_READING:
- events = SW_EVENT_READ;
- break;
- case PGRES_POLLING_WRITING:
- events = SW_EVENT_WRITE;
- break;
- case PGRES_POLLING_OK:
- object->connected = true;
- object->lob_streams = (HashTable *) pemalloc(sizeof(HashTable), 1);
- zend_hash_init(object->lob_streams, 0, NULL, NULL, 1);
- events = 0;
- break;
- case PGRES_POLLING_FAILED:
- events = 0;
- err_msg = PQerrorMessage(conn);
- zend_update_property_string(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"), err_msg);
- if (object->statement) {
- zend_update_property_string(swoole_postgresql_coro_statement_ce,
- SW_Z8_OBJ_P(object->statement->object),
- ZEND_STRL("error"),
- err_msg);
- }
- break;
- default:
- swoole_warning("PQconnectPoll unexpected status");
- break;
- }
-
- if (events) {
- event->socket->fd = PQsocket(conn);
- swoole_event_add(event->socket, events);
- return;
- }
- }
-
- if (object->connected == 1) {
- object->request_success = true;
- zend_update_property_null(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"));
- if (object->statement) {
- zend_update_property_null(
- swoole_postgresql_coro_statement_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"));
- }
- } else {
- object->request_success = false;
- }
- object->co->resume();
-}
-
-static int swoole_pgsql_coro_onWritable(Reactor *reactor, Event *event) {
- PGObject *object = (PGObject *) event->socket->object;
-
- if (!object->connected) {
- connect_callback(object, reactor, event);
- return SW_OK;
- }
-
- if (object->co) {
- object->co->resume();
- return SW_OK;
- } else {
- return reactor->default_write_handler(reactor, event);
- }
-}
-
-static int swoole_pgsql_coro_onReadable(Reactor *reactor, Event *event) {
- PGObject *object = (PGObject *) (event->socket->object);
-
- if (!object->connected) {
- connect_callback(object, reactor, event);
- return SW_OK;
- }
-
- switch (object->request_type) {
- case PGQueryType::NORMAL_QUERY:
- query_result_parse(object);
- break;
- case PGQueryType::META_DATA:
- meta_data_result_parse(object);
- break;
- case PGQueryType::PREPARE:
- prepare_result_parse(object);
- break;
- }
-
- return SW_OK;
-}
-
-static int meta_data_result_parse(PGObject *object) {
- int i, num_rows;
- zval elem;
- PGresult *pg_result;
- zend_bool extended = 0;
- pg_result = swoole_pgsql_get_result(object);
-
- if (PQresultStatus(pg_result) != PGRES_TUPLES_OK || (num_rows = PQntuples(pg_result)) == 0) {
- php_swoole_fatal_error(E_WARNING, "Table doesn't exists");
- return 0;
- }
-
- array_init(object->return_value);
-
- object->result = pg_result;
- for (i = 0; i < num_rows; i++) {
- char *name;
- array_init(&elem);
- /* pg_attribute.attnum */
- add_assoc_long_ex(&elem, "num", sizeof("num") - 1, atoi(PQgetvalue(pg_result, i, 1)));
- /* pg_type.typname */
- add_assoc_string_ex(&elem, "type", sizeof("type") - 1, PQgetvalue(pg_result, i, 2));
- /* pg_attribute.attlen */
- add_assoc_long_ex(&elem, "len", sizeof("len") - 1, atoi(PQgetvalue(pg_result, i, 3)));
- /* pg_attribute.attnonull */
- add_assoc_bool_ex(&elem, "not null", sizeof("not null") - 1, !strcmp(PQgetvalue(pg_result, i, 4), "t"));
- /* pg_attribute.atthasdef */
- add_assoc_bool_ex(&elem, "has default", sizeof("has default") - 1, !strcmp(PQgetvalue(pg_result, i, 5), "t"));
- /* pg_attribute.attndims */
- add_assoc_long_ex(&elem, "array dims", sizeof("array dims") - 1, atoi(PQgetvalue(pg_result, i, 6)));
- /* pg_type.typtype */
- add_assoc_bool_ex(&elem, "is enum", sizeof("is enum") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "e"));
- if (extended) {
- /* pg_type.typtype */
- add_assoc_bool_ex(&elem, "is base", sizeof("is base") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "b"));
- add_assoc_bool_ex(
- &elem, "is composite", sizeof("is composite") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "c"));
- add_assoc_bool_ex(&elem, "is pesudo", sizeof("is pesudo") - 1, !strcmp(PQgetvalue(pg_result, i, 7), "p"));
- /* pg_description.description */
- add_assoc_string_ex(&elem, "description", sizeof("description") - 1, PQgetvalue(pg_result, i, 8));
- }
- /* pg_attribute.attname */
- name = PQgetvalue(pg_result, i, 0);
- add_assoc_zval(object->return_value, name, &elem);
- }
- zend_update_property_null(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"));
- zend_update_property_null(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("resultDiag"));
- if (object->statement) {
- zend_update_property_null(
- swoole_postgresql_coro_statement_ce, SW_Z8_OBJ_P(object->statement->object), ZEND_STRL("error"));
- zend_update_property_null(
- swoole_postgresql_coro_statement_ce, SW_Z8_OBJ_P(object->statement->object), ZEND_STRL("resultDiag"));
- }
- object->co->resume();
- return SW_OK;
-}
-
-static void set_error_diag(const PGObject *object, const PGresult *pgsql_result) {
- const unsigned int error_codes[] = {PG_DIAG_SEVERITY,
- PG_DIAG_SQLSTATE,
- PG_DIAG_MESSAGE_PRIMARY,
- PG_DIAG_MESSAGE_DETAIL,
- PG_DIAG_MESSAGE_HINT,
- PG_DIAG_STATEMENT_POSITION,
- PG_DIAG_INTERNAL_POSITION,
- PG_DIAG_INTERNAL_QUERY,
- PG_DIAG_CONTEXT,
- PG_DIAG_SCHEMA_NAME,
- PG_DIAG_TABLE_NAME,
- PG_DIAG_COLUMN_NAME,
- PG_DIAG_DATATYPE_NAME,
- PG_DIAG_CONSTRAINT_NAME,
- PG_DIAG_SOURCE_FILE,
- PG_DIAG_SOURCE_LINE,
- PG_DIAG_SOURCE_FUNCTION};
-
- const char *error_names[] = {"severity",
- "sqlstate",
- "message_primary",
- "message_detail",
- "message_hint",
- "statement_position",
- "internal_position",
- "internal_query",
- "content",
- "schema_name",
- "table_name",
- "column_name",
- "datatype_name",
- "constraint_name",
- "source_file",
- "source_line",
- "source_function"};
-
- long unsigned int i;
- char *error_result;
-
- zval result_diag;
- array_init_size(&result_diag, sizeof(error_codes) / sizeof(int));
-
- for (i = 0; i < sizeof(error_codes) / sizeof(int); i++) {
- error_result = PQresultErrorField(pgsql_result, error_codes[i]);
-
- if (error_result != nullptr) {
- add_assoc_string(&result_diag, error_names[i], error_result);
- } else {
- add_assoc_null(&result_diag, error_names[i]);
- }
- }
-
- zend_update_property(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("resultDiag"), &result_diag);
- zval_dtor(&result_diag);
-}
-
-static int query_result_parse(PGObject *object) {
- PGresult *pgsql_result;
- ExecStatusType status;
-
- int error = 0;
- char *err_msg;
- int res;
-
- pgsql_result = swoole_pgsql_get_result(object);
- status = PQresultStatus(pgsql_result);
-
- zend_update_property_long(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("resultStatus"), status);
- if (object->statement) {
- zend_update_property_long(swoole_postgresql_coro_statement_ce,
- SW_Z8_OBJ_P(object->statement->object),
- ZEND_STRL("resultStatus"),
- status);
- }
-
- object->request_success = (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK);
-
- switch (status) {
- case PGRES_EMPTY_QUERY:
- case PGRES_BAD_RESPONSE:
- case PGRES_NONFATAL_ERROR:
- case PGRES_FATAL_ERROR:
- err_msg = PQerrorMessage(object->conn);
- set_error_diag(object, pgsql_result);
- PQclear(pgsql_result);
- ZVAL_FALSE(object->return_value);
- zend_update_property_string(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"), err_msg);
- if (object->statement) {
- zend_update_property_string(swoole_postgresql_coro_statement_ce,
- SW_Z8_OBJ_P(object->statement->object),
- ZEND_STRL("error"),
- err_msg);
- }
- object->co->resume();
- break;
- case PGRES_COMMAND_OK: /* successful command that did not return rows */
- default:
- object->result = pgsql_result;
- /* Wait to finish sending buffer */
- res = PQflush(object->conn);
- zend_update_property_null(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"));
- zend_update_property_null(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("resultDiag"));
- if (object->statement) {
- object->statement->row = 0;
- zend_update_property_null(
- swoole_postgresql_coro_statement_ce, SW_Z8_OBJ_P(object->statement->object), ZEND_STRL("error"));
- zend_update_property_null(
- swoole_postgresql_coro_statement_ce, SW_Z8_OBJ_P(object->statement->object), ZEND_STRL("resultDiag"));
- }
- object->co->resume();
- if (error != 0) {
- php_swoole_fatal_error(E_WARNING, "socket error. Error: %s [%d]", strerror(error), error);
- }
- break;
- }
- (void) res;
-
- return SW_OK;
-}
-
-static int prepare_result_parse(PGObject *object) {
- int error = 0;
- char *err_msg;
- int res;
-
- PGresult *pgsql_result = swoole_pgsql_get_result(object);
- ExecStatusType status = PQresultStatus(pgsql_result);
-
- zend_update_property_long(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("resultStatus"), status);
- if (object->statement) {
- zend_update_property_long(swoole_postgresql_coro_statement_ce,
- SW_Z8_OBJ_P(object->statement->object),
- ZEND_STRL("resultStatus"),
- status);
- }
-
- object->request_success = (status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK);
-
- switch (status) {
- case PGRES_EMPTY_QUERY:
- case PGRES_BAD_RESPONSE:
- case PGRES_NONFATAL_ERROR:
- case PGRES_FATAL_ERROR:
- err_msg = PQerrorMessage(object->conn);
- set_error_diag(object, pgsql_result);
- PQclear(pgsql_result);
- ZVAL_FALSE(object->return_value);
- zend_update_property_string(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"), err_msg);
- if (object->statement) {
- zend_update_property_string(swoole_postgresql_coro_statement_ce,
- SW_Z8_OBJ_P(object->statement->object),
- ZEND_STRL("error"),
- err_msg);
- }
- object->co->resume();
- if (error != 0) {
- php_swoole_fatal_error(E_WARNING, "socket error. Error: %s [%d]", strerror(error), error);
- }
- break;
- case PGRES_COMMAND_OK: /* successful command that did not return rows */
- /* Wait to finish sending buffer */
- PQclear(pgsql_result);
- ZVAL_TRUE(object->return_value);
- zend_update_property_null(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"));
- zend_update_property_null(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("resultDiag"));
- if (object->statement) {
- zend_update_property_null(
- swoole_postgresql_coro_statement_ce, SW_Z8_OBJ_P(object->statement->object), ZEND_STRL("error"));
- zend_update_property_null(
- swoole_postgresql_coro_statement_ce, SW_Z8_OBJ_P(object->statement->object), ZEND_STRL("resultDiag"));
- }
- object->co->resume();
- if (error != 0) {
- php_swoole_fatal_error(E_WARNING, "socket error. Error: %s [%d]", strerror(error), error);
- }
- break;
- default:
- PQclear(pgsql_result);
- ZVAL_FALSE(object->return_value);
- zend_update_property_string(swoole_postgresql_coro_ce,
- SW_Z8_OBJ_P(object->object),
- ZEND_STRL("error"),
- "Bad result returned to prepare");
- if (object->statement) {
- zend_update_property_string(swoole_postgresql_coro_statement_ce,
- SW_Z8_OBJ_P(object->statement->object),
- ZEND_STRL("error"),
- "Bad result returned to prepare");
- }
- object->co->resume();
- if (error != 0) {
- php_swoole_fatal_error(E_WARNING, "socket error. Error: %s [%d]", strerror(error), error);
- }
- break;
- }
- (void) res;
-
- return SW_OK;
-}
-
-bool PGObject::wait_write_ready() {
- int retval = 0;
- while ((retval = PQflush(conn)) == 1) {
- zval return_value;
- if (!yield(&return_value, SW_EVENT_WRITE, Socket::default_write_timeout)) {
- return false;
- }
- }
-
- if (retval == -1) {
- char *err_msg = PQerrorMessage(conn);
- zend_update_property_string(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object), ZEND_STRL("error"), err_msg);
- if (statement) {
- zend_update_property_string(
- swoole_postgresql_coro_statement_ce, SW_Z8_OBJ_P(statement->object), ZEND_STRL("error"), err_msg);
- }
- return false;
- }
-
- return true;
-}
-
-bool PGObject::yield(zval *_return_value, EventType event, double timeout) {
- co = swoole::Coroutine::get_current_safe();
- if (swoole_event_add(socket, event) < 0) {
- php_swoole_fatal_error(E_WARNING, "swoole_event_add failed");
- RETVAL_FALSE;
- return false;
- }
-
- ON_SCOPE_EXIT {
- co = nullptr;
- if (!socket->removed && swoole_event_del(socket) < 0) {
- php_swoole_fatal_error(E_WARNING, "swoole_event_del failed");
- }
- };
-
- return_value = _return_value;
-
- if (!co->yield_ex(timeout)) {
- ZVAL_FALSE(_return_value);
-
- if (co->is_canceled()) {
- zend_update_property_string(swoole_postgresql_coro_ce,
- SW_Z8_OBJ_P(object),
- ZEND_STRL("error"),
- swoole_strerror(SW_ERROR_CO_CANCELED));
- if (statement) {
- zend_update_property_string(swoole_postgresql_coro_statement_ce,
- SW_Z8_OBJ_P(statement->object),
- ZEND_STRL("error"),
- swoole_strerror(SW_ERROR_CO_CANCELED));
- }
- } else if (co->is_timedout()) {
- zend_update_property_string(swoole_postgresql_coro_ce,
- SW_Z8_OBJ_P(object),
- ZEND_STRL("error"),
- swoole_strerror(SW_ERROR_CO_TIMEDOUT));
- if (statement) {
- zend_update_property_string(swoole_postgresql_coro_statement_ce,
- SW_Z8_OBJ_P(statement->object),
- ZEND_STRL("error"),
- swoole_strerror(SW_ERROR_CO_TIMEDOUT));
- }
- }
-
- return false;
- } else if (!request_success) {
- ZVAL_FALSE(_return_value);
- return false;
- }
-
- return true;
-}
-
-static PHP_METHOD(swoole_postgresql_coro, query) {
- zval *zquery;
- PGconn *pgsql;
-
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ZVAL(zquery)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- PGObject *object = php_swoole_postgresql_coro_get_object(ZEND_THIS);
- if (!object || !object->conn) {
- RETURN_FALSE;
- }
- object->request_type = PGQueryType::NORMAL_QUERY;
- pgsql = object->conn;
-
- bool in_trans = swoole_pgsql_in_transaction(object);
-
- zend::String query = zquery;
- if (PQsendQuery(pgsql, query.val()) == 0) {
- char *err_msg = PQerrorMessage(pgsql);
- zend_update_property_string(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("error"), err_msg);
- RETURN_FALSE;
- }
-
- if (!object->wait_write_ready()) {
- RETURN_FALSE;
- }
-
- if (object->yield(return_value, SW_EVENT_READ, Socket::default_read_timeout)) {
- RETVAL_OBJ(php_swoole_postgresql_coro_statement_create_object(object, query.val()));
- }
-
- if (in_trans && !swoole_pgsql_in_transaction(object)) {
- swoole_pgsql_close_lob_streams(object);
- }
-}
-
-static PHP_METHOD(swoole_postgresql_coro, prepare) {
- zval *zquery;
- PGconn *pgsql;
- int is_non_blocking;
-
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ZVAL(zquery)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- PGObject *object = php_swoole_postgresql_coro_get_object(ZEND_THIS);
- if (!object || !object->conn) {
- RETURN_FALSE;
- }
- object->request_type = PGQueryType::PREPARE;
- pgsql = object->conn;
-
- is_non_blocking = PQisnonblocking(pgsql);
-
- if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) {
- php_swoole_fatal_error(E_NOTICE, "Cannot set connection to nonblocking mode");
- RETURN_FALSE;
- }
-
- std::string stmtname = swoole::std_string::format("swoole_stmt_%ld", ++object->stmt_counter);
- zend::String query = zquery;
- if (!PQsendPrepare(pgsql, stmtname.c_str(), query.val(), 0, nullptr)) {
- if (is_non_blocking) {
- RETURN_FALSE;
- } else {
- /*if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
- PQreset(pgsql);
- }*/
- if (!PQsendPrepare(pgsql, stmtname.c_str(), query.val(), 0, nullptr)) {
- RETURN_FALSE;
- }
- }
- }
-
- if (!object->wait_write_ready()) {
- RETURN_FALSE;
- }
-
- if (object->yield(return_value, SW_EVENT_READ, Socket::default_read_timeout)) {
- RETVAL_OBJ(php_swoole_postgresql_coro_statement_create_object(object, stmtname.c_str(), query.val()));
- }
-}
-
-static PHP_METHOD(swoole_postgresql_coro_statement, execute) {
- zval *pv_param_arr = nullptr, *tmp;
- int num_params = 0;
- char **params = nullptr;
- PGconn *pgsql;
- int is_non_blocking;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_ZVAL(pv_param_arr)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- PGStatement *statement = php_swoole_postgresql_coro_statement_get_object(ZEND_THIS);
- PGObject *object = statement->pg_object;
- if (!object || !object->conn) {
- RETURN_FALSE;
- }
- object->statement = statement;
- ON_SCOPE_EXIT {
- object->statement = nullptr;
- };
- object->request_type = PGQueryType::NORMAL_QUERY;
- pgsql = object->conn;
-
- is_non_blocking = PQisnonblocking(pgsql);
-
- if (is_non_blocking == 0 && PQsetnonblocking(pgsql, 1) == -1) {
- php_swoole_fatal_error(E_NOTICE, "Cannot set connection to nonblocking mode");
- RETURN_FALSE;
- }
-
- bool in_trans = swoole_pgsql_in_transaction(object);
-
- num_params = pv_param_arr ? zend_hash_num_elements(Z_ARRVAL_P(pv_param_arr)) : 0;
-
- ON_SCOPE_EXIT {
- if (num_params > 0) {
- _php_pgsql_free_params(params, num_params);
- }
- };
-
- if (num_params > 0) {
- int i = 0;
- params = (char **) safe_emalloc(sizeof(char *), num_params, 0);
-
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pv_param_arr), tmp) {
- if (Z_TYPE_P(tmp) == IS_NULL) {
- params[i] = nullptr;
- } else {
- zval tmp_val;
- if (Z_TYPE_P(tmp) == IS_RESOURCE) {
- php_stream *stm = NULL;
- php_stream_from_zval_no_verify(stm, tmp);
- if (stm) {
- if (php_stream_is(stm, &swoole_pgsql_lob_stream_ops)) {
- struct swoole_pgsql_lob_self *self = (struct swoole_pgsql_lob_self *) stm->abstract;
- std::stringstream ss;
- ss << self->oid;
- ZVAL_STRING(&tmp_val, ss.str().c_str());
- } else {
- zend_string *mem = php_stream_copy_to_mem(stm, PHP_STREAM_COPY_ALL, 0);
- ZVAL_STR(&tmp_val, mem ? mem : ZSTR_EMPTY_ALLOC());
- }
- } else {
- php_swoole_fatal_error(E_WARNING, "Expected a stream resource");
- RETURN_FALSE;
- }
- } else {
- ZVAL_COPY(&tmp_val, tmp);
- convert_to_string(&tmp_val);
- if (Z_TYPE(tmp_val) != IS_STRING) {
- php_swoole_fatal_error(E_WARNING, "Error converting parameter");
- zval_ptr_dtor(&tmp_val);
- RETURN_FALSE;
- }
- }
- params[i] = estrndup(Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
- zval_ptr_dtor(&tmp_val);
- }
- i++;
- }
- ZEND_HASH_FOREACH_END();
- }
-
- if (PQsendQueryPrepared(pgsql, statement->name, num_params, (const char *const *) params, nullptr, nullptr, 0)) {
- } else if (is_non_blocking) {
- RETURN_FALSE;
- } else {
- /*
- if ((PGG(auto_reset_persistent) & 2) && PQstatus(pgsql) != CONNECTION_OK) {
- PQreset(pgsql);
- }
- */
- if (!PQsendQueryPrepared(
- pgsql, statement->name, num_params, (const char *const *) params, nullptr, nullptr, 0)) {
- RETURN_FALSE;
- }
- }
- if (!object->wait_write_ready()) {
- RETURN_FALSE;
- }
- if (object->yield(return_value, SW_EVENT_READ, Socket::default_read_timeout)) {
- statement->result = object->result;
- if (in_trans && !swoole_pgsql_in_transaction(object)) {
- swoole_pgsql_close_lob_streams(object);
- }
- RETURN_TRUE;
- }
-}
-
-static PHP_METHOD(swoole_postgresql_coro_statement, fetchAll) {
- zend_long result_type = PGSQL_ASSOC;
-
- ZEND_PARSE_PARAMETERS_START(0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(result_type)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- PGStatement *statement = php_swoole_postgresql_coro_statement_get_object(ZEND_THIS);
- if (!statement->result) {
- RETURN_FALSE;
- }
-
- array_init(return_value);
- swoole_pgsql_result2array(statement->result, return_value, result_type);
-}
-
-static PHP_METHOD(swoole_postgresql_coro_statement, affectedRows) {
- PGStatement *statement = php_swoole_postgresql_coro_statement_get_object(ZEND_THIS);
- if (!statement->result) {
- RETURN_FALSE;
- }
-
- RETVAL_LONG(atoi(PQcmdTuples(statement->result)));
-}
-
-// query's num
-static PHP_METHOD(swoole_postgresql_coro_statement, numRows) {
- PGStatement *statement = php_swoole_postgresql_coro_statement_get_object(ZEND_THIS);
- if (!statement->result) {
- RETURN_FALSE;
- }
-
- RETVAL_LONG(PQntuples(statement->result));
-}
-
-// query's field count
-static PHP_METHOD(swoole_postgresql_coro_statement, fieldCount) {
- PGStatement *statement = php_swoole_postgresql_coro_statement_get_object(ZEND_THIS);
- if (!statement->result) {
- RETURN_FALSE;
- }
-
- RETVAL_LONG(PQnfields(statement->result));
-}
-
-/* {{{ proto array fetchRow([, int row [, int result_type]])
- Get a row as an enumerated array */
-static PHP_METHOD(swoole_postgresql_coro_statement, fetchRow) {
- php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_NUM, 0);
-}
-/* }}} */
-
-/* {{{ proto array fetchAssoc([, int row])
- Fetch a row as an assoc array */
-static PHP_METHOD(swoole_postgresql_coro_statement, fetchAssoc) {
- /* pg_fetch_assoc() is added from PHP 4.3.0. It should raise error, when
- there is 3rd parameter */
- if (ZEND_NUM_ARGS() > 2) WRONG_PARAM_COUNT;
- php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 0);
-}
-/* }}} */
-
-/* {{{ proto array fetchArray([, int row [, int result_type]])
- Fetch a row as an array */
-static PHP_METHOD(swoole_postgresql_coro_statement, fetchArray) {
- php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_BOTH, 0);
-}
-/* }}} */
-
-/* {{{ proto object fetchObject([, int row [, string class_name [, NULL|array ctor_params]]])
- Fetch a row as an object */
-static PHP_METHOD(swoole_postgresql_coro_statement, fetchObject) {
- /* fetchObject() allowed result_type used to be. 3rd parameter
- must be allowed for compatibility */
- php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, PGSQL_ASSOC, 1);
-}
-
-static void _php_pgsql_free_params(char **params, int num_params) {
- if (num_params > 0) {
- for (int i = 0; i < num_params; i++) {
- if (params[i]) {
- efree(params[i]);
- }
- }
- efree(params);
- }
-}
-
-/* {{{ void php_pgsql_get_field_value */
-static inline void php_pgsql_get_field_value(
- zval *value, PGresult *pgsql_result, zend_long result_type, int row, int column) {
- if (PQgetisnull(pgsql_result, row, column)) {
- ZVAL_NULL(value);
- } else {
- char *element = PQgetvalue(pgsql_result, row, column);
- if (element) {
- const size_t element_len = PQgetlength(pgsql_result, row, column);
- Oid pgsql_type = PQftype(pgsql_result, column);
-
- switch (pgsql_type) {
- case BOOLOID:
- ZVAL_BOOL(value, *element == 't');
- break;
- case FLOAT4OID:
- case FLOAT8OID:
- if (element_len == sizeof("Infinity") - 1 && strcmp(element, "Infinity") == 0) {
- ZVAL_DOUBLE(value, ZEND_INFINITY);
- } else if (element_len == sizeof("-Infinity") - 1 && strcmp(element, "-Infinity") == 0) {
- ZVAL_DOUBLE(value, -ZEND_INFINITY);
- } else if (element_len == sizeof("NaN") - 1 && strcmp(element, "NaN") == 0) {
- ZVAL_DOUBLE(value, ZEND_NAN);
- } else {
- ZVAL_DOUBLE(value, zend_strtod(element, nullptr));
- }
- break;
- case OIDOID:
- case INT2OID:
- case INT4OID:
-#if SIZEOF_ZEND_LONG >= 8
- case INT8OID:
-#endif
- {
- zend_long long_value;
-#if PHP_VERSION_ID < 80100
- ZEND_ATOL(long_value, element);
-#else
- long_value = ZEND_ATOL(element);
-#endif
- ZVAL_LONG(value, long_value);
- break;
- }
- case BYTEAOID: {
- size_t tmp_len;
- char *tmp_ptr = (char *) PQunescapeBytea((unsigned char *) element, &tmp_len);
- if (!tmp_ptr) {
- /* PQunescapeBytea returned an error */
- ZVAL_NULL(value);
- } else {
- ZVAL_STRINGL(value, tmp_ptr, tmp_len);
- PQfreemem(tmp_ptr);
- }
- break;
- }
- default:
- ZVAL_STRINGL(value, element, element_len);
- }
- } else {
- ZVAL_NULL(value);
- }
- }
-}
-/* }}} */
-
-/* {{{ swoole_pgsql_result2array
- */
-static void swoole_pgsql_result2array(PGresult *pg_result, zval *ret_array, long result_type) {
- zval row;
- const char *field_name;
- size_t num_fields, unknown_columns;
- int pg_numrows, pg_row;
- uint32_t i;
- assert(Z_TYPE_P(ret_array) == IS_ARRAY);
-
- pg_numrows = PQntuples(pg_result);
- for (pg_row = 0; pg_row < pg_numrows; pg_row++) {
- array_init(&row);
- unknown_columns = 0;
- for (i = 0, num_fields = PQnfields(pg_result); i < num_fields; i++) {
- if (result_type & PGSQL_ASSOC) {
- zval value;
- php_pgsql_get_field_value(&value, pg_result, result_type, pg_row, i);
- field_name = PQfname(pg_result, i);
- if (0 == strcmp("?column?", field_name)) {
- if (unknown_columns > 0) {
- field_name = (std::string(field_name) + std::to_string(unknown_columns)).c_str();
- }
- ++unknown_columns;
- }
- add_assoc_zval(&row, field_name, &value);
- }
- if (result_type & PGSQL_NUM) {
- zval value;
- php_pgsql_get_field_value(&value, pg_result, result_type, pg_row, i);
- add_next_index_zval(&row, &value);
- }
- }
- add_index_zval(ret_array, pg_row, &row);
- }
-}
-/* }}} */
-
-static PHP_METHOD(swoole_postgresql_coro, metaData) {
- char *table_name;
- size_t table_name_len;
- zend_bool extended = 0;
- PGconn *pgsql;
-
- char *src, *tmp_name, *tmp_name2 = nullptr;
- char *escaped;
- smart_str querystr = {0};
- size_t new_len;
-
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STRING(table_name, table_name_len)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- PGObject *object = php_swoole_postgresql_coro_get_object(ZEND_THIS);
- if (!object || !object->conn) {
- RETURN_FALSE;
- }
- object->request_type = PGQueryType::META_DATA;
- pgsql = object->conn;
-
- if (table_name_len == 0) {
- php_swoole_fatal_error(E_WARNING, "The table name must be specified");
- RETURN_FALSE;
- }
-
- src = estrdup(table_name);
- tmp_name = php_strtok_r(src, ".", &tmp_name2);
- if (!tmp_name) {
- efree(src);
- php_swoole_fatal_error(E_WARNING, "The table name must be specified");
- RETURN_FALSE;
- }
- if (!tmp_name2 || !*tmp_name2) {
- /* Default schema */
- tmp_name2 = tmp_name;
- tmp_name = (char *) "public";
- }
-
- if (extended) {
- smart_str_appends(
- &querystr,
- "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotNULL, a.atthasdef, a.attndims, t.typtype, "
- "d.description "
- "FROM pg_class as c "
- " JOIN pg_attribute a ON (a.attrelid = c.oid) "
- " JOIN pg_type t ON (a.atttypid = t.oid) "
- " JOIN pg_namespace n ON (c.relnamespace = n.oid) "
- " LEFT JOIN pg_description d ON (d.objoid=a.attrelid AND d.objsubid=a.attnum AND c.oid=d.objoid) "
- "WHERE a.attnum > 0 AND c.relname = '");
- } else {
- smart_str_appends(
- &querystr,
- "SELECT a.attname, a.attnum, t.typname, a.attlen, a.attnotnull, a.atthasdef, a.attndims, t.typtype "
- "FROM pg_class as c "
- " JOIN pg_attribute a ON (a.attrelid = c.oid) "
- " JOIN pg_type t ON (a.atttypid = t.oid) "
- " JOIN pg_namespace n ON (c.relnamespace = n.oid) "
- "WHERE a.attnum > 0 AND c.relname = '");
- }
- escaped = (char *) safe_emalloc(strlen(tmp_name2), 2, 1);
- new_len = PQescapeStringConn(pgsql, escaped, tmp_name2, strlen(tmp_name2), nullptr);
- if (new_len) {
- smart_str_appendl(&querystr, escaped, new_len);
- }
- efree(escaped);
-
- smart_str_appends(&querystr, "' AND n.nspname = '");
- escaped = (char *) safe_emalloc(strlen(tmp_name), 2, 1);
- new_len = PQescapeStringConn(pgsql, escaped, tmp_name, strlen(tmp_name), nullptr);
- if (new_len) {
- smart_str_appendl(&querystr, escaped, new_len);
- }
- efree(escaped);
-
- smart_str_appends(&querystr, "' ORDER BY a.attnum;");
- smart_str_0(&querystr);
- efree(src);
-
- int ret = PQsendQuery(pgsql, ZSTR_VAL(querystr.s));
- if (ret == 0) {
- char *err_msg = PQerrorMessage(pgsql);
- swoole_warning("error:[%s]", err_msg);
- }
- smart_str_free(&querystr);
- object->yield(return_value, SW_EVENT_READ, Socket::default_read_timeout);
-}
-
-static PHP_METHOD(swoole_postgresql_coro, createLOB) {
- ZEND_PARSE_PARAMETERS_NONE();
-
- PGObject *object = php_swoole_postgresql_coro_get_object(ZEND_THIS);
- if (!object || !object->conn) {
- RETURN_FALSE;
- }
- Oid lfd = 0;
- swoole::coroutine::async([&]() {
- lfd = lo_creat(object->conn, INV_READ | INV_WRITE);
- PGresult *pgsql_result = swoole_pgsql_get_result(object);
- set_error_diag(object, pgsql_result);
- PQclear(pgsql_result);
- });
-
- if (lfd != InvalidOid) {
- RETURN_LONG(lfd);
- }
-
- zend_update_property_string(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"), PQerrorMessage(object->conn));
-
- RETURN_FALSE;
-}
-
-static PHP_METHOD(swoole_postgresql_coro, openLOB) {
- Oid oid = 0;
- char *modestr = "rb";
- size_t modestrlen;
- if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l|s", &oid, &modestr, &modestrlen)) {
- RETURN_THROWS();
- }
-
- PGObject *object = php_swoole_postgresql_coro_get_object(ZEND_THIS);
- if (!object || !object->conn) {
- RETURN_FALSE;
- }
-
- if (oid == 0 && (errno == ERANGE || errno == EINVAL)) {
- RETURN_FALSE;
- }
-
- int mode = INV_READ;
-
- if (strpbrk(modestr, "+w")) {
- mode = INV_READ | INV_WRITE;
- }
-
- int lfd = -1;
-
- swoole::coroutine::async([&]() {
- lfd = lo_open(object->conn, oid, mode);
- PGresult *pgsql_result = swoole_pgsql_get_result(object);
- set_error_diag(object, pgsql_result);
- PQclear(pgsql_result);
- });
-
- if (lfd >= 0) {
- php_stream *stream = swoole_pgsql_create_lob_stream(ZEND_THIS, lfd, oid);
- if (stream) {
- php_stream_to_zval(stream, return_value);
- return;
- }
- }
-
- zend_update_property_string(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"), PQerrorMessage(object->conn));
-
- RETURN_FALSE;
-}
-
-static PHP_METHOD(swoole_postgresql_coro, unlinkLOB) {
- Oid oid = 0;
-
- if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &oid)) {
- RETURN_THROWS();
- }
-
- PGObject *object = php_swoole_postgresql_coro_get_object(ZEND_THIS);
- if (!object || !object->conn) {
- RETURN_FALSE;
- }
-
- if (oid == 0 && (errno == ERANGE || errno == EINVAL)) {
- RETURN_FALSE;
- }
-
- int result = 0;
- swoole::coroutine::async([&]() {
- result = lo_unlink(object->conn, oid);
- PGresult *pgsql_result = swoole_pgsql_get_result(object);
- set_error_diag(object, pgsql_result);
- PQclear(pgsql_result);
- });
- if (1 == result) {
- RETURN_TRUE;
- }
-
- zend_update_property_string(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"), PQerrorMessage(object->conn));
-
- RETURN_FALSE;
-}
-
-/* {{{ void php_pgsql_fetch_hash */
-static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_type, int into_object) {
- zval *zrow = nullptr;
- PGresult *pgsql_result;
- PGObject *pg_result;
- PGStatement *statement;
- int i, num_fields, pgsql_row, use_row;
- zend_long row = -1;
- char *field_name;
- zval *ctor_params = nullptr;
- zend_class_entry *ce = nullptr;
-
- if (into_object) {
- zend_string *class_name = nullptr;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z!Sz", &zrow, &class_name, &ctor_params) == FAILURE) {
- RETURN_FALSE;
- }
- if (!class_name) {
- ce = zend_standard_class_def;
- } else {
- ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_AUTO);
- }
- if (!ce) {
- php_swoole_fatal_error(E_WARNING, "Could not find class '%s'", ZSTR_VAL(class_name));
- return;
- }
- result_type = PGSQL_ASSOC;
- } else {
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z!l", &zrow, &result_type) == FAILURE) {
- RETURN_FALSE;
- }
- }
- if (zrow == nullptr) {
- row = -1;
- } else {
- row = zval_get_long(zrow);
- if (row < 0) {
- php_swoole_fatal_error(E_WARNING, "The row parameter must be greater or equal to zero");
- RETURN_FALSE;
- }
- }
- use_row = ZEND_NUM_ARGS() > 0 && row != -1;
-
- if (!(result_type & PGSQL_BOTH)) {
- php_swoole_fatal_error(E_WARNING, "Invalid result type");
- RETURN_FALSE;
- }
-
- statement = php_swoole_postgresql_coro_statement_get_object(ZEND_THIS);
- if (!statement || !statement->result) {
- RETURN_FALSE;
- }
- pgsql_result = statement->result;
- pg_result = statement->pg_object;
- if (!pg_result || !pg_result->conn) {
- RETURN_FALSE;
- }
-
- if (use_row) {
- if (row < 0 || row >= PQntuples(pgsql_result)) {
- php_swoole_fatal_error(E_WARNING, "Unable to jump to row " ZEND_LONG_FMT " on PostgreSQL result", row);
- RETURN_FALSE;
- }
- pgsql_row = (int) row;
- statement->row = pgsql_row;
- } else {
- /* If 2nd param is nullptr, use internal row counter to access next row */
- pgsql_row = statement->row;
- if (pgsql_row < 0 || pgsql_row >= PQntuples(pgsql_result)) {
- RETURN_FALSE;
- }
- statement->row++;
- }
-
- array_init(return_value);
- for (i = 0, num_fields = PQnfields(pgsql_result); i < num_fields; i++) {
- if (result_type & PGSQL_NUM) {
- zval value;
- php_pgsql_get_field_value(&value, pgsql_result, result_type, pgsql_row, i);
- add_index_zval(return_value, i, &value);
- }
-
- if (result_type & PGSQL_ASSOC) {
- zval value;
- php_pgsql_get_field_value(&value, pgsql_result, result_type, pgsql_row, i);
- field_name = PQfname(pgsql_result, i);
- add_assoc_zval(return_value, field_name, &value);
- }
- }
-
- if (into_object) {
- zval dataset;
- zend_fcall_info fci;
- zend_fcall_info_cache fcc;
- zval retval;
-
- ZVAL_COPY_VALUE(&dataset, return_value);
- object_and_properties_init(return_value, ce, nullptr);
- if (!ce->default_properties_count && !ce->__set) {
- Z_OBJ_P(return_value)->properties = Z_ARR(dataset);
- } else {
- zend_merge_properties(return_value, Z_ARRVAL(dataset));
- zval_ptr_dtor(&dataset);
- }
-
- if (ce->constructor) {
- fci.size = sizeof(fci);
- ZVAL_UNDEF(&fci.function_name);
- fci.object = Z_OBJ_P(return_value);
- fci.retval = &retval;
- fci.params = nullptr;
- fci.param_count = 0;
-
- if (ctor_params && Z_TYPE_P(ctor_params) != IS_NULL) {
- if (zend_fcall_info_args(&fci, ctor_params) == FAILURE) {
- /* Two problems why we throw exceptions here: PHP is typeless
- * and hence passing one argument that's not an array could be
- * by mistake and the other way round is possible, too. The
- * single value is an array. Also we'd have to make that one
- * argument passed by reference.
- */
- zend_throw_exception(zend_ce_exception, "Parameter ctor_params must be an array", 0);
- return;
- }
- }
-
- fcc.function_handler = ce->constructor;
- fcc.calling_scope = zend_get_executed_scope();
- fcc.called_scope = Z_OBJCE_P(return_value);
- fcc.object = Z_OBJ_P(return_value);
-
- if (zend_call_function(&fci, &fcc) == FAILURE) {
- zend_throw_exception_ex(zend_ce_exception,
- 0,
- "Could not execute %s::%s()",
- ZSTR_VAL(ce->name),
- ZSTR_VAL(ce->constructor->common.function_name));
- } else {
- zval_ptr_dtor(&retval);
- }
- if (fci.params) {
- efree(fci.params);
- }
- } else if (ctor_params) {
- zend_throw_exception_ex(zend_ce_exception,
- 0,
- "Class %s does not have a constructor hence you cannot use ctor_params",
- ZSTR_VAL(ce->name));
- }
- }
-}
-/* }}} */
-
-static int swoole_pgsql_coro_onError(Reactor *reactor, Event *event) {
- PGObject *object = (PGObject *) (event->socket->object);
-
- zend_update_property_string(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(object->object), ZEND_STRL("error"), "onerror");
- if (object->statement) {
- zend_update_property_string(
- swoole_postgresql_coro_statement_ce, SW_Z8_OBJ_P(object->statement->object), ZEND_STRL("error"), "onerror");
- object->statement = nullptr;
- }
- object->connected = false;
- ZVAL_FALSE(object->return_value);
- object->co->resume();
-
- return SW_OK;
-}
-
-static PHP_METHOD(swoole_postgresql_coro, __destruct) {}
-
-static int swoole_postgresql_coro_close(zval *zobject) {
- PGObject *object = php_swoole_postgresql_coro_get_object(zobject);
- if (!object || !object->conn) {
- php_swoole_fatal_error(E_WARNING, "object is not instanceof swoole_postgresql_coro");
- return FAILURE;
- }
-
- if (sw_reactor()) {
- Socket *_socket = object->socket;
- if (!_socket->removed) {
- sw_reactor()->del(_socket);
- }
- _socket->object = nullptr;
- _socket->free();
- }
-
- PGresult *res;
- if (object->connected) {
- while ((res = PQgetResult(object->conn))) {
- PQclear(res);
- }
- /**
- * PQfinish will close fd
- */
- PQfinish(object->conn);
- /**
- * fd marked -1, prevent double close
- */
- object->socket->fd = -1;
- object->conn = nullptr;
- object->connected = false;
- if (object->lob_streams) {
- swoole_pgsql_close_lob_streams(object);
- zend_hash_destroy(object->lob_streams);
- pefree(object->lob_streams, 1);
- object->lob_streams = nullptr;
- }
- }
- object->co = nullptr;
- return SUCCESS;
-}
-
-static PHP_METHOD(swoole_postgresql_coro, escape) {
- char *str;
- size_t l_str;
- PGconn *pgsql;
-
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STRING(str, l_str)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- PGObject *object = php_swoole_postgresql_coro_get_object(ZEND_THIS);
- if (!object || !object->conn) {
- RETURN_FALSE;
- }
- pgsql = object->conn;
-
- zend_string *result = zend_string_alloc(l_str * 2, 0);
- int error = 0;
- size_t new_len = PQescapeStringConn(object->conn, result->val, str, l_str, &error);
-
- if (new_len == 0 || error) {
- zend_update_property_string(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("error"), PQerrorMessage(pgsql));
- zend_update_property_long(swoole_postgresql_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errCode"), error);
- zend_string_free(result);
- RETURN_FALSE;
- } else {
- result->val[new_len] = 0;
- result->len = new_len;
- RETURN_STR(result);
- }
-}
-
-static PHP_METHOD(swoole_postgresql_coro, escapeLiteral) {
- char *str, *tmp;
- size_t l_str;
- PGconn *pgsql;
-
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STRING(str, l_str)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- PGObject *object = php_swoole_postgresql_coro_get_object(ZEND_THIS);
- if (!object || !object->conn) {
- RETURN_FALSE;
- }
- pgsql = object->conn;
-
- tmp = PQescapeLiteral(pgsql, str, l_str);
- if (tmp == nullptr) {
- zend_update_property_string(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("error"), PQerrorMessage(pgsql));
-
- RETURN_FALSE;
- }
-
- RETVAL_STRING(tmp);
- PQfreemem(tmp);
-}
-
-static PHP_METHOD(swoole_postgresql_coro, escapeIdentifier) {
- char *str, *tmp;
- size_t l_str;
- PGconn *pgsql;
-
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STRING(str, l_str)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- PGObject *object = php_swoole_postgresql_coro_get_object(ZEND_THIS);
- if (!object || !object->conn) {
- RETURN_FALSE;
- }
- pgsql = object->conn;
-
- tmp = PQescapeIdentifier(pgsql, str, l_str);
- if (tmp == nullptr) {
- zend_update_property_string(
- swoole_postgresql_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("error"), PQerrorMessage(pgsql));
-
- RETURN_FALSE;
- }
-
- RETVAL_STRING(tmp);
- PQfreemem(tmp);
-}
-
-/* {{{ swoole_pgsql_get_result */
-static PGresult *swoole_pgsql_get_result(PGObject *object) {
- PGresult *result, *last_result = nullptr;
-
- while ((result = PQgetResult(object->conn))) {
- PQclear(last_result);
- last_result = result;
- }
-
- return last_result;
-}
-/* }}} */
-
-/* {{{ swoole_pgsql_close_lob_streams */
-static void swoole_pgsql_close_lob_streams(PGObject *object) {
- zval *zres;
- if (object->lob_streams) {
- ZEND_HASH_FOREACH_VAL(object->lob_streams, zres) {
- zend_list_close(Z_RES_P(zres));
- }
- ZEND_HASH_FOREACH_END();
- }
-}
-/* }}} */
-
-/* {{{ swoole_pgsql_in_transaction */
-static inline bool swoole_pgsql_in_transaction(PGObject *object) {
- return PQtransactionStatus(object->conn) > PQTRANS_IDLE;
-}
-/* }}} */
-
-#endif
diff --git a/ext-src/swoole_process.cc b/ext-src/swoole_process.cc
index 77543fc84a7..667ffcc1cf8 100644
--- a/ext-src/swoole_process.cc
+++ b/ext-src/swoole_process.cc
@@ -52,7 +52,7 @@ Worker *php_swoole_process_get_worker(zval *zobject) {
Worker *php_swoole_process_get_and_check_worker(zval *zobject) {
Worker *worker = php_swoole_process_get_worker(zobject);
if (!worker) {
- php_swoole_fatal_error(E_ERROR, "you must call Process constructor first");
+ php_swoole_fatal_error(E_ERROR, "must call constructor first");
}
return worker;
}
@@ -601,10 +601,11 @@ void php_swoole_process_clean() {
signal_fci_caches[i] = nullptr;
}
}
-
- if (SwooleG.process_type != SW_PROCESS_USERWORKER) {
- SwooleG.process_type = 0;
+#ifndef SW_THREAD
+ if (swoole_get_process_type() != SW_PROCESS_USERWORKER) {
+ swoole_set_process_type(0);
}
+#endif
}
void php_swoole_process_rshutdown() {
@@ -644,7 +645,7 @@ int php_swoole_process_start(Worker *process, zval *zobject) {
}
php_swoole_process_clean();
- SwooleG.process_id = process->id;
+ swoole_set_process_id(process->id);
SwooleWG.worker = process;
zend_update_property_long(swoole_process_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("pid"), process->pid);
@@ -701,10 +702,6 @@ static PHP_METHOD(swoole_process, read) {
RETURN_FALSE;
}
- if (buf_size > 65536) {
- buf_size = 65536;
- }
-
Worker *process = php_swoole_process_get_and_check_worker(ZEND_THIS);
if (process->pipe_current == nullptr) {
diff --git a/ext-src/swoole_process_pool.cc b/ext-src/swoole_process_pool.cc
index fd7db5e7cfb..f14004f8ff1 100644
--- a/ext-src/swoole_process_pool.cc
+++ b/ext-src/swoole_process_pool.cc
@@ -567,7 +567,7 @@ static PHP_METHOD(swoole_process_pool, getProcess) {
php_swoole_error(E_WARNING, "invalid worker_id[%ld]", worker_id);
RETURN_FALSE;
} else if (worker_id < 0) {
- worker_id = SwooleG.process_id;
+ worker_id = swoole_get_process_id();
}
zval *zworkers =
@@ -584,11 +584,11 @@ static PHP_METHOD(swoole_process_pool, getProcess) {
*worker = current_pool->workers[worker_id];
object_init_ex(zprocess, swoole_process_ce);
- zend_update_property_long(swoole_process_ce, SW_Z8_OBJ_P(zprocess), ZEND_STRL("id"), SwooleG.process_id);
+ zend_update_property_long(swoole_process_ce, SW_Z8_OBJ_P(zprocess), ZEND_STRL("id"), swoole_get_process_id());
zend_update_property_long(swoole_process_ce, SW_Z8_OBJ_P(zprocess), ZEND_STRL("pid"), worker->pid);
if (current_pool->ipc_mode == SW_IPC_UNIXSOCK) {
// current process
- if (worker->id == SwooleG.process_id) {
+ if (worker->id == swoole_get_process_id()) {
worker->pipe_current = worker->pipe_worker;
} else {
worker->pipe_current = worker->pipe_master;
diff --git a/ext-src/swoole_redis_coro.cc b/ext-src/swoole_redis_coro.cc
deleted file mode 100644
index 8ab59ea27dc..00000000000
--- a/ext-src/swoole_redis_coro.cc
+++ /dev/null
@@ -1,5545 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | 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 "thirdparty/hiredis/hiredis.h"
-
-#include "ext/standard/php_var.h"
-
-using swoole::coroutine::Socket;
-using namespace swoole;
-
-#define SW_REDIS_COMMAND_ALLOC_ARGS_ARR zval *z_args = (zval *) emalloc(argc * sizeof(zval));
-#define SW_REDIS_COMMAND_ARGS_TYPE(arg) Z_TYPE(arg)
-#define SW_REDIS_COMMAND_ARGS_LVAL(arg) Z_LVAL(arg)
-#define SW_REDIS_COMMAND_ARGS_DVAL(arg) Z_DVAL(arg)
-#define SW_REDIS_COMMAND_ARGS_ARRVAL(arg) Z_ARRVAL(arg)
-#define SW_REDIS_COMMAND_ARGS_STRVAL(arg) Z_STRVAL(arg)
-#define SW_REDIS_COMMAND_ARGS_STRLEN(arg) Z_STRLEN(arg)
-#define SW_REDIS_COMMAND_ARGS_REF(arg) &arg
-
-#define SW_REDIS_COMMAND_BUFFER_SIZE 64
-#define SW_BITOP_MIN_OFFSET 0
-#define SW_BITOP_MAX_OFFSET 4294967295
-#define SW_REDIS_TYPE_NOT_FOUND 0
-#define SW_REDIS_TYPE_STRING 1
-#define SW_REDIS_TYPE_SET 2
-#define SW_REDIS_TYPE_LIST 3
-#define SW_REDIS_TYPE_ZSET 4
-#define SW_REDIS_TYPE_HASH 5
-
-/* The same errCode define with hiredis */
-enum swRedisError {
- SW_REDIS_ERR_IO = 1, /* Error in read or write */
- SW_REDIS_ERR_OTHER = 2, /* Everything else... */
- SW_REDIS_ERR_EOF = 3, /* End of file */
- SW_REDIS_ERR_PROTOCOL = 4, /* Protocol error */
- SW_REDIS_ERR_OOM = 5, /* Out of memory */
- SW_REDIS_ERR_CLOSED = 6, /* Closed */
- SW_REDIS_ERR_NOAUTH = 7, /* Authentication required */
- SW_REDIS_ERR_ALLOC = 8, /* Alloc failed */
-};
-
-/* Extended SET argument detection */
-// clang-format off
-#define IS_EX_ARG(a) \
- ((a[0]=='e' || a[0]=='E') && (a[1]=='x' || a[1]=='X') && a[2]=='\0')
-#define IS_PX_ARG(a) \
- ((a[0]=='p' || a[0]=='P') && (a[1]=='x' || a[1]=='X') && a[2]=='\0')
-#define IS_NX_ARG(a) \
- ((a[0]=='n' || a[0]=='N') && (a[1]=='x' || a[1]=='X') && a[2]=='\0')
-#define IS_XX_ARG(a) \
- ((a[0]=='x' || a[0]=='X') && (a[1]=='x' || a[1]=='X') && a[2]=='\0')
-
-static zend_class_entry *swoole_redis_coro_ce;
-static zend_object_handlers swoole_redis_coro_handlers;
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_construct, 0, 0, 0)
- ZEND_ARG_INFO(0, config)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_connect, 0, 0, 1)
- ZEND_ARG_INFO(0, host)
- ZEND_ARG_INFO(0, port)
- ZEND_ARG_INFO(0, serialize)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_setOptions, 0, 0, 1)
- ZEND_ARG_INFO(0, options)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_setDefer, 0, 0, 1)
- ZEND_ARG_INFO(0, defer)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_void, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_key, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_key_value, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_key_long, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, integer)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_request, 0, 0, 1)
- ZEND_ARG_ARRAY_INFO(0, params, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_append, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_auth, 0, 0, 1)
- ZEND_ARG_INFO(0, password)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_bgSave, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_bgrewriteaof, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_bitcount, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_bitop, 0, 0, 3)
- ZEND_ARG_INFO(0, operation)
- ZEND_ARG_INFO(0, ret_key)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, other_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_blPop, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, timeout_or_key)
- ZEND_ARG_INFO(0, extra_args)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_brPop, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, timeout_or_key)
- ZEND_ARG_INFO(0, extra_args)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_brpoplpush, 0, 0, 3)
- ZEND_ARG_INFO(0, src)
- ZEND_ARG_INFO(0, dst)
- ZEND_ARG_INFO(0, timeout)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_close, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_dbSize, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_debug, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_decr, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_decrBy, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_dump, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_eval, 0, 0, 1)
- ZEND_ARG_INFO(0, script)
- ZEND_ARG_INFO(0, args)
- ZEND_ARG_INFO(0, num_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_evalsha, 0, 0, 1)
- ZEND_ARG_INFO(0, script_sha)
- ZEND_ARG_INFO(0, args)
- ZEND_ARG_INFO(0, num_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_exec, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_exists, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, other_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_expireAt, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, timestamp)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_flushAll, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_flushDB, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_get, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_getBit, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, offset)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_getKeys, 0, 0, 1)
- ZEND_ARG_INFO(0, pattern)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_getRange, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, end)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_getSet, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hDel, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
- ZEND_ARG_INFO(0, other_members)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hExists, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hGet, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hGetAll, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hIncrBy, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hIncrByFloat, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hKeys, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hLen, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hMget, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hMset, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, pairs)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hSet, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hSetNx, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_hVals, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_incr, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_incrBy, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_incrByFloat, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lGet, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, index)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lGetRange, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, end)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lInsert, 0, 0, 4)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, position)
- ZEND_ARG_INFO(0, pivot)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lPop, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lPush, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lPushx, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lRemove, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
- ZEND_ARG_INFO(0, count)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lSet, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, index)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lSize, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lastSave, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_listTrim, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, stop)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_move, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, dbindex)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_mset, 0, 0, 1)
- ZEND_ARG_INFO(0, pairs)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_msetnx, 0, 0, 1)
- ZEND_ARG_INFO(0, pairs)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_multi, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_persist, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_pexpire, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, timestamp)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_pexpireAt, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, timestamp)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_pfadd, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, elements)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_pfcount, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_pfmerge, 0, 0, 2)
- ZEND_ARG_INFO(0, dstkey)
- ZEND_ARG_INFO(0, keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_ping, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_psetex, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, expire)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_psubscribe, 0, 0, 1)
- ZEND_ARG_INFO(0, patterns)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_punsubscribe, 0, 0, 1)
- ZEND_ARG_INFO(0, patterns)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_pttl, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_publish, 0, 0, 2)
- ZEND_ARG_INFO(0, channel)
- ZEND_ARG_INFO(0, message)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_rPop, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_rPush, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_rPushx, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_randomKey, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_renameKey, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, newkey)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_renameNx, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, newkey)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_restore, 0, 0, 3)
- ZEND_ARG_INFO(0, ttl)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_role, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_rpoplpush, 0, 0, 2)
- ZEND_ARG_INFO(0, src)
- ZEND_ARG_INFO(0, dst)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sAdd, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sContains, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sDiff, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, other_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sDiffStore, 0, 0, 2)
- ZEND_ARG_INFO(0, dst)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, other_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sInter, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, other_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sInterStore, 0, 0, 2)
- ZEND_ARG_INFO(0, dst)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, other_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sMembers, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sMove, 0, 0, 3)
- ZEND_ARG_INFO(0, src)
- ZEND_ARG_INFO(0, dst)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sPop, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sRandMember, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, count)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sRemove, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sSize, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sUnion, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, other_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_sUnionStore, 0, 0, 2)
- ZEND_ARG_INFO(0, dst)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, other_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_save, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_script, 0, 0, 1)
- ZEND_ARG_INFO(0, cmd)
- ZEND_ARG_INFO(0, args)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_select, 0, 0, 1)
- ZEND_ARG_INFO(0, dbindex)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_set, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
- ZEND_ARG_INFO(0, timeout)
- ZEND_ARG_INFO(0, opt)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_setBit, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, offset)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_setRange, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, offset)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_setTimeout, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, timeout)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_setex, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, expire)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_setnx, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_strlen, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_subscribe, 0, 0, 1)
- ZEND_ARG_INFO(0, channels)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_unsubscribe, 0, 0, 1)
- ZEND_ARG_INFO(0, channels)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_time, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_ttl, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_type, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_unwatch, 0, 0, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_watch, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, other_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zAdd, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, score)
- ZEND_ARG_INFO(0, value)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zPopMin, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, count)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zPopMax, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, count)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_bzPopMin, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, timeout_or_key)
- ZEND_ARG_INFO(0, extra_args)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_bzPopMax, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, timeout_or_key)
- ZEND_ARG_INFO(0, extra_args)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zCard, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zCount, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, min)
- ZEND_ARG_INFO(0, max)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zDelete, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
- ZEND_ARG_INFO(0, other_members)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zDeleteRangeByRank, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, end)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zDeleteRangeByScore, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, min)
- ZEND_ARG_INFO(0, max)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zIncrBy, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
- ZEND_ARG_INFO(0, member)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zInter, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, keys)
- ZEND_ARG_INFO(0, weights)
- ZEND_ARG_INFO(0, aggregate)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRange, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, end)
- ZEND_ARG_INFO(0, scores)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRangeByLex, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, min)
- ZEND_ARG_INFO(0, max)
- ZEND_ARG_INFO(0, offset)
- ZEND_ARG_INFO(0, limit)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRangeByScore, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, end)
- ZEND_ARG_INFO(0, options)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRank, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRevRange, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, end)
- ZEND_ARG_INFO(0, scores)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRevRangeByLex, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, min)
- ZEND_ARG_INFO(0, max)
- ZEND_ARG_INFO(0, offset)
- ZEND_ARG_INFO(0, limit)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRevRangeByScore, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, end)
- ZEND_ARG_INFO(0, options)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRevRank, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zScore, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zUnion, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, keys)
- ZEND_ARG_INFO(0, weights)
- ZEND_ARG_INFO(0, aggregate)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_del, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, other_keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lLen, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lrange, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, end)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_lrem, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, value)
- ZEND_ARG_INFO(0, count)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_ltrim, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, stop)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_mget, 0, 0, 1)
- ZEND_ARG_INFO(0, keys)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_rename, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, newkey)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_scard, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRem, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
- ZEND_ARG_INFO(0, other_members)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRemRangeByRank, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, min)
- ZEND_ARG_INFO(0, max)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRemRangeByScore, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, min)
- ZEND_ARG_INFO(0, max)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zRemove, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, member)
- ZEND_ARG_INFO(0, other_members)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zSize, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zinterstore, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, keys)
- ZEND_ARG_INFO(0, weights)
- ZEND_ARG_INFO(0, aggregate)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_zunionstore, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, keys)
- ZEND_ARG_INFO(0, weights)
- ZEND_ARG_INFO(0, aggregate)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xLen, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xAdd, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, id)
- ZEND_ARG_INFO(0, pairs)
- ZEND_ARG_INFO(0, options)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xRead, 0, 0, 1)
- ZEND_ARG_INFO(0, streams)
- ZEND_ARG_INFO(0, options)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xDel, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xRange, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, end)
- ZEND_ARG_INFO(0, count)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xRevRange, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, end)
- ZEND_ARG_INFO(0, count)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xTrim, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, options)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xGroupCreate, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, group_name)
- ZEND_ARG_INFO(0, id)
- ZEND_ARG_INFO(0, mkstream)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xGroupSetId, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, group_name)
- ZEND_ARG_INFO(0, id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xGroupDestroy, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, group_name)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xGroupCreateConsumer, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, group_name)
- ZEND_ARG_INFO(0, consumer_name)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xGroupDelConsumer, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, group_name)
- ZEND_ARG_INFO(0, consumer_name)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xReadGroup, 0, 0, 3)
- ZEND_ARG_INFO(0, group_name)
- ZEND_ARG_INFO(0, consumer_name)
- ZEND_ARG_INFO(0, streams)
- ZEND_ARG_INFO(0, options)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xPending, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, group_name)
- ZEND_ARG_INFO(0, options)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xAck, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, group_name)
- ZEND_ARG_INFO(0, id)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xClaim, 0, 0, 5)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, group_name)
- ZEND_ARG_INFO(0, consumer_name)
- ZEND_ARG_INFO(0, min_idle_time)
- ZEND_ARG_INFO(0, id)
- ZEND_ARG_INFO(0, options)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xAutoClaim, 0, 0, 5)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, group_name)
- ZEND_ARG_INFO(0, consumer_name)
- ZEND_ARG_INFO(0, min_idle_time)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, options)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xInfoConsumers, 0, 0, 2)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, group_name)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xInfoGroups, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_redis_coro_xInfoStream, 0, 0, 1)
- ZEND_ARG_INFO(0, key)
-ZEND_END_ARG_INFO()
-// clang-format on
-
-#define IS_EX_PX_ARG(a) (IS_EX_ARG(a) || IS_PX_ARG(a))
-#define IS_NX_XX_ARG(a) (IS_NX_ARG(a) || IS_XX_ARG(a))
-
-struct RedisClient {
- redisContext *context;
- struct {
- bool auth;
- long db_num;
- bool subscribe;
- } session;
- double connect_timeout;
- double timeout;
- bool serialize;
- bool defer;
- uint8_t reconnect_interval;
- uint8_t reconnected_count;
- bool auth;
- bool compatibility_mode;
- long database;
- zval *zobject;
- zval _zobject;
- zend_object std;
-};
-
-#define SW_REDIS_COMMAND_CHECK \
- Coroutine::get_current_safe(); \
- RedisClient *redis = php_swoole_get_redis_client(ZEND_THIS);
-
-#define SW_REDIS_COMMAND_ARGV_FILL(str, str_len) \
- argvlen[i] = str_len; \
- argv[i] = estrndup(str, str_len); \
- i++;
-
-#define SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(_val) \
- if (redis->serialize) { \
- smart_str sstr = {}; \
- php_serialize_data_t s_ht; \
- PHP_VAR_SERIALIZE_INIT(s_ht); \
- php_var_serialize(&sstr, _val, &s_ht); \
- argvlen[i] = (size_t) sstr.s->len; \
- argv[i] = estrndup(sstr.s->val, sstr.s->len); \
- zend_string_release(sstr.s); \
- PHP_VAR_SERIALIZE_DESTROY(s_ht); \
- } else { \
- zend_string *convert_str = zval_get_string(_val); \
- argvlen[i] = ZSTR_LEN(convert_str); \
- argv[i] = estrndup(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str)); \
- zend_string_release(convert_str); \
- } \
- i++;
-
-#define SW_REDIS_COMMAND_ALLOC_ARGV \
- size_t stack_argvlen[SW_REDIS_COMMAND_BUFFER_SIZE]; \
- char *stack_argv[SW_REDIS_COMMAND_BUFFER_SIZE]; \
- size_t *argvlen; \
- char **argv; \
- if (argc > SW_REDIS_COMMAND_BUFFER_SIZE) { \
- argvlen = (size_t *) emalloc(sizeof(size_t) * (argc)); \
- argv = (char **) emalloc(sizeof(char *) * (argc)); \
- } else { \
- argvlen = stack_argvlen; \
- argv = stack_argv; \
- }
-
-#define SW_REDIS_COMMAND_INCREASE_ARGV(_new_argc) \
- if (_new_argc > SW_REDIS_COMMAND_BUFFER_SIZE && _new_argc > argc) { \
- size_t *tmp_argvlen; \
- char **tmp_argv; \
- tmp_argvlen = (size_t *) emalloc(sizeof(size_t) * (_new_argc)); \
- tmp_argv = (char **) emalloc(sizeof(char *) * (_new_argc)); \
- for (int argc_i = 0; argc_i < argc; argc_i++) { \
- tmp_argvlen[argc_i] = argvlen[argc_i]; \
- tmp_argv[argc_i] = argv[argc_i]; \
- } \
- argvlen = tmp_argvlen; \
- argv = tmp_argv; \
- } \
- argc = _new_argc;
-
-#define SW_REDIS_COMMAND_FREE_ARGV \
- if (argv != stack_argv) { \
- efree(argvlen); \
- efree(argv); \
- }
-
-enum { SW_REDIS_MODE_MULTI, SW_REDIS_MODE_PIPELINE };
-
-static void swoole_redis_coro_parse_result(RedisClient *redis, zval *return_value, redisReply *reply);
-
-static sw_inline RedisClient *php_swoole_redis_coro_fetch_object(zend_object *obj) {
- return (RedisClient *) ((char *) obj - swoole_redis_coro_handlers.offset);
-}
-
-static sw_inline RedisClient *php_swoole_get_redis_client(zval *zobject) {
- RedisClient *redis = (RedisClient *) php_swoole_redis_coro_fetch_object(Z_OBJ_P(zobject));
- if (UNEXPECTED(!redis)) {
- php_swoole_fatal_error(E_ERROR, "you must call Redis constructor first");
- }
- return redis;
-}
-
-static sw_inline std::shared_ptr swoole_redis_coro_get_socket(redisContext *context) {
- if (context->fd > 0 && SwooleTG.reactor) {
- return swoole_coroutine_get_socket_object(context->fd);
- }
- return nullptr;
-}
-
-static sw_inline bool swoole_redis_coro_close(RedisClient *redis) {
- if (redis->context) {
- int sockfd = redis->context->fd;
- auto socket = swoole_redis_coro_get_socket(redis->context);
- swoole_trace_log(SW_TRACE_REDIS_CLIENT, "redis connection closed, fd=%d", sockfd);
- zend_update_property_bool(swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("connected"), 0);
- if (!(socket != nullptr && socket->has_bound())) {
- redisFreeKeepFd(redis->context);
- redis->context = nullptr;
- redis->session = {false, 0, false};
- }
- if (socket != nullptr) {
- swoole_coroutine_close(sockfd);
- }
- return true;
- }
- return false;
-}
-
-static void php_swoole_redis_coro_free_object(zend_object *object) {
- RedisClient *redis = php_swoole_redis_coro_fetch_object(object);
-
- if (redis && redis->context) {
- swoole_redis_coro_close(redis);
- }
-
- zend_object_std_dtor(&redis->std);
-}
-
-static zend_object *php_swoole_redis_coro_create_object(zend_class_entry *ce) {
- RedisClient *redis = (RedisClient *) zend_object_alloc(sizeof(RedisClient), ce);
- zend_object_std_init(&redis->std, ce);
- object_properties_init(&redis->std, ce);
- redis->std.handlers = &swoole_redis_coro_handlers;
- return &redis->std;
-}
-
-static sw_inline int sw_redis_convert_err(int err) {
- switch (err) {
- case SW_REDIS_ERR_IO:
- return errno;
- case SW_REDIS_ERR_EOF:
- case SW_REDIS_ERR_CLOSED:
- return ECONNRESET;
- case SW_REDIS_ERR_OTHER:
- return EINVAL;
- case SW_REDIS_ERR_OOM:
- case SW_REDIS_ERR_ALLOC:
- return ENOMEM;
- case SW_REDIS_ERR_PROTOCOL:
- return EPROTO;
- case SW_REDIS_ERR_NOAUTH:
- return EACCES;
- case 0:
- return 0;
- default:
- return errno;
- }
-}
-
-static sw_inline void swoole_redis_handle_assoc_array_result(zval *return_value, bool str2double) {
- zval *zkey, *zvalue;
- zval zret;
- bool is_key = false;
-
- array_init(&zret);
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(return_value), zvalue) {
- if ((is_key = !is_key)) {
- zkey = zvalue;
- } else {
- if (str2double) {
- convert_to_double(zvalue);
- } else {
- Z_ADDREF_P(zvalue);
- }
- add_assoc_zval_ex(&zret, Z_STRVAL_P(zkey), Z_STRLEN_P(zkey), zvalue);
- }
- }
- ZEND_HASH_FOREACH_END();
-
- zval_ptr_dtor(return_value);
- RETVAL_ZVAL(&zret, 1, 1);
-}
-
-static bool redis_auth(RedisClient *redis, char *pw, size_t pw_len);
-static bool redis_select_db(RedisClient *redis, long db_number);
-static void redis_request(
- RedisClient *redis, int argc, char **argv, size_t *argvlen, zval *return_value, bool retry = false);
-
-static bool swoole_redis_coro_connect(RedisClient *redis) {
- zval *zobject = redis->zobject;
- redisContext *context;
- struct timeval tv;
- zval *ztmp;
- zval *zhost = sw_zend_read_property_ex(swoole_redis_coro_ce, zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_HOST), 0);
- zval *zport = sw_zend_read_property_ex(swoole_redis_coro_ce, zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_PORT), 0);
- zend::String host(zhost);
- zend_long port = zval_get_long(zport);
-
- if (host.len() == 0) {
- php_swoole_fatal_error(E_WARNING, "The host is empty");
- return false;
- }
-
- if (redis->context) {
- context = redis->context;
- if (context->connection_type == REDIS_CONN_TCP && strcmp(context->tcp.host, host.val()) == 0 &&
- context->tcp.port == port) {
- return true;
- } else if (context->connection_type == REDIS_CONN_UNIX &&
- (strstr(host.val(), context->unix_sock.path) - host.val()) + strlen(context->unix_sock.path) ==
- host.len()) {
- return true;
- } else {
- swoole_redis_coro_close(redis);
- }
- }
-
- php_swoole_check_reactor();
-
- if (redis->connect_timeout > 0) {
- tv.tv_sec = redis->connect_timeout;
- tv.tv_usec = (redis->connect_timeout - (double) tv.tv_sec) * 1000 * 1000;
- }
- if (SW_STR_ISTARTS_WITH(host.val(), host.len(), "unix:/")) {
- context = redisConnectUnixWithTimeout(host.val() + 5 + strspn(host.val() + 5, "/") - 1, tv);
- } else {
- if (port <= 0 || port > SW_CLIENT_MAX_PORT) {
- php_swoole_fatal_error(E_WARNING, "The port " ZEND_LONG_FMT " is invalid", port);
- return false;
- }
- context = redisConnectWithTimeout(host.val(), (int) port, tv);
- }
-
- redis->context = context;
-
- if (!context) {
- zend_update_property_long(swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errType"), SW_REDIS_ERR_ALLOC);
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errCode"), sw_redis_convert_err(SW_REDIS_ERR_ALLOC));
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errMsg"), "cannot allocate redis context");
- return false;
- }
- if (context->err) {
- zend_update_property_long(swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errType"), context->err);
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errCode"), sw_redis_convert_err(context->err));
- zend_update_property_string(swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errMsg"), context->errstr);
- swoole_redis_coro_close(redis);
- return false;
- }
- auto socket = swoole_redis_coro_get_socket(context);
- if (socket == nullptr) {
- zend_update_property_long(swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errCode"), sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errMsg"), "Can not found the connection");
- swoole_redis_coro_close(redis);
- return false;
- }
-
- socket->set_timeout(redis->timeout, Socket::TIMEOUT_RDWR);
- redis->reconnected_count = 0;
- zend_update_property_bool(swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("connected"), 1);
- zend_update_property_long(swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("sock"), context->fd);
-
- // auth and select db after connected
- zval *zsetting =
- sw_zend_read_and_convert_property_array(swoole_redis_coro_ce, redis->zobject, ZEND_STRL("setting"), 0);
- HashTable *vht = Z_ARRVAL_P(zsetting);
-
- if (php_swoole_array_get_value(vht, "password", ztmp)) {
- zend::String passowrd(ztmp);
- if (passowrd.len() > 0 && !redis_auth(redis, passowrd.val(), passowrd.len())) {
- swoole_redis_coro_close(redis);
- return false;
- }
- }
- if (php_swoole_array_get_value(vht, "database", ztmp)) {
- zend_long db_number = zval_get_long(ztmp);
- // default is 0, don't need select
- if (db_number > 0 && !redis_select_db(redis, db_number)) {
- swoole_redis_coro_close(redis);
- return false;
- }
- }
- return true;
-}
-
-static sw_inline bool swoole_redis_coro_keep_liveness(RedisClient *redis) {
- std::shared_ptr socket;
- if (!redis->context || !(socket = swoole_redis_coro_get_socket(redis->context)) || !socket->check_liveness()) {
- if (socket) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errType"), SW_REDIS_ERR_CLOSED);
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errCode"), socket->errCode);
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errMsg"), socket->errMsg);
- }
- swoole_redis_coro_close(redis);
- for (; redis->reconnected_count < redis->reconnect_interval; redis->reconnected_count++) {
- if (swoole_redis_coro_connect(redis)) {
- return true;
- }
- }
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errType"), SW_REDIS_ERR_CLOSED);
- // Notice: do not update errCode
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errMsg"), "connection is not available");
- return false;
- }
- return true;
-}
-
-static bool redis_auth(RedisClient *redis, char *pw, size_t pw_len) {
- int i = 0;
- size_t argvlen[2];
- char *argv[2];
- bool ret;
- zval retval;
-
- SW_REDIS_COMMAND_ARGV_FILL("AUTH", 4)
- SW_REDIS_COMMAND_ARGV_FILL(pw, pw_len)
- redis_request(redis, 2, argv, argvlen, &retval);
- ret = Z_BVAL_P(&retval);
- if (ret) {
- redis->session.auth = true;
- }
- return ret;
-}
-
-static bool redis_select_db(RedisClient *redis, long db_number) {
- int i = 0;
- size_t argvlen[2];
- char *argv[2];
- char str[32];
- bool ret;
- zval retval;
-
- SW_REDIS_COMMAND_ARGV_FILL("SELECT", 6)
- sprintf(str, "%ld", db_number);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
- redis_request(redis, 2, argv, argvlen, &retval);
- ret = Z_BVAL_P(&retval);
- if (ret) {
- redis->session.db_num = db_number;
- }
- return ret;
-}
-
-static void redis_request(RedisClient *redis, int argc, char **argv, size_t *argvlen, zval *return_value, bool retry) {
- redisReply *reply = nullptr;
- if (!swoole_redis_coro_keep_liveness(redis)) {
- ZVAL_FALSE(return_value);
- } else {
- // must clear err before request
- redis->context->err = 0;
- zend_update_property_long(swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errType"), 0);
- zend_update_property_long(swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errCode"), 0);
- zend_update_property_string(swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errMsg"), "");
- if (redis->defer) {
- if (redisAppendCommandArgv(redis->context, argc, (const char **) argv, (const size_t *) argvlen) ==
- REDIS_ERR) {
- goto _error;
- } else {
- ZVAL_TRUE(return_value);
- }
- } else {
- reply =
- (redisReply *) redisCommandArgv(redis->context, argc, (const char **) argv, (const size_t *) argvlen);
- if (reply == nullptr) {
- _error:
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errType"), redis->context->err);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(redis->zobject),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(redis->context->err));
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errMsg"), redis->context->errstr);
- ZVAL_FALSE(return_value);
- swoole_redis_coro_close(redis);
- } else {
- // Redis Cluster
- if (reply->type == REDIS_REPLY_ERROR &&
- (!strncmp(reply->str, "MOVED", 5) || !strcmp(reply->str, "ASK"))) {
- char *p1, *p2;
- // MOVED 1234 127.0.0.1:1234
- p1 = strrchr(reply->str, ' ') + 1; // MOVED 1234 [p1]27.0.0.1:1234
- p2 = strrchr(p1, ':'); // MOVED 1234 [p1]27.0.0.1[p2]1234
- *p2 = '\0';
- int port = atoi(p2 + 1);
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("host"), p1);
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("port"), port);
-
- if (swoole_redis_coro_connect(redis) > 0) {
- freeReplyObject(reply);
- redis_request(redis, argc, argv, argvlen, return_value, retry);
- return;
- } else {
- ZVAL_FALSE(return_value);
- }
- }
- // Normal Response
- else {
- swoole_redis_coro_parse_result(redis, return_value, reply);
- }
- freeReplyObject(reply);
- }
- }
- }
- SW_LOOP_N(argc) {
- efree(argv[i]);
- }
-}
-
-static sw_inline void sw_redis_command_empty(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[1];
- char *argv[1];
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- redis_request(redis, 1, argv, argvlen, return_value);
-}
-
-static sw_inline void sw_redis_command_var_key(
- INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len, int min_argc, int has_timeout) {
- long timeout;
- int argc = ZEND_NUM_ARGS();
- if (argc < min_argc) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGS_ARR
- if (argc == 0 || zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
- efree(z_args);
- RETURN_FALSE;
- }
- zend_bool single_array = 0;
- if (has_timeout == 0) {
- single_array = argc == 1 && SW_REDIS_COMMAND_ARGS_TYPE(z_args[0]) == IS_ARRAY;
- } else {
- single_array = argc == 2 && SW_REDIS_COMMAND_ARGS_TYPE(z_args[0]) == IS_ARRAY &&
- SW_REDIS_COMMAND_ARGS_TYPE(z_args[1]) == IS_LONG;
- timeout = SW_REDIS_COMMAND_ARGS_LVAL(z_args[1]);
- }
- if (single_array) {
- argc = zend_hash_num_elements(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0])) + 1;
- } else {
- argc++;
- }
-
- SW_REDIS_COMMAND_ALLOC_ARGV
- int i = 0;
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- char buf[32];
- size_t buf_len;
- if (single_array) {
- zval *value;
- SW_HASHTABLE_FOREACH_START(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0]), value)
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- SW_HASHTABLE_FOREACH_END();
- if (has_timeout) {
- buf_len = sw_snprintf(buf, sizeof(buf), "%ld", timeout);
- SW_REDIS_COMMAND_ARGV_FILL((char *) buf, buf_len);
- }
- } else {
- if (has_timeout && SW_REDIS_COMMAND_ARGS_TYPE(z_args[argc - 2]) != IS_LONG) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(redis->zobject),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errMsg"), "Timeout value must be a LONG");
- efree(z_args);
- RETURN_FALSE;
- }
- int j, tail;
- tail = has_timeout ? argc - 2 : argc - 1;
- for (j = 0; j < tail; ++j) {
- zend_string *convert_str = zval_get_string(&z_args[j]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- }
- if (has_timeout) {
- buf_len = sw_snprintf(buf, sizeof(buf), ZEND_LONG_FMT, SW_REDIS_COMMAND_ARGS_LVAL(z_args[tail]));
- SW_REDIS_COMMAND_ARGV_FILL((char *) buf, buf_len);
- }
- }
- efree(z_args);
-
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static inline void sw_redis_command_key(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- char *key;
- size_t key_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &key, &key_len) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[2];
- char *argv[2];
- int argc = 2;
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode) {
- if (ZVAL_IS_ARRAY(return_value) && sw_mem_equal(ZEND_STRL("HGETALL"), cmd, cmd_len)) {
- swoole_redis_handle_assoc_array_result(return_value, false);
- } else if (ZVAL_IS_NULL(return_value) && sw_mem_equal(ZEND_STRL("GET"), cmd, cmd_len)) {
- RETURN_FALSE;
- }
- }
-}
-
-static sw_inline void sw_redis_command_key_var_val(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- int argc = ZEND_NUM_ARGS();
- // We at least need a key and one value
- if (argc < 2) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- // Make sure we at least have a key, and we can get other args
- SW_REDIS_COMMAND_ALLOC_ARGS_ARR
- if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
- efree(z_args);
- RETURN_FALSE;
- }
-
- int i = 0, j;
- argc++;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- zend_string *convert_str = zval_get_string(&z_args[0]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- for (j = 1; j < argc - 1; ++j) {
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(SW_REDIS_COMMAND_ARGS_REF(z_args[j]))
- }
- efree(z_args);
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static sw_inline void sw_redis_command_key_long_val(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- char *key;
- size_t key_len;
- long l_val;
- zval *z_value;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "slz", &key, &key_len, &l_val, &z_value) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- int argc = 4;
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char str[32];
- sprintf(str, "%ld", l_val);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(z_value)
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static sw_inline void sw_redis_command_key_long_str(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- char *key, *val;
- size_t key_len, val_len;
- long l_val;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sls", &key, &key_len, &l_val, &val, &val_len) == FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- int argc = 4;
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char str[32];
- sprintf(str, "%ld", l_val);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
- SW_REDIS_COMMAND_ARGV_FILL(val, val_len)
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static sw_inline void sw_redis_command_key_long(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- char *key;
- size_t key_len;
- long l_val;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &key, &key_len, &l_val) == FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[3];
- char *argv[3];
- int argc = 3;
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char str[32];
- sprintf(str, "%ld", l_val);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static sw_inline void sw_redis_command_key_long_long(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- char *key;
- size_t key_len;
- long l1_val, l2_val;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll", &key, &key_len, &l1_val, &l2_val) == FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- int argc = 4;
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char str[32];
- sprintf(str, "%ld", l1_val);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
- sprintf(str, "%ld", l2_val);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static sw_inline void sw_redis_command_key_dbl(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- char *key;
- size_t key_len;
- double d_val;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sd", &key, &key_len, &d_val) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[3];
- char *argv[3];
- int argc = 3;
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char str[32];
- sprintf(str, "%f", d_val);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static sw_inline void sw_redis_command_key_key(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- char *key1, *key2;
- size_t key1_len, key2_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &key1, &key1_len, &key2, &key2_len) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[3];
- char *argv[3];
- int argc = 3;
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- SW_REDIS_COMMAND_ARGV_FILL(key1, key1_len)
- SW_REDIS_COMMAND_ARGV_FILL(key2, key2_len)
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static sw_inline void sw_redis_command_key_val(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- char *key;
- size_t key_len;
- zval *z_value;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &key, &key_len, &z_value) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[3];
- char *argv[3];
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(z_value)
- redis_request(redis, 3, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_NULL(return_value) && strncmp("ZRANK", cmd, cmd_len) == 0) {
- RETURN_FALSE;
- }
-}
-
-static sw_inline void sw_redis_command_key_str(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- char *key, *val;
- size_t key_len, val_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &key, &key_len, &val, &val_len) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[3];
- char *argv[3];
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(val, val_len)
- redis_request(redis, 3, argv, argvlen, return_value);
-}
-
-static sw_inline void sw_redis_command_key_str_str(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- char *key, *val1, *val2;
- size_t key_len, val1_len, val2_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss", &key, &key_len, &val1, &val1_len, &val2, &val2_len) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(val1, val1_len)
- SW_REDIS_COMMAND_ARGV_FILL(val2, val2_len)
- redis_request(redis, 4, argv, argvlen, return_value);
-}
-
-static sw_inline void sw_redis_command_xrange(INTERNAL_FUNCTION_PARAMETERS, const char *cmd, int cmd_len) {
- char *key, *val1, *val2;
- size_t key_len, val1_len, val2_len;
- zend_long count = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|l", &key, &key_len, &val1, &val1_len, &val2, &val2_len, &count) ==
- FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0, argc;
- argc = ZEND_NUM_ARGS() == 4 ? 6 : 4;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL(cmd, cmd_len)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(val1, val1_len)
- SW_REDIS_COMMAND_ARGV_FILL(val2, val2_len)
- if (count > 0) {
- SW_REDIS_COMMAND_ARGV_FILL("COUNT", 5)
- char buf[32];
- size_t buf_len;
- buf_len = sprintf(buf, ZEND_LONG_FMT, count);
- SW_REDIS_COMMAND_ARGV_FILL((char *) buf, buf_len)
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-SW_EXTERN_C_BEGIN
-static PHP_METHOD(swoole_redis_coro, __construct);
-static PHP_METHOD(swoole_redis_coro, __destruct);
-static PHP_METHOD(swoole_redis_coro, connect);
-static PHP_METHOD(swoole_redis_coro, getAuth);
-static PHP_METHOD(swoole_redis_coro, getDBNum);
-static PHP_METHOD(swoole_redis_coro, getOptions);
-static PHP_METHOD(swoole_redis_coro, setOptions);
-static PHP_METHOD(swoole_redis_coro, getDefer);
-static PHP_METHOD(swoole_redis_coro, setDefer);
-static PHP_METHOD(swoole_redis_coro, recv);
-static PHP_METHOD(swoole_redis_coro, request);
-static PHP_METHOD(swoole_redis_coro, close);
-/*---------------------Redis Command------------------------*/
-static PHP_METHOD(swoole_redis_coro, set);
-static PHP_METHOD(swoole_redis_coro, setBit);
-static PHP_METHOD(swoole_redis_coro, setEx);
-static PHP_METHOD(swoole_redis_coro, psetEx);
-static PHP_METHOD(swoole_redis_coro, lSet);
-static PHP_METHOD(swoole_redis_coro, get);
-static PHP_METHOD(swoole_redis_coro, mGet);
-static PHP_METHOD(swoole_redis_coro, del);
-static PHP_METHOD(swoole_redis_coro, hDel);
-static PHP_METHOD(swoole_redis_coro, hSet);
-static PHP_METHOD(swoole_redis_coro, hMSet);
-static PHP_METHOD(swoole_redis_coro, hSetNx);
-static PHP_METHOD(swoole_redis_coro, mSet);
-static PHP_METHOD(swoole_redis_coro, mSetNx);
-static PHP_METHOD(swoole_redis_coro, getKeys);
-static PHP_METHOD(swoole_redis_coro, exists);
-static PHP_METHOD(swoole_redis_coro, type);
-static PHP_METHOD(swoole_redis_coro, strLen);
-static PHP_METHOD(swoole_redis_coro, lPop);
-static PHP_METHOD(swoole_redis_coro, blPop);
-static PHP_METHOD(swoole_redis_coro, rPop);
-static PHP_METHOD(swoole_redis_coro, brPop);
-static PHP_METHOD(swoole_redis_coro, bRPopLPush);
-static PHP_METHOD(swoole_redis_coro, lSize);
-static PHP_METHOD(swoole_redis_coro, sSize);
-static PHP_METHOD(swoole_redis_coro, sPop);
-static PHP_METHOD(swoole_redis_coro, sMembers);
-static PHP_METHOD(swoole_redis_coro, sRandMember);
-static PHP_METHOD(swoole_redis_coro, persist);
-static PHP_METHOD(swoole_redis_coro, ttl);
-static PHP_METHOD(swoole_redis_coro, pttl);
-static PHP_METHOD(swoole_redis_coro, zCard);
-static PHP_METHOD(swoole_redis_coro, hLen);
-static PHP_METHOD(swoole_redis_coro, hKeys);
-static PHP_METHOD(swoole_redis_coro, hVals);
-static PHP_METHOD(swoole_redis_coro, hGetAll);
-static PHP_METHOD(swoole_redis_coro, restore);
-static PHP_METHOD(swoole_redis_coro, dump);
-static PHP_METHOD(swoole_redis_coro, debug);
-static PHP_METHOD(swoole_redis_coro, renameKey);
-static PHP_METHOD(swoole_redis_coro, renameNx);
-static PHP_METHOD(swoole_redis_coro, rpoplpush);
-static PHP_METHOD(swoole_redis_coro, randomKey);
-static PHP_METHOD(swoole_redis_coro, pfadd);
-static PHP_METHOD(swoole_redis_coro, pfcount);
-static PHP_METHOD(swoole_redis_coro, pfmerge);
-static PHP_METHOD(swoole_redis_coro, ping);
-static PHP_METHOD(swoole_redis_coro, auth);
-static PHP_METHOD(swoole_redis_coro, unwatch);
-static PHP_METHOD(swoole_redis_coro, watch);
-static PHP_METHOD(swoole_redis_coro, save);
-static PHP_METHOD(swoole_redis_coro, bgSave);
-static PHP_METHOD(swoole_redis_coro, lastSave);
-static PHP_METHOD(swoole_redis_coro, flushDB);
-static PHP_METHOD(swoole_redis_coro, flushAll);
-static PHP_METHOD(swoole_redis_coro, dbSize);
-static PHP_METHOD(swoole_redis_coro, bgrewriteaof);
-static PHP_METHOD(swoole_redis_coro, time);
-static PHP_METHOD(swoole_redis_coro, role);
-static PHP_METHOD(swoole_redis_coro, setRange);
-static PHP_METHOD(swoole_redis_coro, setNx);
-static PHP_METHOD(swoole_redis_coro, getSet);
-static PHP_METHOD(swoole_redis_coro, append);
-static PHP_METHOD(swoole_redis_coro, lPushx);
-static PHP_METHOD(swoole_redis_coro, lPush);
-static PHP_METHOD(swoole_redis_coro, rPush);
-static PHP_METHOD(swoole_redis_coro, rPushx);
-static PHP_METHOD(swoole_redis_coro, sContains);
-static PHP_METHOD(swoole_redis_coro, zScore);
-static PHP_METHOD(swoole_redis_coro, zRank);
-static PHP_METHOD(swoole_redis_coro, zRevRank);
-static PHP_METHOD(swoole_redis_coro, hGet);
-static PHP_METHOD(swoole_redis_coro, hMGet);
-static PHP_METHOD(swoole_redis_coro, hExists);
-static PHP_METHOD(swoole_redis_coro, publish);
-static PHP_METHOD(swoole_redis_coro, zIncrBy);
-static PHP_METHOD(swoole_redis_coro, zAdd);
-static PHP_METHOD(swoole_redis_coro, zPopMin);
-static PHP_METHOD(swoole_redis_coro, zPopMax);
-static PHP_METHOD(swoole_redis_coro, bzPopMin);
-static PHP_METHOD(swoole_redis_coro, bzPopMax);
-static PHP_METHOD(swoole_redis_coro, zDeleteRangeByScore);
-static PHP_METHOD(swoole_redis_coro, zCount);
-static PHP_METHOD(swoole_redis_coro, zRange);
-static PHP_METHOD(swoole_redis_coro, zRevRange);
-static PHP_METHOD(swoole_redis_coro, zRangeByScore);
-static PHP_METHOD(swoole_redis_coro, zRevRangeByScore);
-static PHP_METHOD(swoole_redis_coro, zRangeByLex);
-static PHP_METHOD(swoole_redis_coro, zRevRangeByLex);
-static PHP_METHOD(swoole_redis_coro, zInter);
-static PHP_METHOD(swoole_redis_coro, zUnion);
-static PHP_METHOD(swoole_redis_coro, incrBy);
-static PHP_METHOD(swoole_redis_coro, hIncrBy);
-static PHP_METHOD(swoole_redis_coro, incr);
-static PHP_METHOD(swoole_redis_coro, decrBy);
-static PHP_METHOD(swoole_redis_coro, decr);
-static PHP_METHOD(swoole_redis_coro, getBit);
-static PHP_METHOD(swoole_redis_coro, lGet);
-static PHP_METHOD(swoole_redis_coro, lInsert);
-static PHP_METHOD(swoole_redis_coro, setTimeout);
-static PHP_METHOD(swoole_redis_coro, pexpire);
-static PHP_METHOD(swoole_redis_coro, expireAt);
-static PHP_METHOD(swoole_redis_coro, pexpireAt);
-static PHP_METHOD(swoole_redis_coro, move);
-static PHP_METHOD(swoole_redis_coro, select);
-static PHP_METHOD(swoole_redis_coro, getRange);
-static PHP_METHOD(swoole_redis_coro, listTrim);
-static PHP_METHOD(swoole_redis_coro, lGetRange);
-static PHP_METHOD(swoole_redis_coro, lRem);
-static PHP_METHOD(swoole_redis_coro, zDeleteRangeByRank);
-static PHP_METHOD(swoole_redis_coro, incrByFloat);
-static PHP_METHOD(swoole_redis_coro, hIncrByFloat);
-static PHP_METHOD(swoole_redis_coro, bitCount);
-static PHP_METHOD(swoole_redis_coro, bitOp);
-static PHP_METHOD(swoole_redis_coro, sAdd);
-static PHP_METHOD(swoole_redis_coro, sMove);
-static PHP_METHOD(swoole_redis_coro, sDiff);
-static PHP_METHOD(swoole_redis_coro, sDiffStore);
-static PHP_METHOD(swoole_redis_coro, sUnion);
-static PHP_METHOD(swoole_redis_coro, sUnionStore);
-static PHP_METHOD(swoole_redis_coro, sInter);
-static PHP_METHOD(swoole_redis_coro, sInterStore);
-static PHP_METHOD(swoole_redis_coro, sRemove);
-static PHP_METHOD(swoole_redis_coro, zDelete);
-static PHP_METHOD(swoole_redis_coro, subscribe);
-static PHP_METHOD(swoole_redis_coro, pSubscribe);
-static PHP_METHOD(swoole_redis_coro, unsubscribe);
-static PHP_METHOD(swoole_redis_coro, pUnSubscribe);
-static PHP_METHOD(swoole_redis_coro, multi);
-static PHP_METHOD(swoole_redis_coro, exec);
-static PHP_METHOD(swoole_redis_coro, eval);
-static PHP_METHOD(swoole_redis_coro, evalSha);
-static PHP_METHOD(swoole_redis_coro, script);
-static PHP_METHOD(swoole_redis_coro, xLen);
-static PHP_METHOD(swoole_redis_coro, xAdd);
-static PHP_METHOD(swoole_redis_coro, xRead);
-static PHP_METHOD(swoole_redis_coro, xDel);
-static PHP_METHOD(swoole_redis_coro, xRange);
-static PHP_METHOD(swoole_redis_coro, xRevRange);
-static PHP_METHOD(swoole_redis_coro, xTrim);
-static PHP_METHOD(swoole_redis_coro, xGroupCreate);
-static PHP_METHOD(swoole_redis_coro, xGroupSetId);
-static PHP_METHOD(swoole_redis_coro, xGroupDestroy);
-static PHP_METHOD(swoole_redis_coro, xGroupCreateConsumer);
-static PHP_METHOD(swoole_redis_coro, xGroupDelConsumer);
-static PHP_METHOD(swoole_redis_coro, xReadGroup);
-static PHP_METHOD(swoole_redis_coro, xPending);
-static PHP_METHOD(swoole_redis_coro, xAck);
-static PHP_METHOD(swoole_redis_coro, xClaim);
-static PHP_METHOD(swoole_redis_coro, xAutoClaim);
-static PHP_METHOD(swoole_redis_coro, xInfoConsumers);
-static PHP_METHOD(swoole_redis_coro, xInfoGroups);
-static PHP_METHOD(swoole_redis_coro, xInfoStream);
-SW_EXTERN_C_END
-/*---------------------Redis Command End------------------------*/
-// clang-format off
-static const zend_function_entry swoole_redis_coro_methods[] =
-{
- PHP_ME(swoole_redis_coro, __construct, arginfo_swoole_redis_coro_construct, ZEND_ACC_PUBLIC | ZEND_ACC_DEPRECATED)
- PHP_ME(swoole_redis_coro, __destruct, arginfo_swoole_redis_coro_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, connect, arginfo_swoole_redis_coro_connect, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, getAuth, arginfo_swoole_redis_coro_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, getDBNum, arginfo_swoole_redis_coro_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, getOptions, arginfo_swoole_redis_coro_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, setOptions, arginfo_swoole_redis_coro_setOptions, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, getDefer, arginfo_swoole_redis_coro_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, setDefer, arginfo_swoole_redis_coro_setDefer, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, recv, arginfo_swoole_redis_coro_void, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, request, arginfo_swoole_redis_coro_request, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, close, arginfo_swoole_redis_coro_close, ZEND_ACC_PUBLIC)
- /*---------------------Redis Command------------------------*/
- PHP_ME(swoole_redis_coro, set, arginfo_swoole_redis_coro_set, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, setBit, arginfo_swoole_redis_coro_setBit, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, setEx, arginfo_swoole_redis_coro_setex, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, psetEx, arginfo_swoole_redis_coro_psetex, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, lSet, arginfo_swoole_redis_coro_lSet, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, get, arginfo_swoole_redis_coro_get, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, mGet, arginfo_swoole_redis_coro_mget, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, del, arginfo_swoole_redis_coro_del, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hDel, arginfo_swoole_redis_coro_hDel, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hSet, arginfo_swoole_redis_coro_hSet, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hMSet, arginfo_swoole_redis_coro_hMset, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hSetNx, arginfo_swoole_redis_coro_hSetNx, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, delete, del, arginfo_swoole_redis_coro_del, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, mSet, arginfo_swoole_redis_coro_mset, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, mSetNx, arginfo_swoole_redis_coro_msetnx, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, getKeys, arginfo_swoole_redis_coro_getKeys, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, keys, getKeys, arginfo_swoole_redis_coro_getKeys, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, exists, arginfo_swoole_redis_coro_exists, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, type, arginfo_swoole_redis_coro_type, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, strLen, arginfo_swoole_redis_coro_strlen, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, lPop, arginfo_swoole_redis_coro_lPop, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, blPop, arginfo_swoole_redis_coro_blPop, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, rPop, arginfo_swoole_redis_coro_rPop, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, brPop, arginfo_swoole_redis_coro_brPop, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, bRPopLPush, arginfo_swoole_redis_coro_brpoplpush, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, lSize, arginfo_swoole_redis_coro_lSize, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, lLen, lSize, arginfo_swoole_redis_coro_lLen, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sSize, arginfo_swoole_redis_coro_sSize, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, scard, sSize, arginfo_swoole_redis_coro_scard, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sPop, arginfo_swoole_redis_coro_sPop, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sMembers, arginfo_swoole_redis_coro_sMembers, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, sGetMembers, sMembers, arginfo_swoole_redis_coro_key, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sRandMember, arginfo_swoole_redis_coro_sRandMember, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, persist, arginfo_swoole_redis_coro_persist, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, ttl, arginfo_swoole_redis_coro_ttl, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, pttl, arginfo_swoole_redis_coro_pttl, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zCard, arginfo_swoole_redis_coro_zCard, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, zSize, zCard, arginfo_swoole_redis_coro_zSize, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hLen, arginfo_swoole_redis_coro_hLen, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hKeys, arginfo_swoole_redis_coro_hKeys, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hVals, arginfo_swoole_redis_coro_hVals, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hGetAll, arginfo_swoole_redis_coro_hGetAll, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, debug, arginfo_swoole_redis_coro_debug, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, restore, arginfo_swoole_redis_coro_restore, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, dump, arginfo_swoole_redis_coro_dump, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, renameKey, arginfo_swoole_redis_coro_renameKey, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, rename, renameKey, arginfo_swoole_redis_coro_rename, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, renameNx, arginfo_swoole_redis_coro_renameNx, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, rpoplpush, arginfo_swoole_redis_coro_rpoplpush, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, randomKey, arginfo_swoole_redis_coro_randomKey, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, pfadd, arginfo_swoole_redis_coro_pfadd, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, pfcount, arginfo_swoole_redis_coro_pfcount, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, pfmerge, arginfo_swoole_redis_coro_pfmerge, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, ping, arginfo_swoole_redis_coro_ping, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, auth, arginfo_swoole_redis_coro_auth, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, unwatch, arginfo_swoole_redis_coro_unwatch, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, watch, arginfo_swoole_redis_coro_watch, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, save, arginfo_swoole_redis_coro_save, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, bgSave, arginfo_swoole_redis_coro_bgSave, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, lastSave, arginfo_swoole_redis_coro_lastSave, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, flushDB, arginfo_swoole_redis_coro_flushDB, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, flushAll, arginfo_swoole_redis_coro_flushAll, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, dbSize, arginfo_swoole_redis_coro_dbSize, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, bgrewriteaof, arginfo_swoole_redis_coro_bgrewriteaof, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, time, arginfo_swoole_redis_coro_time, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, role, arginfo_swoole_redis_coro_role, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, setRange, arginfo_swoole_redis_coro_setRange, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, setNx, arginfo_swoole_redis_coro_setnx, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, getSet, arginfo_swoole_redis_coro_getSet, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, append, arginfo_swoole_redis_coro_append, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, lPushx, arginfo_swoole_redis_coro_lPushx, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, lPush, arginfo_swoole_redis_coro_lPush, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, rPush, arginfo_swoole_redis_coro_rPush, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, rPushx, arginfo_swoole_redis_coro_rPushx, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sContains, arginfo_swoole_redis_coro_sContains, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, sismember, sContains, arginfo_swoole_redis_coro_key_value, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zScore, arginfo_swoole_redis_coro_zScore, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zRank, arginfo_swoole_redis_coro_zRank, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zRevRank, arginfo_swoole_redis_coro_zRevRank, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hGet, arginfo_swoole_redis_coro_hGet, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hMGet, arginfo_swoole_redis_coro_hMget, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hExists, arginfo_swoole_redis_coro_hExists, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, publish, arginfo_swoole_redis_coro_publish, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zIncrBy, arginfo_swoole_redis_coro_zIncrBy, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zAdd, arginfo_swoole_redis_coro_zAdd, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zPopMin, arginfo_swoole_redis_coro_zPopMin, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zPopMax, arginfo_swoole_redis_coro_zPopMax, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, bzPopMin, arginfo_swoole_redis_coro_bzPopMin, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, bzPopMax, arginfo_swoole_redis_coro_bzPopMax, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zDeleteRangeByScore, arginfo_swoole_redis_coro_zDeleteRangeByScore, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, zRemRangeByScore, zDeleteRangeByScore, arginfo_swoole_redis_coro_zRemRangeByScore, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zCount, arginfo_swoole_redis_coro_zCount, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zRange, arginfo_swoole_redis_coro_zRange, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zRevRange, arginfo_swoole_redis_coro_zRevRange, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zRangeByScore, arginfo_swoole_redis_coro_zRangeByScore, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zRevRangeByScore, arginfo_swoole_redis_coro_zRevRangeByScore, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zRangeByLex, arginfo_swoole_redis_coro_zRangeByLex, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zRevRangeByLex, arginfo_swoole_redis_coro_zRevRangeByLex, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zInter, arginfo_swoole_redis_coro_zInter, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, zinterstore, zInter, arginfo_swoole_redis_coro_zinterstore, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zUnion, arginfo_swoole_redis_coro_zUnion, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, zunionstore, zUnion, arginfo_swoole_redis_coro_zunionstore, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, incrBy, arginfo_swoole_redis_coro_incrBy, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hIncrBy, arginfo_swoole_redis_coro_hIncrBy, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, incr, arginfo_swoole_redis_coro_incr, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, decrBy, arginfo_swoole_redis_coro_decrBy, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, decr, arginfo_swoole_redis_coro_decr, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, getBit, arginfo_swoole_redis_coro_getBit, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, lInsert, arginfo_swoole_redis_coro_lInsert, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, lGet, arginfo_swoole_redis_coro_lGet, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, lIndex, lGet, arginfo_swoole_redis_coro_key_long, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, setTimeout, arginfo_swoole_redis_coro_setTimeout, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, expire, setTimeout, arginfo_swoole_redis_coro_key_long, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, pexpire, arginfo_swoole_redis_coro_pexpire, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, expireAt, arginfo_swoole_redis_coro_expireAt, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, pexpireAt, arginfo_swoole_redis_coro_pexpireAt, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, move, arginfo_swoole_redis_coro_move, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, select, arginfo_swoole_redis_coro_select, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, getRange, arginfo_swoole_redis_coro_getRange, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, listTrim, arginfo_swoole_redis_coro_listTrim, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, ltrim, listTrim, arginfo_swoole_redis_coro_ltrim, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, lGetRange, arginfo_swoole_redis_coro_lGetRange, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, lRange, lGetRange, arginfo_swoole_redis_coro_lrange, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, lRem, arginfo_swoole_redis_coro_lrem, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, lRemove,lRem, arginfo_swoole_redis_coro_lRemove, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zDeleteRangeByRank, arginfo_swoole_redis_coro_zDeleteRangeByRank, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, zRemRangeByRank, zDeleteRangeByRank, arginfo_swoole_redis_coro_zRemRangeByRank, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, incrByFloat, arginfo_swoole_redis_coro_incrByFloat, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, hIncrByFloat, arginfo_swoole_redis_coro_hIncrByFloat, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, bitCount, arginfo_swoole_redis_coro_bitcount, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, bitOp, arginfo_swoole_redis_coro_bitop, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sAdd, arginfo_swoole_redis_coro_sAdd, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sMove, arginfo_swoole_redis_coro_sMove, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sDiff, arginfo_swoole_redis_coro_sDiff, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sDiffStore, arginfo_swoole_redis_coro_sDiffStore, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sUnion, arginfo_swoole_redis_coro_sUnion, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sUnionStore, arginfo_swoole_redis_coro_sUnionStore, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sInter, arginfo_swoole_redis_coro_sInter, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sInterStore, arginfo_swoole_redis_coro_sInterStore, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, sRemove, arginfo_swoole_redis_coro_sRemove, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, srem, sRemove, arginfo_swoole_redis_coro_key_value, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, zDelete, arginfo_swoole_redis_coro_zDelete, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, zRemove, zDelete, arginfo_swoole_redis_coro_zRemove, ZEND_ACC_PUBLIC)
- PHP_MALIAS(swoole_redis_coro, zRem, zDelete, arginfo_swoole_redis_coro_zRem, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, pSubscribe, arginfo_swoole_redis_coro_psubscribe, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, subscribe, arginfo_swoole_redis_coro_subscribe, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, unsubscribe, arginfo_swoole_redis_coro_unsubscribe, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, pUnSubscribe, arginfo_swoole_redis_coro_punsubscribe, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, multi, arginfo_swoole_redis_coro_multi, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, exec, arginfo_swoole_redis_coro_exec, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, eval, arginfo_swoole_redis_coro_eval, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, evalSha, arginfo_swoole_redis_coro_evalsha, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, script, arginfo_swoole_redis_coro_script, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xLen, arginfo_swoole_redis_coro_xLen, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xAdd, arginfo_swoole_redis_coro_xAdd, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xRead, arginfo_swoole_redis_coro_xRead, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xDel, arginfo_swoole_redis_coro_xDel, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xRange, arginfo_swoole_redis_coro_xRange, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xRevRange, arginfo_swoole_redis_coro_xRevRange, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xTrim, arginfo_swoole_redis_coro_xTrim, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xGroupCreate, arginfo_swoole_redis_coro_xGroupCreate, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xGroupSetId, arginfo_swoole_redis_coro_xGroupSetId, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xGroupDestroy, arginfo_swoole_redis_coro_xGroupDestroy, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xGroupCreateConsumer, arginfo_swoole_redis_coro_xGroupCreateConsumer, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xGroupDelConsumer, arginfo_swoole_redis_coro_xGroupDelConsumer, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xReadGroup, arginfo_swoole_redis_coro_xReadGroup, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xPending, arginfo_swoole_redis_coro_xPending, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xAck, arginfo_swoole_redis_coro_xAck, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xClaim, arginfo_swoole_redis_coro_xClaim, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xAutoClaim, arginfo_swoole_redis_coro_xAutoClaim, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xInfoConsumers, arginfo_swoole_redis_coro_xInfoConsumers, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xInfoGroups, arginfo_swoole_redis_coro_xInfoGroups, ZEND_ACC_PUBLIC)
- PHP_ME(swoole_redis_coro, xInfoStream, arginfo_swoole_redis_coro_xInfoStream, ZEND_ACC_PUBLIC)
- /*---------------------Redis Command End------------------------*/
- PHP_FE_END
-};
-// clang-format on
-
-void php_swoole_redis_coro_minit(int module_number) {
- SW_INIT_CLASS_ENTRY(swoole_redis_coro, "Swoole\\Coroutine\\Redis", "Co\\Redis", swoole_redis_coro_methods);
- SW_SET_CLASS_NOT_SERIALIZABLE(swoole_redis_coro);
- SW_SET_CLASS_CLONEABLE(swoole_redis_coro, sw_zend_class_clone_deny);
- SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_redis_coro, sw_zend_class_unset_property_deny);
- SW_SET_CLASS_CREATE_WITH_ITS_OWN_HANDLERS(swoole_redis_coro);
- SW_SET_CLASS_CUSTOM_OBJECT(
- swoole_redis_coro, php_swoole_redis_coro_create_object, php_swoole_redis_coro_free_object, RedisClient, std);
-#if PHP_VERSION_ID >= 80200
- zend_add_parameter_attribute((zend_function *) zend_hash_str_find_ptr(&swoole_redis_coro_ce->function_table, SW_STRL("auth")), 0, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0);
-#endif
-
- zend_declare_property_string(swoole_redis_coro_ce, ZEND_STRL("host"), "", ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_redis_coro_ce, ZEND_STRL("port"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_null(swoole_redis_coro_ce, ZEND_STRL("setting"), ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_redis_coro_ce, ZEND_STRL("sock"), -1, ZEND_ACC_PUBLIC);
- zend_declare_property_bool(swoole_redis_coro_ce, ZEND_STRL("connected"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_redis_coro_ce, ZEND_STRL("errType"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_redis_coro_ce, ZEND_STRL("errCode"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_string(swoole_redis_coro_ce, ZEND_STRL("errMsg"), "", ZEND_ACC_PUBLIC);
-
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_MODE_MULTI", SW_REDIS_MODE_MULTI);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_MODE_PIPELINE", SW_REDIS_MODE_PIPELINE);
-
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_TYPE_NOT_FOUND", SW_REDIS_TYPE_NOT_FOUND);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_TYPE_STRING", SW_REDIS_TYPE_STRING);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_TYPE_SET", SW_REDIS_TYPE_SET);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_TYPE_LIST", SW_REDIS_TYPE_LIST);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_TYPE_ZSET", SW_REDIS_TYPE_ZSET);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_TYPE_HASH", SW_REDIS_TYPE_HASH);
-
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_ERR_IO", SW_REDIS_ERR_IO);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_ERR_OTHER", SW_REDIS_ERR_OTHER);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_ERR_EOF", SW_REDIS_ERR_EOF);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_ERR_PROTOCOL", SW_REDIS_ERR_PROTOCOL);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_ERR_OOM", SW_REDIS_ERR_OOM);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_ERR_CLOSED", SW_REDIS_ERR_CLOSED);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_ERR_NOAUTH", SW_REDIS_ERR_NOAUTH);
- SW_REGISTER_LONG_CONSTANT("SWOOLE_REDIS_ERR_ALLOC", SW_REDIS_ERR_ALLOC);
-}
-
-static void swoole_redis_coro_set_options(RedisClient *redis, zval *zoptions, bool backward_compatibility = false) {
- zval *zsettings =
- sw_zend_read_and_convert_property_array(swoole_redis_coro_ce, redis->zobject, ZEND_STRL("setting"), 0);
- HashTable *vht = Z_ARRVAL_P(zoptions);
- zval *ztmp;
-
- php_array_merge(Z_ARRVAL_P(zsettings), vht);
-
- if (php_swoole_array_get_value(vht, "connect_timeout", ztmp)) {
- redis->connect_timeout = zval_get_double(ztmp);
- if (redis->connect_timeout <= 0) {
- redis->connect_timeout = SW_TIMER_MAX_SEC;
- }
- }
- if (php_swoole_array_get_value(vht, "timeout", ztmp)) {
- redis->timeout = zval_get_double(ztmp);
- if (backward_compatibility) {
- redis->connect_timeout = redis->timeout;
- if (redis->connect_timeout <= 0) {
- redis->connect_timeout = SW_TIMER_MAX_SEC;
- }
- }
- if (redis->context) {
- auto socket = swoole_redis_coro_get_socket(redis->context);
- if (socket) {
- socket->set_timeout(redis->timeout, Socket::TIMEOUT_RDWR);
- }
- }
- }
- if (php_swoole_array_get_value(vht, "serialize", ztmp)) {
- redis->serialize = zval_is_true(ztmp);
- }
- if (php_swoole_array_get_value(vht, "reconnect", ztmp)) {
- redis->reconnect_interval = (uint8_t) SW_MIN(zval_get_long(ztmp), UINT8_MAX);
- }
- if (php_swoole_array_get_value(vht, "compatibility_mode", ztmp)) {
- redis->compatibility_mode = zval_is_true(ztmp);
- }
-}
-
-static PHP_METHOD(swoole_redis_coro, __construct) {
- RedisClient *redis = php_swoole_get_redis_client(ZEND_THIS);
- zval *zsettings = sw_zend_read_and_convert_property_array(swoole_redis_coro_ce, ZEND_THIS, ZEND_STRL("setting"), 0);
- zval *zset = nullptr;
-
- ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 1)
- Z_PARAM_OPTIONAL
- Z_PARAM_ARRAY(zset)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- if (redis->zobject) {
- zend_throw_error(NULL, "Constructor of %s can only be called once", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS));
- RETURN_FALSE;
- }
-
- redis->zobject = &redis->_zobject;
- redis->_zobject = *ZEND_THIS;
-
- redis->connect_timeout = network::Socket::default_connect_timeout;
- redis->timeout = network::Socket::default_read_timeout;
- redis->reconnect_interval = 1;
-
- // settings init
- add_assoc_double(zsettings, "connect_timeout", redis->connect_timeout);
- add_assoc_double(zsettings, "timeout", redis->timeout);
- add_assoc_bool(zsettings, "serialize", redis->serialize);
- add_assoc_long(zsettings, "reconnect", redis->reconnect_interval);
- // after connected
- add_assoc_string(zsettings, "password", (char *) "");
- add_assoc_long(zsettings, "database", 0);
-
- if (zset) {
- swoole_redis_coro_set_options(redis, zset, true);
- }
-}
-
-static PHP_METHOD(swoole_redis_coro, connect) {
- zval *zobject = ZEND_THIS;
- char *host = nullptr;
- size_t host_len = 0;
- zend_long port = 0;
- zend_bool serialize = 0;
-
- SW_REDIS_COMMAND_CHECK
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lb", &host, &host_len, &port, &serialize) == FAILURE) {
- RETURN_FALSE;
- }
-
- zend_update_property_string(swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("host"), host);
- zend_update_property_long(swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("port"), port);
- redis->serialize = serialize;
-
- if (swoole_redis_coro_connect(redis) > 0) {
- // clear the error code only when the developer manually tries to connect successfully
- // if the kernel retries automatically, keep silent.
- zend_update_property_long(swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errType"), 0);
- zend_update_property_long(swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errCode"), 0);
- zend_update_property_string(swoole_redis_coro_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("errMsg"), "");
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
-}
-
-static PHP_METHOD(swoole_redis_coro, getAuth) {
- RedisClient *redis = php_swoole_get_redis_client(ZEND_THIS);
- if (redis->session.auth) {
- zval *ztmp = sw_zend_read_and_convert_property_array(swoole_redis_coro_ce, ZEND_THIS, ZEND_STRL("setting"), 0);
- if (php_swoole_array_get_value(Z_ARRVAL_P(ztmp), "password", ztmp)) {
- RETURN_ZVAL(ztmp, 1, 0);
- }
- RETURN_EMPTY_STRING();
- }
- RETURN_FALSE;
-}
-
-static PHP_METHOD(swoole_redis_coro, getDBNum) {
- RedisClient *redis = php_swoole_get_redis_client(ZEND_THIS);
- if (!redis->context) {
- RETURN_FALSE;
- }
- RETURN_LONG(redis->session.db_num);
-}
-
-static PHP_METHOD(swoole_redis_coro, getOptions) {
- RETURN_ZVAL(
- sw_zend_read_and_convert_property_array(swoole_redis_coro_ce, ZEND_THIS, ZEND_STRL("setting"), 0), 1, 0);
-}
-
-static PHP_METHOD(swoole_redis_coro, setOptions) {
- RedisClient *redis = php_swoole_get_redis_client(ZEND_THIS);
- zval *zoptions;
-
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ARRAY(zoptions)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- swoole_redis_coro_set_options(redis, zoptions);
-
- RETURN_TRUE;
-}
-
-static PHP_METHOD(swoole_redis_coro, getDefer) {
- RedisClient *redis = php_swoole_get_redis_client(ZEND_THIS);
-
- RETURN_BOOL(redis->defer);
-}
-
-static PHP_METHOD(swoole_redis_coro, setDefer) {
- RedisClient *redis = php_swoole_get_redis_client(ZEND_THIS);
- zend_bool defer = 1;
-
- if (redis->session.subscribe) {
- php_swoole_fatal_error(E_WARNING, "you should not use setDefer after subscribe");
- RETURN_FALSE;
- }
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &defer) == FAILURE) {
- RETURN_FALSE;
- }
- redis->defer = defer;
-
- RETURN_TRUE;
-}
-
-static PHP_METHOD(swoole_redis_coro, recv) {
- SW_REDIS_COMMAND_CHECK
-
- if (UNEXPECTED(!redis->context)) {
- RETURN_FALSE;
- }
- if (UNEXPECTED(!redis->defer && !redis->session.subscribe)) {
- php_swoole_fatal_error(E_WARNING, "you should not use recv without defer or subscribe");
- RETURN_FALSE;
- }
-
- redisReply *reply;
-_recv:
- if (redisGetReply(redis->context, (void **) &reply) == REDIS_OK) {
- swoole_redis_coro_parse_result(redis, return_value, reply);
- freeReplyObject(reply);
-
- if (redis->session.subscribe) {
- zval *ztype;
-
- if (!ZVAL_IS_ARRAY(return_value)) {
- zval_ptr_dtor(return_value);
- goto _error;
- }
-
- ztype = zend_hash_index_find(Z_ARRVAL_P(return_value), 0);
- if (Z_TYPE_P(ztype) == IS_STRING) {
- char *type = Z_STRVAL_P(ztype);
-
- if (!strcmp(type, "unsubscribe") || !strcmp(type, "punsubscribe")) {
- zval *znum = zend_hash_index_find(Z_ARRVAL_P(return_value), 2);
- if (Z_LVAL_P(znum) == 0) {
- redis->session.subscribe = false;
- }
-
- return;
- } else if (!strcmp(type, "message") || !strcmp(type, "pmessage") || !strcmp(type, "subscribe") ||
- !strcmp(type, "psubscribe")) {
- return;
- }
- }
-
- zval_ptr_dtor(return_value);
- goto _recv;
- }
- } else {
- _error:
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errType"), redis->context->err);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(redis->zobject),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(redis->context->err));
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errMsg"), redis->context->errstr);
-
- swoole_redis_coro_close(redis);
- RETURN_FALSE;
- }
-}
-
-static PHP_METHOD(swoole_redis_coro, close) {
- RedisClient *redis = php_swoole_get_redis_client(ZEND_THIS);
- RETURN_BOOL(swoole_redis_coro_close(redis));
-}
-
-static PHP_METHOD(swoole_redis_coro, __destruct) {
- SW_PREVENT_USER_DESTRUCT();
-}
-
-static PHP_METHOD(swoole_redis_coro, set) {
- char *key, *exp_type = nullptr, *set_type = nullptr;
- size_t key_len, argc = 3;
- zval *z_value, *z_opts = nullptr;
- zend_long expire = -1;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|z", &key, &key_len, &z_value, &z_opts) == FAILURE) {
- RETURN_FALSE;
- }
-
- SW_REDIS_COMMAND_CHECK
-
- if (z_opts && Z_TYPE_P(z_opts) != IS_LONG && Z_TYPE_P(z_opts) != IS_ARRAY && Z_TYPE_P(z_opts) != IS_NULL) {
- RETURN_FALSE;
- }
-
- if (z_opts && ZVAL_IS_ARRAY(z_opts)) {
- HashTable *kt = Z_ARRVAL_P(z_opts);
-
- zend_string *zkey;
- zend_ulong idx;
- zval *zv;
-
- /* Iterate our option array */
- ZEND_HASH_FOREACH_KEY_VAL(kt, idx, zkey, zv) {
- /* Detect PX or EX argument and validate timeout */
- if (!exp_type && zkey && IS_EX_PX_ARG(ZSTR_VAL(zkey))) {
- /* Set expire type */
- exp_type = ZSTR_VAL(zkey);
-
- /* Try to extract timeout */
- if (Z_TYPE_P(zv) == IS_LONG) {
- expire = Z_LVAL_P(zv);
- } else if (Z_TYPE_P(zv) == IS_STRING) {
- expire = atol(Z_STRVAL_P(zv));
- }
-
- /* Expiry can't be set < 1 */
- if (expire < 1) {
- RETURN_FALSE;
- }
- argc += 2;
- } else if (!set_type && Z_TYPE_P(zv) == IS_STRING && IS_NX_XX_ARG(Z_STRVAL_P(zv))) {
- argc += 1;
- set_type = Z_STRVAL_P(zv);
- }
- (void) idx;
- }
- ZEND_HASH_FOREACH_END();
- } else if (z_opts && Z_TYPE_P(z_opts) == IS_LONG) {
- /* Grab expiry and fail if it's < 1 */
- expire = Z_LVAL_P(z_opts);
- /* Expiry can't be set < 1 */
- if (expire < 1) {
- RETURN_FALSE;
- }
- argc += 1;
- }
-
- SW_REDIS_COMMAND_ALLOC_ARGV
-
- int i = 0;
- if (exp_type || set_type) {
- SW_REDIS_COMMAND_ARGV_FILL("SET", 3)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(z_value)
-
- if (set_type) {
- SW_REDIS_COMMAND_ARGV_FILL(set_type, (size_t) strlen(set_type))
- }
-
- if (exp_type) {
- SW_REDIS_COMMAND_ARGV_FILL(exp_type, (size_t) strlen(exp_type))
-
- char str[32];
- sprintf(str, ZEND_LONG_FMT, expire);
- SW_REDIS_COMMAND_ARGV_FILL(str, (size_t) strlen(str))
- }
- } else if (expire > 0) {
- SW_REDIS_COMMAND_ARGV_FILL("SETEX", 5)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
-
- char str[32];
- sprintf(str, ZEND_LONG_FMT, expire);
- SW_REDIS_COMMAND_ARGV_FILL(str, (size_t) strlen(str))
-
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(z_value)
- } else {
- SW_REDIS_COMMAND_ARGV_FILL("SET", 3)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(z_value)
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, setBit) {
- char *key;
- size_t key_len;
- long offset;
- zend_bool val;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "slb", &key, &key_len, &offset, &val) == FAILURE) {
- return;
- }
-
- // Validate our offset
- if (offset < SW_BITOP_MIN_OFFSET || offset > SW_BITOP_MAX_OFFSET) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errMsg"),
- "Invalid OFFSET for bitop command (must be between 0-2^32-1)");
- RETURN_FALSE;
- }
-
- SW_REDIS_COMMAND_CHECK
-
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
-
- SW_REDIS_COMMAND_ARGV_FILL("SETBIT", 6)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
-
- char str[32];
- sprintf(str, "%ld", offset);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
-
- SW_REDIS_COMMAND_ARGV_FILL(val ? "1" : "0", 1)
- redis_request(redis, 4, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, setEx) {
- sw_redis_command_key_long_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SETEX"));
-}
-
-static PHP_METHOD(swoole_redis_coro, psetEx) {
- sw_redis_command_key_long_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("PSETEX"));
-}
-
-static PHP_METHOD(swoole_redis_coro, lSet) {
- sw_redis_command_key_long_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("LSET"));
-}
-
-static PHP_METHOD(swoole_redis_coro, restore) {
- sw_redis_command_key_long_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("RESTORE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, dump) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("DUMP"));
-}
-
-static PHP_METHOD(swoole_redis_coro, debug) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("DEBUG"));
-}
-
-static PHP_METHOD(swoole_redis_coro, get) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("GET"));
-}
-
-static PHP_METHOD(swoole_redis_coro, mGet) {
- zval *z_args;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &z_args) == FAILURE) {
- RETURN_FALSE;
- }
- int argc;
- argc = zend_hash_num_elements(Z_ARRVAL_P(z_args));
- if (argc == 0) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- argc++;
- SW_REDIS_COMMAND_ALLOC_ARGV
- int i = 0;
- zval *value;
- SW_REDIS_COMMAND_ARGV_FILL("MGET", 4)
- SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(z_args), value)
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- SW_HASHTABLE_FOREACH_END();
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, hSet) {
- char *key, *field;
- size_t key_len, field_len;
- zval *z_val;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssz", &key, &key_len, &field, &field_len, &z_val) == FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- SW_REDIS_COMMAND_ARGV_FILL("HSET", 4)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(field, field_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(z_val)
-
- redis_request(redis, 4, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, hMSet) {
- char *key;
- size_t key_len, argc;
- zval *z_arr;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa", &key, &key_len, &z_arr) == FAILURE) {
- return;
- }
- if ((argc = zend_hash_num_elements(Z_ARRVAL_P(z_arr))) == 0) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- argc = argc * 2 + 2;
- zval *value;
- char buf[32];
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("HMSET", 5)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- zend_ulong idx;
- zend_string *_key;
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(z_arr), idx, _key, value) {
- if (_key == nullptr) {
- key_len = sw_snprintf(buf, sizeof(buf), "%ld", (long) idx);
- key = (char *) buf;
- } else {
- key_len = ZSTR_LEN(_key);
- key = ZSTR_VAL(_key);
- }
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(value)
- }
- ZEND_HASH_FOREACH_END();
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, hSetNx) {
- char *key, *field;
- size_t key_len, field_len;
- zval *z_val;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssz", &key, &key_len, &field, &field_len, &z_val) == FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- convert_to_string(z_val);
- SW_REDIS_COMMAND_ARGV_FILL("HSETNX", 6)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(field, field_len)
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(z_val), Z_STRLEN_P(z_val))
-
- redis_request(redis, 4, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, hDel) {
- int argc = ZEND_NUM_ARGS();
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGS_ARR
- if (argc < 2 || zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
- efree(z_args);
- RETURN_FALSE;
- }
- argc++;
- int i = 0, j;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("HDEL", 4)
- for (j = 0; j < argc - 1; ++j) {
- zend_string *convert_str = zval_get_string(&z_args[j]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- }
- efree(z_args);
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, watch) {
- sw_redis_command_var_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("WATCH"), 1, 0);
-}
-
-static PHP_METHOD(swoole_redis_coro, del) {
- sw_redis_command_var_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("DEL"), 1, 0);
-}
-
-static PHP_METHOD(swoole_redis_coro, sDiff) {
- sw_redis_command_var_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SDIFF"), 1, 0);
-}
-
-static PHP_METHOD(swoole_redis_coro, sDiffStore) {
- sw_redis_command_var_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SDIFFSTORE"), 1, 0);
-}
-
-static PHP_METHOD(swoole_redis_coro, sUnion) {
- sw_redis_command_var_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SUNION"), 1, 0);
-}
-
-static PHP_METHOD(swoole_redis_coro, sUnionStore) {
- sw_redis_command_var_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SUNIONSTORE"), 1, 0);
-}
-
-static PHP_METHOD(swoole_redis_coro, sInter) {
- sw_redis_command_var_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SINTER"), 1, 0);
-}
-
-static PHP_METHOD(swoole_redis_coro, sInterStore) {
- sw_redis_command_var_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SINTERSTORE"), 1, 0);
-}
-
-static PHP_METHOD(swoole_redis_coro, mSet) {
- zval *z_args;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &z_args) == FAILURE) {
- RETURN_FALSE;
- }
- int argc;
- argc = zend_hash_num_elements(Z_ARRVAL_P(z_args));
- if (argc == 0) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- argc *= 2;
- argc++;
- SW_REDIS_COMMAND_ALLOC_ARGV
- int i = 0;
- SW_REDIS_COMMAND_ARGV_FILL("MSET", 4)
- zval *value;
- char buf[32];
- char *key;
- uint32_t key_len;
- zend_ulong idx;
- zend_string *_key;
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(z_args), idx, _key, value) {
- if (_key == nullptr) {
- key_len = sw_snprintf(buf, sizeof(buf), "%ld", (long) idx);
- key = (char *) buf;
- } else {
- key_len = ZSTR_LEN(_key);
- key = ZSTR_VAL(_key);
- }
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(value)
- }
- ZEND_HASH_FOREACH_END();
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, mSetNx) {
- zval *z_args;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &z_args) == FAILURE) {
- return;
- }
- int argc;
- argc = zend_hash_num_elements(Z_ARRVAL_P(z_args));
- if (argc == 0) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- argc *= 2;
- argc++;
- SW_REDIS_COMMAND_ALLOC_ARGV
- int i = 0;
- SW_REDIS_COMMAND_ARGV_FILL("MSETNX", 6)
- zval *value;
- char buf[32];
- char *key;
- uint32_t key_len;
- zend_ulong idx;
- zend_string *_key;
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(z_args), idx, _key, value) {
- if (_key == nullptr) {
- key_len = sw_snprintf(buf, sizeof(buf), "%ld", (long) idx);
- key = (char *) buf;
- } else {
- key_len = ZSTR_LEN(_key);
- key = ZSTR_VAL(_key);
- }
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(value)
- }
- ZEND_HASH_FOREACH_END();
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, getKeys) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("KEYS"));
-}
-
-static PHP_METHOD(swoole_redis_coro, exists) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("EXISTS"));
-}
-
-static PHP_METHOD(swoole_redis_coro, type) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("TYPE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, strLen) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("STRLEN"));
-}
-
-static PHP_METHOD(swoole_redis_coro, lPop) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("LPOP"));
-}
-
-static PHP_METHOD(swoole_redis_coro, bRPopLPush) {
- char *key1, *key2;
- size_t key1_len, key2_len;
- long timeout;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssl", &key1, &key1_len, &key2, &key2_len, &timeout) == FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int argc, i = 0;
- argc = timeout < 0 ? 3 : 4;
- SW_REDIS_COMMAND_ALLOC_ARGV
- if (timeout < 0) {
- SW_REDIS_COMMAND_ARGV_FILL("RPOPLPUSH", 9)
- SW_REDIS_COMMAND_ARGV_FILL(key1, key1_len)
- SW_REDIS_COMMAND_ARGV_FILL(key2, key2_len)
- } else {
- SW_REDIS_COMMAND_ARGV_FILL("BRPOPLPUSH", 10)
- SW_REDIS_COMMAND_ARGV_FILL(key1, key1_len)
- SW_REDIS_COMMAND_ARGV_FILL(key2, key2_len)
- char str[32];
- sprintf(str, "%ld", timeout);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, blPop) {
- int argc = ZEND_NUM_ARGS();
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGS_ARR
- if (zend_get_parameters_array(ht, argc, z_args) == FAILURE || argc < 1) {
- efree(z_args);
- return;
- }
-
- zend_bool single_array = 0;
- if (argc == 2 && SW_REDIS_COMMAND_ARGS_TYPE(z_args[0]) == IS_ARRAY) {
- argc = zend_hash_num_elements(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0])) + 2;
- single_array = 1;
- } else {
- argc += 1;
- }
- int i = 0;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("BLPOP", 5)
- if (single_array) {
- zval *value;
- SW_HASHTABLE_FOREACH_START(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0]), value)
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- SW_HASHTABLE_FOREACH_END();
- zend_string *convert_str = zval_get_string(&z_args[1]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- } else {
- int j;
- for (j = 0; j < argc - 1; ++j) {
- zend_string *convert_str = zval_get_string(&z_args[j]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- }
- }
- efree(z_args);
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, brPop) {
- int argc = ZEND_NUM_ARGS();
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGS_ARR
- if (zend_get_parameters_array(ht, argc, z_args) == FAILURE || argc < 1) {
- efree(z_args);
- return;
- }
-
- zend_bool single_array = 0;
- if (argc == 2 && SW_REDIS_COMMAND_ARGS_TYPE(z_args[0]) == IS_ARRAY) {
- argc = zend_hash_num_elements(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0])) + 2;
- single_array = 1;
- } else {
- argc += 1;
- }
- int i = 0;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("BRPOP", 5)
- if (single_array) {
- zval *value;
- SW_HASHTABLE_FOREACH_START(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0]), value)
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- SW_HASHTABLE_FOREACH_END();
- zend_string *convert_str = zval_get_string(&z_args[1]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- } else {
- int j;
- for (j = 0; j < argc - 1; ++j) {
- zend_string *convert_str = zval_get_string(&z_args[j]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- }
- }
- efree(z_args);
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, rPop) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("RPOP"));
-}
-
-static PHP_METHOD(swoole_redis_coro, lSize) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("LLEN"));
-}
-
-static PHP_METHOD(swoole_redis_coro, sSize) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SCARD"));
-}
-
-static PHP_METHOD(swoole_redis_coro, sPop) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SPOP"));
-}
-
-static PHP_METHOD(swoole_redis_coro, sMembers) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SMEMBERS"));
-}
-
-static PHP_METHOD(swoole_redis_coro, sRandMember) {
- char *key;
- size_t key_len;
- zend_long count = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &key, &key_len, &count) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0, argc, buf_len;
- char buf[32];
- argc = ZEND_NUM_ARGS() == 2 ? 3 : 2;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("SRANDMEMBER", 11);
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len);
- if (argc == 3) {
- buf_len = sw_snprintf(buf, sizeof(buf), "%" PRId64 "", count);
- SW_REDIS_COMMAND_ARGV_FILL((char *) buf, buf_len);
- }
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, persist) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("PERSIST"));
-}
-
-static PHP_METHOD(swoole_redis_coro, ttl) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("TTL"));
-}
-
-static PHP_METHOD(swoole_redis_coro, pttl) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("PTTL"));
-}
-
-static PHP_METHOD(swoole_redis_coro, zCard) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("ZCARD"));
-}
-
-static PHP_METHOD(swoole_redis_coro, hLen) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("HLEN"));
-}
-
-static PHP_METHOD(swoole_redis_coro, hKeys) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("HKEYS"));
-}
-
-static PHP_METHOD(swoole_redis_coro, hVals) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("HVALS"));
-}
-
-static PHP_METHOD(swoole_redis_coro, hGetAll) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("HGETALL"));
-}
-
-static PHP_METHOD(swoole_redis_coro, renameKey) {
- sw_redis_command_key_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("RENAME"));
-}
-
-static PHP_METHOD(swoole_redis_coro, renameNx) {
- sw_redis_command_key_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("RENAMENX"));
-}
-
-static PHP_METHOD(swoole_redis_coro, rpoplpush) {
- sw_redis_command_key_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("RPOPLPUSH"));
-}
-
-static PHP_METHOD(swoole_redis_coro, randomKey) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("RANDOMKEY"));
-}
-
-static PHP_METHOD(swoole_redis_coro, unwatch) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("UNWATCH"));
-}
-
-static PHP_METHOD(swoole_redis_coro, pfadd) {
- char *key;
- size_t key_len, argc;
- zval *z_arr;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa", &key, &key_len, &z_arr) == FAILURE) {
- return;
- }
- if ((argc = zend_hash_num_elements(Z_ARRVAL_P(z_arr))) == 0) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- argc = argc + 2;
- zval *value;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("PFADD", 5)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(z_arr), value) {
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str));
- zend_string_release(convert_str);
- }
- SW_HASHTABLE_FOREACH_END()
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, pfcount) {
- int argc = ZEND_NUM_ARGS();
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGS_ARR
- if (zend_get_parameters_array(ht, argc, z_args) == FAILURE || argc != 1) {
- efree(z_args);
- RETURN_FALSE;
- }
-
- zend_bool single_array = 0;
- if (SW_REDIS_COMMAND_ARGS_TYPE(z_args[0]) == IS_ARRAY) {
- argc = zend_hash_num_elements(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0]));
- single_array = 1;
- }
-
- argc += 1;
- int i = 0;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("PFCOUNT", 7)
- if (single_array) {
- zval *value;
- SW_HASHTABLE_FOREACH_START(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0]), value)
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- SW_HASHTABLE_FOREACH_END()
- } else {
- zend_string *convert_str = zval_get_string(&z_args[0]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- }
- efree(z_args);
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, pfmerge) {
- char *key;
- size_t key_len, argc;
- zval *z_arr;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa", &key, &key_len, &z_arr) == FAILURE) {
- RETURN_FALSE;
- }
- if ((argc = zend_hash_num_elements(Z_ARRVAL_P(z_arr))) == 0) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- argc = argc + 2;
- zval *value;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("PFMERGE", 7)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(z_arr), value) {
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str));
- zend_string_release(convert_str);
- }
- SW_HASHTABLE_FOREACH_END()
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, ping) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("PING"));
-}
-
-static PHP_METHOD(swoole_redis_coro, auth) {
- char *pw;
- size_t pw_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &pw, &pw_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- SW_REDIS_COMMAND_CHECK
- zval *zsetting = sw_zend_read_and_convert_property_array(swoole_redis_coro_ce, ZEND_THIS, ZEND_STRL("setting"), 0);
- add_assoc_stringl(zsetting, "password", pw, pw_len);
- RETURN_BOOL(redis_auth(redis, pw, pw_len));
-}
-
-static PHP_METHOD(swoole_redis_coro, save) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SAVE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, bgSave) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("BGSAVE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, lastSave) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("LASTSAVE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, flushDB) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("FLUSHDB"));
-}
-
-static PHP_METHOD(swoole_redis_coro, flushAll) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("FLUSHALL"));
-}
-
-static PHP_METHOD(swoole_redis_coro, dbSize) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("DBSIZE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, bgrewriteaof) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("BGREWRITEAOF"));
-}
-
-static PHP_METHOD(swoole_redis_coro, time) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("TIME"));
-}
-
-static PHP_METHOD(swoole_redis_coro, role) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("ROLE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, setRange) {
- sw_redis_command_key_long_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SETRANGE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, setNx) {
- sw_redis_command_key_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SETNX"));
-}
-
-static PHP_METHOD(swoole_redis_coro, getSet) {
- sw_redis_command_key_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("GETSET"));
-}
-
-static PHP_METHOD(swoole_redis_coro, append) {
- sw_redis_command_key_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("APPEND"));
-}
-
-static PHP_METHOD(swoole_redis_coro, lPushx) {
- sw_redis_command_key_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("LPUSHX"));
-}
-
-static PHP_METHOD(swoole_redis_coro, lPush) {
- sw_redis_command_key_var_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("LPUSH"));
-}
-
-static PHP_METHOD(swoole_redis_coro, rPush) {
- sw_redis_command_key_var_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("RPUSH"));
-}
-
-static PHP_METHOD(swoole_redis_coro, rPushx) {
- sw_redis_command_key_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("RPUSHX"));
-}
-
-static PHP_METHOD(swoole_redis_coro, sContains) {
- sw_redis_command_key_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SISMEMBER"));
-}
-
-static PHP_METHOD(swoole_redis_coro, zRange) {
- char *key;
- size_t key_len;
- zend_long start, end;
- zend_bool ws = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll|b", &key, &key_len, &start, &end, &ws) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0, argc;
- argc = ZEND_NUM_ARGS() + 1;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("ZRANGE", 6)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char buf[32];
- size_t buf_len;
- buf_len = sw_snprintf(buf, sizeof(buf), "%" PRId64 "", start);
- SW_REDIS_COMMAND_ARGV_FILL((char *) buf, buf_len)
- buf_len = sw_snprintf(buf, sizeof(buf), "%" PRId64 "", end);
- SW_REDIS_COMMAND_ARGV_FILL((char *) buf, buf_len)
- if (ws) {
- SW_REDIS_COMMAND_ARGV_FILL("WITHSCORES", 10)
- } else {
- argc = 4;
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (ws && redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, zRevRange) {
- char *key;
- size_t key_len;
- zend_long start, end;
- zend_bool ws = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll|b", &key, &key_len, &start, &end, &ws) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0, argc;
- argc = ZEND_NUM_ARGS() + 1;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("ZREVRANGE", 9)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char buf[32];
- size_t buf_len;
- buf_len = sw_snprintf(buf, sizeof(buf), "%" PRId64 "", start);
- SW_REDIS_COMMAND_ARGV_FILL((char *) buf, buf_len)
- buf_len = sw_snprintf(buf, sizeof(buf), "%" PRId64 "", end);
- SW_REDIS_COMMAND_ARGV_FILL((char *) buf, buf_len)
- if (ws) {
- SW_REDIS_COMMAND_ARGV_FILL("WITHSCORES", 10)
- } else {
- argc = 4;
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (ws && redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, zUnion) {
- char *key, *agg_op;
- size_t key_len;
- zval *z_keys, *z_weights = nullptr;
- HashTable *ht_keys, *ht_weights = nullptr;
- size_t argc = 2, agg_op_len = 0, keys_count;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa|a!s", &key, &key_len, &z_keys, &z_weights, &agg_op, &agg_op_len) ==
- FAILURE) {
- RETURN_FALSE;
- }
-
- ht_keys = Z_ARRVAL_P(z_keys);
-
- if ((keys_count = zend_hash_num_elements(ht_keys)) == 0) {
- RETURN_FALSE;
- } else {
- argc += keys_count + 1;
- }
-
- if (z_weights != nullptr) {
- ht_weights = Z_ARRVAL_P(z_weights);
- if (zend_hash_num_elements(ht_weights) != keys_count) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errMsg"),
- "WEIGHTS and keys array should be the same size!");
- RETURN_FALSE;
- }
- argc += keys_count + 1;
- }
-
- // AGGREGATE option
- if (agg_op_len != 0) {
- if (strncasecmp(agg_op, "SUM", sizeof("SUM")) && strncasecmp(agg_op, "MIN", sizeof("MIN")) &&
- strncasecmp(agg_op, "MAX", sizeof("MAX"))) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errMsg"),
- "Invalid AGGREGATE option provided!");
- RETURN_FALSE;
- }
-
- // "AGGREGATE" + type
- argc += 2;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0, j;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("ZUNIONSTORE", 11)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char buf[32];
- size_t buf_len;
- buf_len = sprintf(buf, "%zu", keys_count);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
-
- // Process input keys
- zval *value;
- SW_HASHTABLE_FOREACH_START(ht_keys, value)
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- SW_HASHTABLE_FOREACH_END();
-
- // Weights
- if (ht_weights != nullptr) {
- SW_REDIS_COMMAND_ARGV_FILL("WEIGHTS", 7)
-
- SW_HASHTABLE_FOREACH_START(ht_weights, value)
- if (Z_TYPE_P(value) != IS_LONG && Z_TYPE_P(value) != IS_DOUBLE &&
- strncasecmp(Z_STRVAL_P(value), "inf", sizeof("inf")) != 0 &&
- strncasecmp(Z_STRVAL_P(value), "-inf", sizeof("-inf")) != 0 &&
- strncasecmp(Z_STRVAL_P(value), "+inf", sizeof("+inf")) != 0) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(redis->zobject),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(redis->zobject),
- ZEND_STRL("errMsg"),
- "Weights must be numeric or '-inf','inf','+inf'");
- for (j = 0; j < i; j++) {
- efree((void *) argv[j]);
- }
- SW_REDIS_COMMAND_FREE_ARGV
- RETURN_FALSE;
- }
- switch (Z_TYPE_P(value)) {
- case IS_LONG:
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(value));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- break;
- case IS_DOUBLE:
- buf_len = sprintf(buf, "%f", Z_DVAL_P(value));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- break;
- case IS_STRING:
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(value), Z_STRLEN_P(value))
- break;
- }
- SW_HASHTABLE_FOREACH_END();
- }
-
- // AGGREGATE
- if (agg_op_len != 0) {
- SW_REDIS_COMMAND_ARGV_FILL("AGGREGATE", 9)
- SW_REDIS_COMMAND_ARGV_FILL(agg_op, agg_op_len)
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, zInter) {
- char *key, *agg_op;
- size_t key_len;
- zval *z_keys, *z_weights = nullptr;
- HashTable *ht_keys, *ht_weights = nullptr;
- size_t argc = 2, agg_op_len = 0, keys_count;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa|a!s", &key, &key_len, &z_keys, &z_weights, &agg_op, &agg_op_len) ==
- FAILURE) {
- RETURN_FALSE;
- }
-
- ht_keys = Z_ARRVAL_P(z_keys);
-
- if ((keys_count = zend_hash_num_elements(ht_keys)) == 0) {
- RETURN_FALSE;
- } else {
- argc += keys_count + 1;
- }
-
- if (z_weights != nullptr) {
- ht_weights = Z_ARRVAL_P(z_weights);
- if (zend_hash_num_elements(ht_weights) != keys_count) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errMsg"),
- "WEIGHTS and keys array should be the same size!");
- RETURN_FALSE;
- }
-
- argc += keys_count + 1;
- }
-
- // AGGREGATE option
- if (agg_op_len != 0) {
- if (strncasecmp(agg_op, "SUM", sizeof("SUM")) && strncasecmp(agg_op, "MIN", sizeof("MIN")) &&
- strncasecmp(agg_op, "MAX", sizeof("MAX"))) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errMsg"),
- "Invalid AGGREGATE option provided!");
- RETURN_FALSE;
- }
-
- // "AGGREGATE" + type
- argc += 2;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0, j;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("ZINTERSTORE", 11)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char buf[32];
- size_t buf_len;
- buf_len = sprintf(buf, "%zu", keys_count);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
-
- // Process input keys
- zval *value;
- SW_HASHTABLE_FOREACH_START(ht_keys, value)
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- SW_HASHTABLE_FOREACH_END();
-
- // Weights
- if (ht_weights != nullptr) {
- SW_REDIS_COMMAND_ARGV_FILL("WEIGHTS", 7)
-
- SW_HASHTABLE_FOREACH_START(ht_weights, value)
- if (Z_TYPE_P(value) != IS_LONG && Z_TYPE_P(value) != IS_DOUBLE &&
- strncasecmp(Z_STRVAL_P(value), "inf", sizeof("inf")) != 0 &&
- strncasecmp(Z_STRVAL_P(value), "-inf", sizeof("-inf")) != 0 &&
- strncasecmp(Z_STRVAL_P(value), "+inf", sizeof("+inf")) != 0) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errMsg"),
- "Weights must be numeric or '-inf','inf','+inf'");
- for (j = 0; j < i; j++) {
- efree((void *) argv[j]);
- }
- SW_REDIS_COMMAND_FREE_ARGV
- RETURN_FALSE;
- }
- switch (Z_TYPE_P(value)) {
- case IS_LONG:
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(value));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- break;
- case IS_DOUBLE:
- buf_len = sprintf(buf, "%f", Z_DVAL_P(value));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- break;
- case IS_STRING:
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(value), Z_STRLEN_P(value))
- break;
- }
- SW_HASHTABLE_FOREACH_END();
- }
-
- // AGGREGATE
- if (agg_op_len != 0) {
- SW_REDIS_COMMAND_ARGV_FILL("AGGREGATE", 9)
- SW_REDIS_COMMAND_ARGV_FILL(agg_op, agg_op_len)
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, zRangeByLex) {
- char *key, *min, *max;
- size_t key_len, min_len, max_len;
- zend_long offset = 0, count = 0;
- size_t argc = ZEND_NUM_ARGS();
-
- /* We need either 3 or 5 arguments for this to be valid */
- if (argc != 3 && argc != 5) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errMsg"), "Must pass either 3 or 5 arguments");
- RETURN_FALSE;
- }
-
- if (zend_parse_parameters(argc, "sss|ll", &key, &key_len, &min, &min_len, &max, &max_len, &offset, &count) ==
- FAILURE) {
- RETURN_FALSE;
- }
-
- /* min and max must start with '(' or '[', or be either '-' or '+' */
- if (min_len < 1 || max_len < 1 ||
- (min[0] != '(' && min[0] != '[' && (min[0] != '-' || min_len > 1) && (min[0] != '+' || min_len > 1)) ||
- (max[0] != '(' && max[0] != '[' && (max[0] != '-' || max_len > 1) && (max[0] != '+' || max_len > 1))) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errMsg"),
- "min and max arguments must start with '[' or '('");
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- argc = argc == 3 ? 4 : 7;
- int i = 0;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("ZRANGEBYLEX", 11)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(min, min_len)
- SW_REDIS_COMMAND_ARGV_FILL(max, max_len)
- if (argc == 7) {
- SW_REDIS_COMMAND_ARGV_FILL("LIMIT", 5)
- char buf[32];
- size_t buf_len;
- buf_len = sprintf(buf, ZEND_LONG_FMT, offset);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- buf_len = sprintf(buf, ZEND_LONG_FMT, count);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, zRevRangeByLex) {
- char *key, *min, *max;
- size_t key_len, min_len, max_len;
- zend_long offset = 0, count = 0;
- int argc = ZEND_NUM_ARGS();
-
- /* We need either 3 or 5 arguments for this to be valid */
- if (argc != 3 && argc != 5) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errMsg"), "Must pass either 3 or 5 arguments");
- RETURN_FALSE;
- }
-
- if (zend_parse_parameters(argc, "sss|ll", &key, &key_len, &min, &min_len, &max, &max_len, &offset, &count) ==
- FAILURE) {
- RETURN_FALSE;
- }
-
- /* min and max must start with '(' or '[', or be either '-' or '+' */
- if (min_len < 1 || max_len < 1 ||
- (min[0] != '(' && min[0] != '[' && (min[0] != '-' || min_len > 1) && (min[0] != '+' || min_len > 1)) ||
- (max[0] != '(' && max[0] != '[' && (max[0] != '-' || max_len > 1) && (max[0] != '+' || max_len > 1))) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errMsg"),
- "min and max arguments must start with '[' or '('");
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- argc = argc == 3 ? 4 : 7;
- int i = 0;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("ZREVRANGEBYLEX", 14)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(min, min_len)
- SW_REDIS_COMMAND_ARGV_FILL(max, max_len)
- if (argc == 7) {
- SW_REDIS_COMMAND_ARGV_FILL("LIMIT", 5)
- char buf[32];
- size_t buf_len;
- buf_len = sprintf(buf, ZEND_LONG_FMT, offset);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- buf_len = sprintf(buf, ZEND_LONG_FMT, count);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, zRangeByScore) {
- char *key;
- size_t key_len;
- char *start, *end;
- size_t start_len, end_len;
- long limit_low, limit_high;
- zval *z_opt = nullptr, *z_ele;
- zend_bool withscores = 0, has_limit = 0;
- HashTable *ht_opt;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|a", &key, &key_len, &start, &start_len, &end, &end_len, &z_opt) ==
- FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- int argc = 4, i = 0;
- // Check for an options array
- if (z_opt && ZVAL_IS_ARRAY(z_opt)) {
- ht_opt = Z_ARRVAL_P(z_opt);
-
- // Check for WITHSCORES
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("withscores"))) && Z_TYPE_P(z_ele) == IS_TRUE) {
- withscores = 1;
- argc++;
- }
-
- // LIMIT
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("limit")))) {
- HashTable *ht_limit = Z_ARRVAL_P(z_ele);
- zval *z_off, *z_cnt;
- z_off = zend_hash_index_find(ht_limit, 0);
- z_cnt = zend_hash_index_find(ht_limit, 1);
- if (z_off && z_cnt && Z_TYPE_P(z_off) == IS_LONG && Z_TYPE_P(z_cnt) == IS_LONG) {
- has_limit = 1;
- limit_low = Z_LVAL_P(z_off);
- limit_high = Z_LVAL_P(z_cnt);
- argc += 3;
- }
- }
- }
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("ZRANGEBYSCORE", 13)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(start, start_len)
- SW_REDIS_COMMAND_ARGV_FILL(end, end_len)
-
- if (withscores) {
- SW_REDIS_COMMAND_ARGV_FILL("WITHSCORES", 10)
- }
- if (has_limit) {
- SW_REDIS_COMMAND_ARGV_FILL("LIMIT", 5)
- char buf[32];
- size_t buf_len;
- buf_len = sprintf(buf, "%ld", limit_low);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- buf_len = sprintf(buf, "%ld", limit_high);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (withscores && redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, zRevRangeByScore) {
- char *key;
- size_t key_len;
- char *start, *end;
- size_t start_len, end_len;
- long limit_low, limit_high;
- zval *z_opt = nullptr, *z_ele;
- zend_bool withscores = 0, has_limit = 0;
- HashTable *ht_opt;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|a", &key, &key_len, &start, &start_len, &end, &end_len, &z_opt) ==
- FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- int argc = 4, i = 0;
- // Check for an options array
- if (z_opt && ZVAL_IS_ARRAY(z_opt)) {
- ht_opt = Z_ARRVAL_P(z_opt);
-
- // Check for WITHSCORES
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("withscores"))) && Z_TYPE_P(z_ele) == IS_TRUE) {
- withscores = 1;
- argc++;
- }
-
- // LIMIT
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("limit")))) {
- HashTable *ht_limit = Z_ARRVAL_P(z_ele);
- zval *z_off, *z_cnt;
- z_off = zend_hash_index_find(ht_limit, 0);
- z_cnt = zend_hash_index_find(ht_limit, 1);
- if (z_off && z_cnt && Z_TYPE_P(z_off) == IS_LONG && Z_TYPE_P(z_cnt) == IS_LONG) {
- has_limit = 1;
- limit_low = Z_LVAL_P(z_off);
- limit_high = Z_LVAL_P(z_cnt);
- argc += 3;
- }
- }
- }
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("ZREVRANGEBYSCORE", 16)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(start, start_len)
- SW_REDIS_COMMAND_ARGV_FILL(end, end_len)
-
- if (withscores) {
- SW_REDIS_COMMAND_ARGV_FILL("WITHSCORES", 10)
- }
- if (has_limit) {
- SW_REDIS_COMMAND_ARGV_FILL("LIMIT", 5)
- char buf[32];
- size_t buf_len;
- buf_len = sprintf(buf, "%ld", limit_low);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- buf_len = sprintf(buf, "%ld", limit_high);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (withscores && redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, zIncrBy) {
- char *key;
- size_t key_len;
- double incrby;
- zval *z_val;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sdz", &key, &key_len, &incrby, &z_val) == FAILURE) {
- RETURN_FALSE;
- }
-
- SW_REDIS_COMMAND_CHECK;
-
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- SW_REDIS_COMMAND_ARGV_FILL("ZINCRBY", 7)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char buf[32];
- size_t buf_len;
- buf_len = sprintf(buf, "%f", incrby);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(z_val)
- redis_request(redis, 4, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, zAdd) {
- int argc = ZEND_NUM_ARGS();
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGS_ARR
-
- if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
- efree(z_args);
- RETURN_FALSE;
- }
-
- if (argc > 0) {
- convert_to_string(&z_args[0]);
- }
- if (argc < 3 || SW_REDIS_COMMAND_ARGS_TYPE(z_args[0]) != IS_STRING) {
- efree(z_args);
- RETURN_FALSE;
- }
-
- int i = 0, j, k, valid_params;
- valid_params = argc - 1;
- argc++;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("ZADD", 4)
- SW_REDIS_COMMAND_ARGV_FILL(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[0]),
- (size_t) SW_REDIS_COMMAND_ARGS_STRLEN(z_args[0]))
- k = 1;
-
- if (SW_REDIS_COMMAND_ARGS_TYPE(z_args[k]) == IS_STRING && IS_NX_XX_ARG(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[k]))) {
- SW_REDIS_COMMAND_ARGV_FILL(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[k]),
- (size_t) SW_REDIS_COMMAND_ARGS_STRLEN(z_args[k]))
- k++;
- valid_params--;
- }
-
- if (SW_REDIS_COMMAND_ARGS_TYPE(z_args[k]) == IS_STRING &&
- strncasecmp(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[k]), "CH", 2) == 0) {
- SW_REDIS_COMMAND_ARGV_FILL("CH", 2)
- k++;
- valid_params--;
- }
-
- if (SW_REDIS_COMMAND_ARGS_TYPE(z_args[k]) == IS_STRING &&
- strncasecmp(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[k]), "INCR", 4) == 0) {
- SW_REDIS_COMMAND_ARGV_FILL("INCR", 4)
- k++;
- valid_params--;
- }
-
- if (valid_params % 2 != 0) {
- for (i = 0; i < 1 + k; i++) {
- efree((void *) argv[i]);
- }
- SW_REDIS_COMMAND_FREE_ARGV
- efree(z_args);
- RETURN_FALSE;
- }
-
- char buf[32];
- size_t buf_len;
- for (j = k; j < argc - 1; j += 2) {
- buf_len = sw_snprintf(buf, sizeof(buf), "%f", zval_get_double(&z_args[j]));
- SW_REDIS_COMMAND_ARGV_FILL((char *) buf, buf_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(SW_REDIS_COMMAND_ARGS_REF(z_args[j + 1]))
- }
- efree(z_args);
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, zPopMin) {
- char *key;
- size_t key_len;
- zend_long count = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &key, &key_len, &count) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0, argc, buf_len;
- char buf[32];
- argc = ZEND_NUM_ARGS() == 2 ? 3 : 2;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("ZPOPMIN", 7);
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len);
- if (argc == 3) {
- buf_len = sw_snprintf(buf, sizeof(buf), "%" PRId64 "", count);
- SW_REDIS_COMMAND_ARGV_FILL((char *) buf, buf_len);
- }
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, zPopMax) {
- char *key;
- size_t key_len;
- zend_long count = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &key, &key_len, &count) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0, argc, buf_len;
- char buf[32];
- argc = ZEND_NUM_ARGS() == 2 ? 3 : 2;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("ZPOPMAX", 7);
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len);
- if (argc == 3) {
- buf_len = sw_snprintf(buf, sizeof(buf), "%" PRId64 "", count);
- SW_REDIS_COMMAND_ARGV_FILL((char *) buf, buf_len);
- }
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, bzPopMin) {
- int argc = ZEND_NUM_ARGS();
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGS_ARR
- if (zend_get_parameters_array(ht, argc, z_args) == FAILURE || argc < 1) {
- efree(z_args);
- return;
- }
-
- zend_bool single_array = 0;
- if (argc == 2 && SW_REDIS_COMMAND_ARGS_TYPE(z_args[0]) == IS_ARRAY) {
- argc = zend_hash_num_elements(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0])) + 2;
- single_array = 1;
- } else {
- argc += 1;
- }
- int i = 0;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("BZPOPMIN", 8)
- if (single_array) {
- zval *value;
- SW_HASHTABLE_FOREACH_START(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0]), value)
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- SW_HASHTABLE_FOREACH_END();
- zend_string *convert_str = zval_get_string(&z_args[1]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- } else {
- int j;
- for (j = 0; j < argc - 1; ++j) {
- zend_string *convert_str = zval_get_string(&z_args[j]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- }
- }
- efree(z_args);
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, bzPopMax) {
- int argc = ZEND_NUM_ARGS();
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGS_ARR
- if (zend_get_parameters_array(ht, argc, z_args) == FAILURE || argc < 1) {
- efree(z_args);
- return;
- }
-
- zend_bool single_array = 0;
- if (argc == 2 && SW_REDIS_COMMAND_ARGS_TYPE(z_args[0]) == IS_ARRAY) {
- argc = zend_hash_num_elements(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0])) + 2;
- single_array = 1;
- } else {
- argc += 1;
- }
- int i = 0;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("BZPOPMAX", 8)
- if (single_array) {
- zval *value;
- SW_HASHTABLE_FOREACH_START(SW_REDIS_COMMAND_ARGS_ARRVAL(z_args[0]), value)
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- SW_HASHTABLE_FOREACH_END();
- zend_string *convert_str = zval_get_string(&z_args[1]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- } else {
- int j;
- for (j = 0; j < argc - 1; ++j) {
- zend_string *convert_str = zval_get_string(&z_args[j]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- }
- }
- efree(z_args);
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, zScore) {
- sw_redis_command_key_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("ZSCORE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, zRank) {
- sw_redis_command_key_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("ZRANK"));
-}
-
-static PHP_METHOD(swoole_redis_coro, zRevRank) {
- sw_redis_command_key_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("ZREVRANK"));
-}
-
-static PHP_METHOD(swoole_redis_coro, hGet) {
- sw_redis_command_key_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("HGET"));
-}
-
-static PHP_METHOD(swoole_redis_coro, hMGet) {
- char *key;
- zval *z_arr;
- size_t argc, key_len;
- HashTable *ht_chan;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa", &key, &key_len, &z_arr) == FAILURE) {
- return;
- }
-
- ht_chan = Z_ARRVAL_P(z_arr);
-
- if ((argc = zend_hash_num_elements(ht_chan)) == 0) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- zval *value;
- int i = 0;
- argc = argc + 2;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("HMGET", 5)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_HASHTABLE_FOREACH_START(ht_chan, value)
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- SW_HASHTABLE_FOREACH_END();
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- size_t index = 0;
- zval *zkey, *zvalue;
- zval zret;
- array_init(&zret);
-
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_arr), zkey) {
- zend::String zkey_str(zkey);
-
- zvalue = zend_hash_index_find(Z_ARRVAL_P(return_value), index++);
- if (ZVAL_IS_NULL(zvalue)) {
- add_assoc_bool_ex(&zret, zkey_str.val(), zkey_str.len(), 0);
- } else {
- Z_ADDREF_P(zvalue);
- add_assoc_zval_ex(&zret, zkey_str.val(), zkey_str.len(), zvalue);
- }
- }
- ZEND_HASH_FOREACH_END();
-
- zval_ptr_dtor(return_value);
- RETVAL_ZVAL(&zret, 1, 1);
- }
-}
-
-static PHP_METHOD(swoole_redis_coro, hExists) {
- sw_redis_command_key_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("HEXISTS"));
-
- RedisClient *redis = php_swoole_get_redis_client(ZEND_THIS);
- if (redis->compatibility_mode && ZVAL_IS_LONG(return_value)) {
- RETURN_BOOL(zval_get_long(return_value));
- }
-}
-
-static PHP_METHOD(swoole_redis_coro, publish) {
- sw_redis_command_key_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("PUBLISH"));
-}
-
-static PHP_METHOD(swoole_redis_coro, zDeleteRangeByScore) {
- sw_redis_command_key_str_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("ZREMRANGEBYSCORE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, zCount) {
- sw_redis_command_key_str_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("ZCOUNT"));
-}
-
-static PHP_METHOD(swoole_redis_coro, incrBy) {
- sw_redis_command_key_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("INCRBY"));
-}
-
-static PHP_METHOD(swoole_redis_coro, hIncrBy) {
- char *key, *mem;
- size_t key_len, mem_len;
- long byval;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssl", &key, &key_len, &mem, &mem_len, &byval) == FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- SW_REDIS_COMMAND_ARGV_FILL("HINCRBY", 7)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(mem, mem_len)
- char str[32];
- sprintf(str, "%ld", byval);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
-
- redis_request(redis, 4, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, hIncrByFloat) {
- char *key, *mem;
- size_t key_len, mem_len;
- double byval;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssd", &key, &key_len, &mem, &mem_len, &byval) == FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- SW_REDIS_COMMAND_ARGV_FILL("HINCRBYFLOAT", 12)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(mem, mem_len)
- char str[32];
- sprintf(str, "%f", byval);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
-
- redis_request(redis, 4, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, incr) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("INCR"));
-}
-
-static PHP_METHOD(swoole_redis_coro, decrBy) {
- sw_redis_command_key_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("DECRBY"));
-}
-
-static PHP_METHOD(swoole_redis_coro, decr) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("DECR"));
-}
-
-static PHP_METHOD(swoole_redis_coro, getBit) {
- sw_redis_command_key_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("GETBIT"));
-}
-
-static PHP_METHOD(swoole_redis_coro, lInsert) {
- char *key, *pos;
- size_t key_len, pos_len;
- zval *z_val, *z_pivot;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sszz", &key, &key_len, &pos, &pos_len, &z_pivot, &z_val) == FAILURE) {
- return;
- }
-
- if (strncasecmp(pos, "after", 5) && strncasecmp(pos, "before", 6)) {
- php_swoole_error(E_WARNING, "Position must be either 'BEFORE' or 'AFTER'");
- RETURN_FALSE;
- }
-
- SW_REDIS_COMMAND_CHECK
-
- int i = 0;
- size_t argvlen[5];
- char *argv[5];
-
- SW_REDIS_COMMAND_ARGV_FILL("LINSERT", 7)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(pos, pos_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(z_pivot)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(z_val)
- redis_request(redis, 5, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, lGet) {
- sw_redis_command_key_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("LINDEX"));
-}
-
-static PHP_METHOD(swoole_redis_coro, setTimeout) {
- sw_redis_command_key_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("EXPIRE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, pexpire) {
- sw_redis_command_key_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("PEXPIRE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, expireAt) {
- sw_redis_command_key_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("EXPIREAT"));
-}
-
-static PHP_METHOD(swoole_redis_coro, pexpireAt) {
- sw_redis_command_key_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("PEXPIREAT"));
-}
-
-static PHP_METHOD(swoole_redis_coro, move) {
- sw_redis_command_key_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("MOVE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, select) {
- zend_long db_number;
-
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_LONG(db_number)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- SW_REDIS_COMMAND_CHECK
- zval *zsetting = sw_zend_read_and_convert_property_array(swoole_redis_coro_ce, ZEND_THIS, ZEND_STRL("setting"), 0);
- add_assoc_long(zsetting, "database", db_number);
- RETURN_BOOL(redis_select_db(redis, db_number));
-}
-
-static PHP_METHOD(swoole_redis_coro, getRange) {
- sw_redis_command_key_long_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("GETRANGE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, listTrim) {
- sw_redis_command_key_long_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("LTRIM"));
-}
-
-static PHP_METHOD(swoole_redis_coro, lGetRange) {
- sw_redis_command_key_long_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("LRANGE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, lRem) {
- char *key;
- size_t key_len;
- zend_long count = 0;
- zval *z_val;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|l", &key, &key_len, &z_val, &count) == FAILURE) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- SW_REDIS_COMMAND_ARGV_FILL("LREM", 4)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char str[32];
- sprintf(str, "%d", (int) count);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(z_val)
-
- redis_request(redis, 4, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, zDeleteRangeByRank) {
- sw_redis_command_key_long_long(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("ZREMRANGEBYRANK"));
-}
-
-static PHP_METHOD(swoole_redis_coro, incrByFloat) {
- sw_redis_command_key_dbl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("INCRBYFLOAT"));
-}
-
-static PHP_METHOD(swoole_redis_coro, bitCount) {
- char *key;
- size_t key_len;
- zend_long start = 0, end = -1;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ll", &key, &key_len, &start, &end) == FAILURE) {
- return;
- }
-
- SW_REDIS_COMMAND_CHECK
-
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- SW_REDIS_COMMAND_ARGV_FILL("BITCOUNT", 8)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- char str[32];
- sprintf(str, "%d", (int) start);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
- sprintf(str, "%d", (int) end);
- SW_REDIS_COMMAND_ARGV_FILL(str, strlen(str))
-
- redis_request(redis, 4, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, bitOp) {
- int argc = ZEND_NUM_ARGS();
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGS_ARR
- if (zend_get_parameters_array(ht, argc, z_args) == FAILURE || argc < 3 ||
- SW_REDIS_COMMAND_ARGS_TYPE(z_args[0]) != IS_STRING) {
- efree(z_args);
- return;
- }
-
- int j, i = 0;
- argc++;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("BITOP", 5)
- SW_REDIS_COMMAND_ARGV_FILL(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[0]), SW_REDIS_COMMAND_ARGS_STRLEN(z_args[0]))
- for (j = 1; j < argc - 1; j++) {
- zend_string *convert_str = zval_get_string(&z_args[j]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
- efree(z_args);
-}
-
-static PHP_METHOD(swoole_redis_coro, sMove) {
- char *src, *dst;
- size_t src_len, dst_len;
- zval *z_val;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssz", &src, &src_len, &dst, &dst_len, &z_val) == FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
-
- int i = 0;
- size_t argvlen[4];
- char *argv[4];
- SW_REDIS_COMMAND_ARGV_FILL("SMOVE", 5)
- SW_REDIS_COMMAND_ARGV_FILL(src, src_len)
- SW_REDIS_COMMAND_ARGV_FILL(dst, dst_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(z_val)
- redis_request(redis, 4, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, sAdd) {
- sw_redis_command_key_var_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SADD"));
-}
-
-static PHP_METHOD(swoole_redis_coro, sRemove) {
- sw_redis_command_key_var_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("SREM"));
-}
-
-static PHP_METHOD(swoole_redis_coro, zDelete) {
- sw_redis_command_key_var_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("ZREM"));
-}
-
-static sw_inline void redis_subscribe(INTERNAL_FUNCTION_PARAMETERS, const char *cmd) {
- zval *z_arr;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &z_arr) == FAILURE) {
- RETURN_FALSE;
- }
-
- SW_REDIS_COMMAND_CHECK
- if (redis->defer) {
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("errType"), SW_REDIS_ERR_OTHER);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(SW_REDIS_ERR_OTHER));
- zend_update_property_string(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(ZEND_THIS),
- ZEND_STRL("errMsg"),
- "subscribe cannot be used with defer enabled");
- RETURN_FALSE;
- }
-
- HashTable *ht_chan = Z_ARRVAL_P(z_arr);
- size_t chan_num = zend_hash_num_elements(ht_chan);
- int argc = 1 + chan_num, i = 0;
- SW_REDIS_COMMAND_ALLOC_ARGV
-
- SW_REDIS_COMMAND_ARGV_FILL(cmd, strlen(cmd));
-
- zval *value;
- SW_HASHTABLE_FOREACH_START(ht_chan, value)
- zend_string *convert_str = zval_get_string(value);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str))
- zend_string_release(convert_str);
- SW_HASHTABLE_FOREACH_END();
-
- redis->defer = true;
- redis_request(redis, argc, argv, argvlen, return_value);
- redis->defer = false;
- SW_REDIS_COMMAND_FREE_ARGV
-
- if (Z_TYPE_P(return_value) == IS_TRUE) {
- redis->session.subscribe = true;
- }
-}
-
-static PHP_METHOD(swoole_redis_coro, subscribe) {
- redis_subscribe(INTERNAL_FUNCTION_PARAM_PASSTHRU, "SUBSCRIBE");
-}
-
-static PHP_METHOD(swoole_redis_coro, pSubscribe) {
- redis_subscribe(INTERNAL_FUNCTION_PARAM_PASSTHRU, "PSUBSCRIBE");
-}
-
-static PHP_METHOD(swoole_redis_coro, unsubscribe) {
- redis_subscribe(INTERNAL_FUNCTION_PARAM_PASSTHRU, "UNSUBSCRIBE");
-}
-
-static PHP_METHOD(swoole_redis_coro, pUnSubscribe) {
- redis_subscribe(INTERNAL_FUNCTION_PARAM_PASSTHRU, "PUNSUBSCRIBE");
-}
-
-static PHP_METHOD(swoole_redis_coro, multi) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("MULTI"));
-}
-
-static PHP_METHOD(swoole_redis_coro, exec) {
- sw_redis_command_empty(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("EXEC"));
-}
-
-static PHP_METHOD(swoole_redis_coro, request) {
- SW_REDIS_COMMAND_CHECK
-
- zval *params = nullptr;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", ¶ms) == FAILURE) {
- RETURN_FALSE;
- }
-
- int argc = zend_hash_num_elements(Z_ARRVAL_P(params));
- int i = 0;
- zval *value;
-
- SW_REDIS_COMMAND_ALLOC_ARGV
-
- SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(params), value)
- if (i == argc) {
- break;
- }
- zend_string *convert_str = zval_get_string(value);
- argvlen[i] = ZSTR_LEN(convert_str);
- argv[i] = estrndup(ZSTR_VAL(convert_str), ZSTR_LEN(convert_str));
- zend_string_release(convert_str);
- i++;
- SW_HASHTABLE_FOREACH_END();
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, eval) {
- char *script;
- size_t script_len;
- zval *params = nullptr;
- zend_long keys_num = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|al", &script, &script_len, ¶ms, &keys_num) == FAILURE) {
- RETURN_FALSE;
- }
-
- HashTable *params_ht = nullptr;
- uint32_t params_num = 0;
- if (params) {
- params_ht = Z_ARRVAL_P(params);
- params_num = zend_hash_num_elements(params_ht);
- }
-
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t *argvlen = (size_t *) emalloc(sizeof(size_t) * (params_num + 3));
- char **argv = (char **) emalloc(sizeof(char *) * (params_num + 3));
-
- SW_REDIS_COMMAND_ARGV_FILL("EVAL", 4)
- SW_REDIS_COMMAND_ARGV_FILL(script, script_len)
-
- char keys_num_str[32] = {};
- sprintf(keys_num_str, ZEND_LONG_FMT, keys_num);
- SW_REDIS_COMMAND_ARGV_FILL(keys_num_str, strlen(keys_num_str));
-
- if (params_ht) {
- zval *param;
- SW_HASHTABLE_FOREACH_START(params_ht, param)
- zend_string *param_str = zval_get_string(param);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(param_str), ZSTR_LEN(param_str))
- zend_string_release(param_str);
- SW_HASHTABLE_FOREACH_END();
- }
-
- redis_request(redis, params_num + 3, argv, argvlen, return_value);
- efree(argvlen);
- efree(argv);
-}
-
-static PHP_METHOD(swoole_redis_coro, evalSha) {
- char *sha;
- size_t sha_len;
- zval *params = nullptr;
- long keys_num = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|al", &sha, &sha_len, ¶ms, &keys_num) == FAILURE) {
- RETURN_FALSE;
- }
-
- HashTable *params_ht = nullptr;
- uint32_t params_num = 0;
- if (params) {
- params_ht = Z_ARRVAL_P(params);
- params_num = zend_hash_num_elements(params_ht);
- }
-
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- size_t *argvlen = (size_t *) emalloc(sizeof(size_t) * (params_num + 3));
- char **argv = (char **) emalloc(sizeof(char *) * (params_num + 3));
-
- SW_REDIS_COMMAND_ARGV_FILL("EVALSHA", 7)
- SW_REDIS_COMMAND_ARGV_FILL(sha, sha_len)
-
- char keys_num_str[32] = {};
- sprintf(keys_num_str, "%ld", keys_num);
- SW_REDIS_COMMAND_ARGV_FILL(keys_num_str, strlen(keys_num_str));
-
- if (params) {
- zval *param;
- SW_HASHTABLE_FOREACH_START(params_ht, param)
- zend_string *param_str = zval_get_string(param);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(param_str), ZSTR_LEN(param_str))
- zend_string_release(param_str);
- SW_HASHTABLE_FOREACH_END();
- }
-
- redis_request(redis, params_num + 3, argv, argvlen, return_value);
- efree(argvlen);
- efree(argv);
-}
-
-static PHP_METHOD(swoole_redis_coro, script) {
- int argc = ZEND_NUM_ARGS();
- if (argc < 1) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGS_ARR
- if (zend_get_parameters_array(ht, argc, z_args) == FAILURE || SW_REDIS_COMMAND_ARGS_TYPE(z_args[0]) != IS_STRING) {
- efree(z_args);
- RETURN_FALSE;
- }
-
- int i = 0;
- if (!strcasecmp(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[0]), "flush") ||
- !strcasecmp(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[0]), "kill")) {
- size_t argvlen[2];
- char *argv[2];
- SW_REDIS_COMMAND_ARGV_FILL("SCRIPT", 6)
- SW_REDIS_COMMAND_ARGV_FILL(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[0]), SW_REDIS_COMMAND_ARGS_STRLEN(z_args[0]))
- redis_request(redis, 2, argv, argvlen, return_value);
- efree(z_args);
- } else if (!strcasecmp(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[0]), "exists")) {
- if (argc < 2) {
- efree(z_args);
- RETURN_FALSE;
- } else {
- size_t *argvlen = (size_t *) emalloc(sizeof(size_t) * (argc + 1));
- char **argv = (char **) emalloc(sizeof(char *) * (argc + 1));
- SW_REDIS_COMMAND_ARGV_FILL("SCRIPT", 6)
- SW_REDIS_COMMAND_ARGV_FILL("EXISTS", 6)
- int j = 1;
- for (; j < argc; j++) {
- zend_string *z_arg_str = zval_get_string(&z_args[j]);
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(z_arg_str), ZSTR_LEN(z_arg_str))
- zend_string_release(z_arg_str);
- }
-
- redis_request(redis, argc + 1, argv, argvlen, return_value);
- efree(argvlen);
- efree(argv);
- efree(z_args);
- }
- } else if (!strcasecmp(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[0]), "load")) {
- if (argc < 2 || SW_REDIS_COMMAND_ARGS_TYPE(z_args[1]) != IS_STRING) {
- efree(z_args);
- RETURN_FALSE;
- } else {
- size_t argvlen[3];
- char *argv[3];
- SW_REDIS_COMMAND_ARGV_FILL("SCRIPT", 6)
- SW_REDIS_COMMAND_ARGV_FILL("LOAD", 4)
- SW_REDIS_COMMAND_ARGV_FILL(SW_REDIS_COMMAND_ARGS_STRVAL(z_args[1]), SW_REDIS_COMMAND_ARGS_STRLEN(z_args[1]))
- redis_request(redis, 3, argv, argvlen, return_value);
- efree(z_args);
- }
- } else {
- efree(z_args);
- RETURN_FALSE;
- }
-}
-
-static PHP_METHOD(swoole_redis_coro, xLen) {
- sw_redis_command_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("XLEN"));
-}
-
-static PHP_METHOD(swoole_redis_coro, xAdd) {
- zval *z_options = nullptr, *z_ele;
- HashTable *ht_opt, *ht_ele;
- char *key, *id;
- size_t key_len, id_len;
- zval *z_arr;
- int argc, options_argc = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssa|a", &key, &key_len, &id, &id_len, &z_arr, &z_options) == FAILURE) {
- return;
- }
- if ((argc = zend_hash_num_elements(Z_ARRVAL_P(z_arr))) == 0) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0;
- argc = argc * 2 + 3;
- zval *value;
- char buf[32];
- size_t buf_len;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("XADD", 4)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
-
- // options
- if (z_options && ZVAL_IS_ARRAY(z_options)) {
- ht_opt = Z_ARRVAL_P(z_options);
- int has_maxlen_minid = 0;
- int can_limit = 0;
- // NOMKSTREAM
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("nomkstream"))) && Z_TYPE_P(z_ele) == IS_TRUE) {
- SW_REDIS_COMMAND_ARGV_FILL("NOMKSTREAM", 10)
- options_argc++;
- }
- // MAXLEN
- if (has_maxlen_minid == 0 && (z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("maxlen")))) {
- has_maxlen_minid = 1;
- if (Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("MAXLEN", 6)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- } else if (Z_TYPE_P(z_ele) == IS_ARRAY) {
- ht_ele = Z_ARRVAL_P(z_ele);
- zval *z_maxlen_p1 = zend_hash_index_find(ht_ele, 0);
- zval *z_maxlen_p2 = zend_hash_index_find(ht_ele, 1);
- if (Z_TYPE_P(z_maxlen_p1) == IS_STRING && Z_TYPE_P(z_maxlen_p2) == IS_LONG) {
- char *maxlen_p1 = Z_STRVAL_P(z_maxlen_p1);
- zend_long maxlen_p2 = Z_LVAL_P(z_maxlen_p2);
- if ((strcmp(maxlen_p1, "=") == 0 || strcmp(maxlen_p1, "~") == 0) && maxlen_p2 >= 0) {
- if ((strcmp(maxlen_p1, "~") == 0)) {
- can_limit = 1;
- }
- SW_REDIS_COMMAND_ARGV_FILL("MAXLEN", 6)
- SW_REDIS_COMMAND_ARGV_FILL(maxlen_p1, 1)
- buf_len = sprintf(buf, ZEND_LONG_FMT, maxlen_p2);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 3;
- }
- }
- }
- }
- // MINID
- if (has_maxlen_minid == 0 && (z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("minid")))) {
- has_maxlen_minid = 1;
- if (Z_TYPE_P(z_ele) == IS_STRING && Z_STRLEN_P(z_ele) > 0) {
- SW_REDIS_COMMAND_ARGV_FILL("MINID", 5)
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele))
- options_argc += 2;
- } else if (Z_TYPE_P(z_ele) == IS_ARRAY) {
- ht_ele = Z_ARRVAL_P(z_ele);
- zval *z_minid_p1 = zend_hash_index_find(ht_ele, 0);
- zval *z_minid_p2 = zend_hash_index_find(ht_ele, 1);
- if (Z_TYPE_P(z_minid_p1) == IS_STRING && Z_TYPE_P(z_minid_p2) == IS_STRING) {
- char *minid_p1 = Z_STRVAL_P(z_minid_p1);
- char *minid_p2 = Z_STRVAL_P(z_minid_p2);
- if ((strcmp(minid_p1, "=") == 0 || strcmp(minid_p1, "~") == 0) && strlen(minid_p2) > 0) {
- if ((strcmp(minid_p1, "~") == 0)) {
- can_limit = 1;
- }
- SW_REDIS_COMMAND_ARGV_FILL("MINID", 5)
- SW_REDIS_COMMAND_ARGV_FILL(minid_p1, 1)
- SW_REDIS_COMMAND_ARGV_FILL(minid_p2, strlen(minid_p2))
- options_argc += 3;
- }
- }
- }
- }
- // LIMIT
- if (can_limit == 1 && (z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("limit"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("LIMIT", 5)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- }
- }
-
- SW_REDIS_COMMAND_INCREASE_ARGV(argc + options_argc)
-
- // id
- SW_REDIS_COMMAND_ARGV_FILL(id, id_len)
-
- // k-v
- zend_ulong idx;
- zend_string *_key;
- ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(z_arr), idx, _key, value) {
- if (_key == nullptr) {
- key_len = sw_snprintf(buf, sizeof(buf), ZEND_LONG_FMT, idx);
- key = (char *) buf;
- } else {
- key_len = ZSTR_LEN(_key);
- key = ZSTR_VAL(_key);
- }
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL_WITH_SERIALIZE(value)
- }
- ZEND_HASH_FOREACH_END();
-
- redis_request(redis, argc, argv, argvlen, return_value);
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, xRead) {
- zval *z_streams = nullptr, *z_options = nullptr, *z_ele;
- HashTable *ht_opt;
- int i = 0, argc = 0, options_argc = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|a", &z_streams, &z_options) == FAILURE) {
- RETURN_FALSE;
- }
- if ((argc = zend_hash_num_elements(Z_ARRVAL_P(z_streams))) == 0) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
-
- argc = argc * 2 + 2;
- char buf[32];
- size_t buf_len;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("XREAD", 5)
-
- // options
- if (z_options && ZVAL_IS_ARRAY(z_options)) {
- ht_opt = Z_ARRVAL_P(z_options);
- // COUNT
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("count"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("COUNT", 5)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- }
- // BLOCK
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("block"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("BLOCK", 5)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- }
- }
-
- SW_REDIS_COMMAND_INCREASE_ARGV(argc + options_argc)
-
- // streams
- SW_REDIS_COMMAND_ARGV_FILL("STREAMS", 7)
- zend_long _num_key;
- zend_string *_str_key;
- zval *_val;
- ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(z_streams), _num_key, _str_key) {
- if (_str_key == NULL) {
- _str_key = zend_long_to_str(_num_key);
- }
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(_str_key), ZSTR_LEN(_str_key))
- }
- ZEND_HASH_FOREACH_END();
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_streams), _val) {
- convert_to_string(_val);
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(_val), Z_STRLEN_P(_val))
- }
- ZEND_HASH_FOREACH_END();
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, xRange) {
- sw_redis_command_xrange(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("XRANGE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, xRevRange) {
- sw_redis_command_xrange(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("XREVRANGE"));
-}
-
-static PHP_METHOD(swoole_redis_coro, xTrim) {
- zval *z_options = nullptr, *z_ele;
- HashTable *ht_opt, *ht_ele;
- int i = 0, argc = 2, options_argc = 0;
- char buf[32], *key;
- size_t buf_len, key_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &key, &key_len, &z_options) == FAILURE) {
- RETURN_FALSE;
- }
- if (php_swoole_array_length_safe(z_options) < 1) {
- RETURN_FALSE;
- }
-
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("XTRIM", 5)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
-
- // options
- if (z_options && ZVAL_IS_ARRAY(z_options)) {
- ht_opt = Z_ARRVAL_P(z_options);
- int has_maxlen_minid = 0;
- int can_limit = 0;
- // MAXLEN
- if (has_maxlen_minid == 0 && (z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("maxlen")))) {
- has_maxlen_minid = 1;
- if (Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("MAXLEN", 6)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- } else if (Z_TYPE_P(z_ele) == IS_ARRAY) {
- ht_ele = Z_ARRVAL_P(z_ele);
- zval *z_maxlen_p1 = zend_hash_index_find(ht_ele, 0);
- zval *z_maxlen_p2 = zend_hash_index_find(ht_ele, 1);
- if (Z_TYPE_P(z_maxlen_p1) == IS_STRING && Z_TYPE_P(z_maxlen_p2) == IS_LONG) {
- char *maxlen_p1 = Z_STRVAL_P(z_maxlen_p1);
- zend_long maxlen_p2 = Z_LVAL_P(z_maxlen_p2);
- if ((strcmp(maxlen_p1, "=") == 0 || strcmp(maxlen_p1, "~") == 0) && maxlen_p2 >= 0) {
- if ((strcmp(maxlen_p1, "~") == 0)) {
- can_limit = 1;
- }
- SW_REDIS_COMMAND_ARGV_FILL("MAXLEN", 6)
- SW_REDIS_COMMAND_ARGV_FILL(maxlen_p1, 1)
- buf_len = sprintf(buf, ZEND_LONG_FMT, maxlen_p2);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 3;
- }
- }
- }
- }
- // MINID
- if (has_maxlen_minid == 0 && (z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("minid")))) {
- has_maxlen_minid = 1;
- if (Z_TYPE_P(z_ele) == IS_STRING && Z_STRLEN_P(z_ele) > 0) {
- SW_REDIS_COMMAND_ARGV_FILL("MINID", 5)
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele))
- options_argc += 2;
- } else if (Z_TYPE_P(z_ele) == IS_ARRAY) {
- ht_ele = Z_ARRVAL_P(z_ele);
- zval *z_minid_p1 = zend_hash_index_find(ht_ele, 0);
- zval *z_minid_p2 = zend_hash_index_find(ht_ele, 1);
- if (Z_TYPE_P(z_minid_p1) == IS_STRING && Z_TYPE_P(z_minid_p2) == IS_STRING) {
- char *minid_p1 = Z_STRVAL_P(z_minid_p1);
- char *minid_p2 = Z_STRVAL_P(z_minid_p2);
- if ((strcmp(minid_p1, "=") == 0 || strcmp(minid_p1, "~") == 0) && strlen(minid_p2) > 0) {
- if ((strcmp(minid_p1, "~") == 0)) {
- can_limit = 1;
- }
- SW_REDIS_COMMAND_ARGV_FILL("MINID", 5)
- SW_REDIS_COMMAND_ARGV_FILL(minid_p1, 1)
- SW_REDIS_COMMAND_ARGV_FILL(minid_p2, strlen(minid_p2))
- options_argc += 3;
- }
- }
- }
- }
- // LIMIT
- if (can_limit == 1 && (z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("limit"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("LIMIT", 5)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- }
- }
-
- SW_REDIS_COMMAND_INCREASE_ARGV(argc + options_argc)
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, xDel) {
- sw_redis_command_key_var_val(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("XDEL"));
-}
-
-static PHP_METHOD(swoole_redis_coro, xGroupCreate) {
- char *key, *group_name, *id;
- size_t key_len, group_name_len, id_len;
- zend_bool mkstream = 0;
-
- if (zend_parse_parameters(
- ZEND_NUM_ARGS(), "sss|b", &key, &key_len, &group_name, &group_name_len, &id, &id_len, &mkstream) ==
- FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0, argc = 5;
- size_t argvlen[6];
- char *argv[6];
- SW_REDIS_COMMAND_ARGV_FILL("XGROUP", 6)
- SW_REDIS_COMMAND_ARGV_FILL("CREATE", 6)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(group_name, group_name_len)
- SW_REDIS_COMMAND_ARGV_FILL(id, id_len)
- if (mkstream) {
- SW_REDIS_COMMAND_ARGV_FILL("MKSTREAM", 8)
- argc = 6;
- }
-
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, xGroupSetId) {
- char *key, *group_name, *id;
- size_t key_len, group_name_len, id_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss", &key, &key_len, &group_name, &group_name_len, &id, &id_len) ==
- FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0, argc = 5;
- size_t argvlen[5];
- char *argv[5];
- SW_REDIS_COMMAND_ARGV_FILL("XGROUP", 6)
- SW_REDIS_COMMAND_ARGV_FILL("CREATECONSUMER", 14)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(group_name, group_name_len)
- SW_REDIS_COMMAND_ARGV_FILL(id, id_len)
-
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, xGroupDestroy) {
- char *key, *group_name;
- size_t key_len, group_name_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &key, &key_len, &group_name, &group_name_len) == FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0, argc = 4;
- size_t argvlen[4];
- char *argv[4];
- SW_REDIS_COMMAND_ARGV_FILL("XGROUP", 6)
- SW_REDIS_COMMAND_ARGV_FILL("DESTROY", 7)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(group_name, group_name_len)
-
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, xGroupCreateConsumer) {
- char *key, *group_name, *consumer_name;
- size_t key_len, group_name_len, consumer_name_len;
-
- if (zend_parse_parameters(
- ZEND_NUM_ARGS(), "sss", &key, &key_len, &group_name, &group_name_len, &consumer_name, &consumer_name_len) ==
- FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0, argc = 5;
- size_t argvlen[5];
- char *argv[5];
- SW_REDIS_COMMAND_ARGV_FILL("XGROUP", 6)
- SW_REDIS_COMMAND_ARGV_FILL("CREATECONSUMER", 14)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(group_name, group_name_len)
- SW_REDIS_COMMAND_ARGV_FILL(consumer_name, consumer_name_len)
-
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, xGroupDelConsumer) {
- char *key, *group_name, *consumer_name;
- size_t key_len, group_name_len, consumer_name_len;
-
- if (zend_parse_parameters(
- ZEND_NUM_ARGS(), "sss", &key, &key_len, &group_name, &group_name_len, &consumer_name, &consumer_name_len) ==
- FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0, argc = 5;
- size_t argvlen[5];
- char *argv[5];
- SW_REDIS_COMMAND_ARGV_FILL("XGROUP", 6)
- SW_REDIS_COMMAND_ARGV_FILL("DELCONSUMER", 11)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(group_name, group_name_len)
- SW_REDIS_COMMAND_ARGV_FILL(consumer_name, consumer_name_len)
-
- redis_request(redis, argc, argv, argvlen, return_value);
-}
-
-static PHP_METHOD(swoole_redis_coro, xReadGroup) {
- char *group_name, *consumer_name;
- size_t group_name_len, consumer_name_len;
- zval *z_streams = nullptr, *z_options = nullptr, *z_ele;
- HashTable *ht_opt;
- int i = 0, argc = 0, options_argc = 0;
- char buf[32];
- size_t buf_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(),
- "ssa|a",
- &group_name,
- &group_name_len,
- &consumer_name,
- &consumer_name_len,
- &z_streams,
- &z_options) == FAILURE) {
- RETURN_FALSE;
- }
- if ((argc = zend_hash_num_elements(Z_ARRVAL_P(z_streams))) == 0) {
- RETURN_FALSE;
- }
- SW_REDIS_COMMAND_CHECK
- argc = argc * 2 + 5;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("XREADGROUP", 10)
- SW_REDIS_COMMAND_ARGV_FILL("GROUP", 5)
- SW_REDIS_COMMAND_ARGV_FILL(group_name, group_name_len)
- SW_REDIS_COMMAND_ARGV_FILL(consumer_name, consumer_name_len)
-
- // options
- if (z_options && ZVAL_IS_ARRAY(z_options)) {
- ht_opt = Z_ARRVAL_P(z_options);
- // COUNT
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("count"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("COUNT", 5)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- }
- // BLOCK
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("block"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("BLOCK", 5)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- }
- // NOACK
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("noack"))) && Z_TYPE_P(z_ele) == IS_TRUE) {
- SW_REDIS_COMMAND_ARGV_FILL("NOACK", 5)
- options_argc++;
- }
- }
-
- SW_REDIS_COMMAND_INCREASE_ARGV(argc + options_argc)
-
- // streams
- SW_REDIS_COMMAND_ARGV_FILL("STREAMS", 7)
- zend_long _num_key;
- zend_string *_str_key;
- zval *_val;
- ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(z_streams), _num_key, _str_key) {
- if (_str_key == NULL) {
- _str_key = zend_long_to_str(_num_key);
- }
- SW_REDIS_COMMAND_ARGV_FILL(ZSTR_VAL(_str_key), ZSTR_LEN(_str_key))
- }
- ZEND_HASH_FOREACH_END();
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_streams), _val) {
- convert_to_string(_val);
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(_val), Z_STRLEN_P(_val))
- }
- ZEND_HASH_FOREACH_END();
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, xPending) {
- char *key, *group_name;
- size_t key_len, group_name_len;
- zval *z_options = nullptr, *z_ele;
- HashTable *ht_opt;
- int i = 0, argc = 3, options_argc = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|a", &key, &key_len, &group_name, &group_name_len, &z_options) ==
- FAILURE) {
- RETURN_FALSE;
- }
-
- char buf[32];
- size_t buf_len;
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("XPENDING", 8)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(group_name, group_name_len)
-
- // options
- if (z_options && ZVAL_IS_ARRAY(z_options)) {
- ht_opt = Z_ARRVAL_P(z_options);
- // IDLE
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("idle"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("IDLE", 4)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- }
- // START
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("start"))) && Z_TYPE_P(z_ele) == IS_STRING) {
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele))
- options_argc++;
- }
- // END
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("end"))) && Z_TYPE_P(z_ele) == IS_STRING) {
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele))
- options_argc++;
- }
- // COUNT
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("count"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc++;
- }
- // CONSUMER
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("consumer"))) && Z_TYPE_P(z_ele) == IS_TRUE) {
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(z_ele), Z_STRLEN_P(z_ele))
- options_argc++;
- }
- }
-
- SW_REDIS_COMMAND_INCREASE_ARGV(argc + options_argc)
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, xAck) {
- char *key, *group_name;
- size_t key_len, group_name_len;
- zval *z_id = nullptr;
- int i = 0, argc = 3, id_argc = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssa", &key, &key_len, &group_name, &group_name_len, &z_id) == FAILURE) {
- RETURN_FALSE;
- }
- if ((id_argc = zend_hash_num_elements(Z_ARRVAL_P(z_id))) == 0) {
- RETURN_FALSE;
- }
- argc += id_argc;
- SW_REDIS_COMMAND_CHECK
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("XACK", 4)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(group_name, group_name_len)
-
- // id
- zval *_id;
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_id), _id) {
- convert_to_string(_id);
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(_id), Z_STRLEN_P(_id))
- }
- ZEND_HASH_FOREACH_END();
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, xClaim) {
- char *key, *group_name, *consumer_name;
- size_t key_len, group_name_len, consumer_name_len;
- zend_long min_idle_time = 0;
- zval *z_id = nullptr, *z_options = nullptr, *z_ele;
- HashTable *ht_opt;
- int i = 0, argc = 5, id_argc = 0, options_argc = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(),
- "sssla|a",
- &key,
- &key_len,
- &group_name,
- &group_name_len,
- &consumer_name,
- &consumer_name_len,
- &min_idle_time,
- &z_id,
- &z_options) == FAILURE) {
- RETURN_FALSE;
- }
-
- SW_REDIS_COMMAND_CHECK
- id_argc = zend_hash_num_elements(Z_ARRVAL_P(z_id));
- argc += id_argc;
- char buf[32];
- size_t buf_len;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("XCLAIM", 6)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(group_name, group_name_len)
- SW_REDIS_COMMAND_ARGV_FILL(consumer_name, consumer_name_len)
- buf_len = sprintf(buf, ZEND_LONG_FMT, min_idle_time);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
-
- // id
- zval *_id;
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_id), _id) {
- convert_to_string(_id);
- SW_REDIS_COMMAND_ARGV_FILL(Z_STRVAL_P(_id), Z_STRLEN_P(_id))
- }
- ZEND_HASH_FOREACH_END();
-
- // options
- if (z_options && ZVAL_IS_ARRAY(z_options)) {
- ht_opt = Z_ARRVAL_P(z_options);
- // IDLE
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("idle"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("IDLE", 4)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- }
- // TIME
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("time"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("TIME", 4)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- }
- // RETRYCOUNT
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("retrycount"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("RETRYCOUNT", 10)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- }
- // FORCE
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("force"))) && Z_TYPE_P(z_ele) == IS_TRUE) {
- SW_REDIS_COMMAND_ARGV_FILL("FORCE", 5)
- options_argc++;
- }
- // JUSTID
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("justid"))) && Z_TYPE_P(z_ele) == IS_TRUE) {
- SW_REDIS_COMMAND_ARGV_FILL("JUSTID", 6)
- options_argc++;
- }
- }
-
- SW_REDIS_COMMAND_INCREASE_ARGV(argc + options_argc)
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, xAutoClaim) {
- char *key, *group_name, *consumer_name, *start;
- size_t key_len, group_name_len, consumer_name_len, start_len;
- zend_long min_idle_time = 0;
- zval *z_options = nullptr, *z_ele;
- HashTable *ht_opt;
- int i = 0, argc = 6, options_argc = 0;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(),
- "sssls|a",
- &key,
- &key_len,
- &group_name,
- &group_name_len,
- &consumer_name,
- &consumer_name_len,
- &min_idle_time,
- &start,
- &start_len,
- &z_options) == FAILURE) {
- RETURN_FALSE;
- }
-
- SW_REDIS_COMMAND_CHECK
- char buf[32];
- size_t buf_len;
- SW_REDIS_COMMAND_ALLOC_ARGV
- SW_REDIS_COMMAND_ARGV_FILL("XAUTOCLAIM", 10)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(group_name, group_name_len)
- SW_REDIS_COMMAND_ARGV_FILL(consumer_name, consumer_name_len)
- buf_len = sprintf(buf, ZEND_LONG_FMT, min_idle_time);
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- SW_REDIS_COMMAND_ARGV_FILL(start, start_len)
-
- // options
- if (z_options && ZVAL_IS_ARRAY(z_options)) {
- ht_opt = Z_ARRVAL_P(z_options);
- // COUNT
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("count"))) && Z_TYPE_P(z_ele) == IS_LONG) {
- SW_REDIS_COMMAND_ARGV_FILL("COUNT", 5)
- buf_len = sprintf(buf, ZEND_LONG_FMT, Z_LVAL_P(z_ele));
- SW_REDIS_COMMAND_ARGV_FILL(buf, buf_len)
- options_argc += 2;
- }
- // JUSTID
- if ((z_ele = zend_hash_str_find(ht_opt, ZEND_STRL("justid"))) && Z_TYPE_P(z_ele) == IS_TRUE) {
- SW_REDIS_COMMAND_ARGV_FILL("JUSTID", 6)
- options_argc++;
- }
- }
-
- SW_REDIS_COMMAND_INCREASE_ARGV(argc + options_argc)
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-
- SW_REDIS_COMMAND_FREE_ARGV
-}
-
-static PHP_METHOD(swoole_redis_coro, xInfoConsumers) {
- char *key, *group_name;
- size_t key_len, group_name_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &key, &key_len, &group_name, &group_name_len) == FAILURE) {
- return;
- }
-
- SW_REDIS_COMMAND_CHECK
- int i = 0, argc = 4;
- size_t argvlen[4];
- char *argv[4];
- SW_REDIS_COMMAND_ARGV_FILL("XINFO", 5)
- SW_REDIS_COMMAND_ARGV_FILL("CONSUMERS", 9)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
- SW_REDIS_COMMAND_ARGV_FILL(group_name, group_name_len)
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-}
-
-static PHP_METHOD(swoole_redis_coro, xInfoGroups) {
- char *key;
- size_t key_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &key, &key_len) == FAILURE) {
- return;
- }
-
- SW_REDIS_COMMAND_CHECK
- int i = 0, argc = 3;
- size_t argvlen[3];
- char *argv[3];
- SW_REDIS_COMMAND_ARGV_FILL("XINFO", 5)
- SW_REDIS_COMMAND_ARGV_FILL("GROUPS", 6)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-}
-
-static PHP_METHOD(swoole_redis_coro, xInfoStream) {
- char *key;
- size_t key_len;
-
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &key, &key_len) == FAILURE) {
- return;
- }
- SW_REDIS_COMMAND_CHECK
- int i = 0, argc = 3;
- size_t argvlen[3];
- char *argv[3];
- SW_REDIS_COMMAND_ARGV_FILL("XINFO", 5)
- SW_REDIS_COMMAND_ARGV_FILL("STREAM", 6)
- SW_REDIS_COMMAND_ARGV_FILL(key, key_len)
-
- redis_request(redis, argc, argv, argvlen, return_value);
-
- if (redis->compatibility_mode && ZVAL_IS_ARRAY(return_value)) {
- swoole_redis_handle_assoc_array_result(return_value, true);
- }
-}
-
-static void swoole_redis_coro_parse_result(RedisClient *redis, zval *return_value, redisReply *reply) {
- int j;
- zval _val, *val = &_val;
-
- switch (reply->type) {
- case REDIS_REPLY_INTEGER:
- ZVAL_LONG(return_value, reply->integer);
- break;
-
- case REDIS_REPLY_DOUBLE:
- ZVAL_DOUBLE(return_value, reply->dval);
- break;
-
- case REDIS_REPLY_BOOL:
- ZVAL_BOOL(return_value, reply->integer);
- break;
-
- case REDIS_REPLY_ERROR:
- ZVAL_FALSE(return_value);
- if (redis->context->err == 0) {
- if (strncmp(reply->str, "NOAUTH", 6) == 0) {
- redis->context->err = SW_REDIS_ERR_NOAUTH;
- } else {
- redis->context->err = SW_REDIS_ERR_OTHER;
- }
- size_t str_len = strlen(reply->str);
- memcpy(redis->context->errstr, reply->str, SW_MIN(str_len, sizeof(redis->context->errstr) - 1));
- }
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errType"), redis->context->err);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(redis->zobject),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(redis->context->err));
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errMsg"), redis->context->errstr);
- break;
-
- case REDIS_REPLY_STATUS:
- if (redis->context->err == 0) {
- if (reply->len > 0) {
- if (strncmp(reply->str, "OK", 2) == 0) {
- ZVAL_TRUE(return_value);
- break;
- }
- long l;
- if (strncmp(reply->str, "string", 6) == 0) {
- l = SW_REDIS_TYPE_STRING;
- } else if (strncmp(reply->str, "set", 3) == 0) {
- l = SW_REDIS_TYPE_SET;
- } else if (strncmp(reply->str, "list", 4) == 0) {
- l = SW_REDIS_TYPE_LIST;
- } else if (strncmp(reply->str, "zset", 4) == 0) {
- l = SW_REDIS_TYPE_ZSET;
- } else if (strncmp(reply->str, "hash", 4) == 0) {
- l = SW_REDIS_TYPE_HASH;
- } else {
- l = SW_REDIS_TYPE_NOT_FOUND;
- }
- ZVAL_LONG(return_value, l);
- } else {
- ZVAL_TRUE(return_value);
- }
- } else {
- ZVAL_FALSE(return_value);
- zend_update_property_long(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errType"), redis->context->err);
- zend_update_property_long(swoole_redis_coro_ce,
- SW_Z8_OBJ_P(redis->zobject),
- ZEND_STRL("errCode"),
- sw_redis_convert_err(redis->context->err));
- zend_update_property_string(
- swoole_redis_coro_ce, SW_Z8_OBJ_P(redis->zobject), ZEND_STRL("errMsg"), redis->context->errstr);
- }
- break;
-
- case REDIS_REPLY_STRING:
- if (redis->serialize) {
- char *reserve_str = reply->str;
- php_unserialize_data_t s_ht;
- PHP_VAR_UNSERIALIZE_INIT(s_ht);
- if (!php_var_unserialize(return_value,
- (const unsigned char **) &reply->str,
- (const unsigned char *) reply->str + reply->len,
- &s_ht)) {
- ZVAL_STRINGL(return_value, reply->str, reply->len);
- }
- PHP_VAR_UNSERIALIZE_DESTROY(s_ht);
- reply->str = reserve_str;
- } else {
- ZVAL_STRINGL(return_value, reply->str, reply->len);
- }
- break;
-
- case REDIS_REPLY_ARRAY:
- array_init(return_value);
- for (j = 0; j < (int) reply->elements; j++) {
- swoole_redis_coro_parse_result(redis, val, reply->element[j]);
- (void) add_next_index_zval(return_value, val);
- }
- break;
-
- case REDIS_REPLY_NIL:
- default:
- ZVAL_NULL(return_value);
- return;
- }
-}
diff --git a/ext-src/swoole_redis_server.cc b/ext-src/swoole_redis_server.cc
index edb8be271e9..bb427cda020 100644
--- a/ext-src/swoole_redis_server.cc
+++ b/ext-src/swoole_redis_server.cc
@@ -35,7 +35,7 @@ namespace Redis = swoole::redis;
zend_class_entry *swoole_redis_server_ce;
zend_object_handlers swoole_redis_server_handlers;
-static std::unordered_map redis_handlers;
+static SW_THREAD_LOCAL std::unordered_map redis_handlers;
SW_EXTERN_C_BEGIN
static PHP_METHOD(swoole_redis_server, setHandler);
diff --git a/ext-src/swoole_runtime.cc b/ext-src/swoole_runtime.cc
index cbc6e7657b7..e0bb4bda177 100644
--- a/ext-src/swoole_runtime.cc
+++ b/ext-src/swoole_runtime.cc
@@ -110,9 +110,6 @@ struct NetStream {
bool blocking;
};
-static bool runtime_hook_init = false;
-static int runtime_hook_flags = 0;
-
static struct {
php_stream_transport_factory tcp;
php_stream_transport_factory udp;
@@ -172,8 +169,11 @@ static zend_internal_arg_info *get_arginfo(const char *name, size_t l_name) {
#define SW_HOOK_LIBRARY_FE(name, arg_info) \
ZEND_RAW_FENTRY("swoole_hook_" #name, PHP_FN(swoole_user_func_handler), arg_info, 0)
-static zend_array *tmp_function_table = nullptr;
-static std::unordered_map child_class_entries;
+static bool runtime_hook_init = false;
+static int runtime_hook_flags = 0;
+static SW_THREAD_LOCAL zend_array *tmp_function_table = nullptr;
+static SW_THREAD_LOCAL std::unordered_map child_class_entries;
+static std::unordered_map ori_func_handlers;
SW_EXTERN_C_BEGIN
#include "ext/standard/file.h"
@@ -236,6 +236,13 @@ void php_swoole_runtime_rinit() {
}
void php_swoole_runtime_rshutdown() {
+#ifdef SW_THREAD
+ if (tsrm_is_main_thread()) {
+ PHPCoroutine::disable_hook();
+ ori_func_handlers.clear();
+ }
+#endif
+
void *ptr;
ZEND_HASH_FOREACH_PTR(tmp_function_table, ptr) {
real_func *rf = reinterpret_cast(ptr);
@@ -1169,6 +1176,12 @@ void PHPCoroutine::enable_unsafe_function() {
}
bool PHPCoroutine::enable_hook(uint32_t flags) {
+#ifdef SW_THREAD
+ if (!tsrm_is_main_thread()) {
+ swoole_set_last_error(SW_ERROR_OPERATION_NOT_SUPPORT);
+ return false;
+ }
+#endif
if (swoole_isset_hook((enum swGlobalHookType) PHP_SWOOLE_HOOK_BEFORE_ENABLE_HOOK)) {
swoole_call_hook((enum swGlobalHookType) PHP_SWOOLE_HOOK_BEFORE_ENABLE_HOOK, &flags);
}
@@ -1588,6 +1601,13 @@ static PHP_METHOD(swoole_runtime, enableCoroutine) {
}
}
+#ifdef SW_THREAD
+ if (runtime_hook_init && flags == 0) {
+ swoole_set_last_error(SW_ERROR_OPERATION_NOT_SUPPORT);
+ RETURN_FALSE;
+ }
+#endif
+
PHPCoroutine::set_hook_flags(flags);
RETURN_BOOL(PHPCoroutine::enable_hook(flags));
}
@@ -1611,6 +1631,15 @@ static PHP_METHOD(swoole_runtime, setHookFlags) {
Z_PARAM_LONG(flags)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
+#ifdef SW_THREAD
+ // In a multi-threaded environment, disabling the hook is prohibited.
+ // It can only be enabled once in the main thread.
+ if (runtime_hook_init && flags == 0) {
+ swoole_set_last_error(SW_ERROR_OPERATION_NOT_SUPPORT);
+ RETURN_FALSE;
+ }
+#endif
+
PHPCoroutine::set_hook_flags(flags);
RETURN_BOOL(PHPCoroutine::enable_hook(flags));
}
@@ -1946,6 +1975,7 @@ static void hook_func(const char *name, size_t l_name, zif_handler handler, zend
return;
}
+ auto fn_str = zf->common.function_name;
rf = (real_func *) emalloc(sizeof(real_func));
sw_memset_zero(rf, sizeof(*rf));
rf->function = zf;
@@ -1956,12 +1986,14 @@ static void hook_func(const char *name, size_t l_name, zif_handler handler, zend
zf->internal_function.arg_info = arg_info;
}
+ ori_func_handlers[std::string(fn_str->val, fn_str->len)] = rf->ori_handler;
+
if (use_php_func) {
char func[128];
memcpy(func, ZEND_STRL("swoole_"));
- memcpy(func + 7, zf->common.function_name->val, zf->common.function_name->len);
+ memcpy(func + 7, fn_str->val, fn_str->len);
- ZVAL_STRINGL(&rf->name, func, zf->common.function_name->len + 7);
+ ZVAL_STRINGL(&rf->name, func, fn_str->len + 7);
char *func_name;
zend_fcall_info_cache *func_cache = (zend_fcall_info_cache *) emalloc(sizeof(zend_fcall_info_cache));
@@ -1973,7 +2005,7 @@ static void hook_func(const char *name, size_t l_name, zif_handler handler, zend
rf->fci_cache = func_cache;
}
- zend_hash_add_ptr(tmp_function_table, zf->common.function_name, rf);
+ zend_hash_add_ptr(tmp_function_table, fn_str, rf);
}
static void unhook_func(const char *name, size_t l_name) {
@@ -2006,6 +2038,14 @@ php_stream *php_swoole_create_stream_from_socket(php_socket_t _fd, int domain, i
return stream;
}
+php_stream *php_swoole_create_stream_from_pipe(int fd, const char *mode, const char *persistent_id STREAMS_DC) {
+#if PHP_VERSION_ID >= 80200
+ return _sw_php_stream_fopen_from_fd(fd, mode, persistent_id, false STREAMS_CC);
+#else
+ return _sw_php_stream_fopen_from_fd(fd, mode, persistent_id STREAMS_CC);
+#endif
+}
+
php_stream_ops *php_swoole_get_ori_php_stream_stdio_ops() {
return &ori_php_stream_stdio_ops;
}
@@ -2043,16 +2083,32 @@ static PHP_FUNCTION(swoole_stream_socket_pair) {
}
static PHP_FUNCTION(swoole_user_func_handler) {
+ auto fn_str = execute_data->func->common.function_name;
+ if (!swoole_coroutine_is_in()) {
+ auto ori_handler = ori_func_handlers[std::string(fn_str->val, fn_str->len)];
+ ori_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+ return;
+ }
+
+ real_func *rf = (real_func *) zend_hash_find_ptr(tmp_function_table, fn_str);
+ if (!rf) {
+#ifdef SW_THREAD
+ hook_func(fn_str->val, fn_str->len);
+ rf = (real_func *) zend_hash_find_ptr(tmp_function_table, fn_str);
+#else
+ zend_throw_exception_ex(swoole_exception_ce, SW_ERROR_UNDEFINED_BEHAVIOR, "%s func not exists", fn_str->val);
+ return;
+#endif
+ }
+
zend_fcall_info fci;
fci.size = sizeof(fci);
fci.object = nullptr;
- ZVAL_UNDEF(&fci.function_name);
fci.retval = return_value;
fci.param_count = ZEND_NUM_ARGS();
fci.params = ZEND_CALL_ARG(execute_data, 1);
fci.named_params = NULL;
-
- real_func *rf = (real_func *) zend_hash_find_ptr(tmp_function_table, execute_data->func->common.function_name);
+ ZVAL_UNDEF(&fci.function_name);
zend_call_function(&fci, rf->fci_cache);
}
diff --git a/ext-src/swoole_server.cc b/ext-src/swoole_server.cc
index 879a6ac1793..62b75c7c38a 100644
--- a/ext-src/swoole_server.cc
+++ b/ext-src/swoole_server.cc
@@ -17,6 +17,7 @@
#include "php_swoole_server.h"
#include "php_swoole_http_server.h"
#include "php_swoole_process.h"
+#include "php_swoole_thread.h"
#include "php_swoole_call_stack.h"
#include "swoole_msg_queue.h"
@@ -98,7 +99,7 @@ void php_swoole_server_rshutdown() {
Server *serv = sw_server();
serv->drain_worker_pipe();
- if (serv->is_started() && !serv->is_user_worker()) {
+ if (serv->is_started() && serv->is_running() && !serv->is_user_worker()) {
if (php_swoole_is_fatal_error()) {
swoole_error_log(SW_LOG_ERROR,
SW_ERROR_PHP_FATAL_ERROR,
@@ -137,6 +138,12 @@ static zend_object_handlers swoole_server_status_info_handlers;
static zend_class_entry *swoole_server_task_result_ce;
static zend_object_handlers swoole_server_task_result_handlers;
+static SW_THREAD_LOCAL zval swoole_server_instance;
+#ifdef SW_THREAD
+static SW_THREAD_LOCAL WorkerFn worker_thread_fn;
+static SW_THREAD_LOCAL std::vector swoole_server_port_properties;
+#endif
+
static sw_inline ServerObject *server_fetch_object(zend_object *obj) {
return (ServerObject *) ((char *) obj - swoole_server_handlers.offset);
}
@@ -153,16 +160,35 @@ Server *php_swoole_server_get_and_check_server(zval *zobject) {
return serv;
}
-zval *php_swoole_server_get_zval_object(Server *serv) {
- return (zval *) serv->private_data_2;
+zval *php_swoole_server_zval_ptr(Server *serv) {
+ return &swoole_server_instance;
+}
+
+ServerPortProperty *php_swoole_server_get_port_property(ListenPort *port) {
+#ifdef SW_THREAD
+ return swoole_server_port_properties.at(port->socket->get_fd());
+#else
+ return (ServerPortProperty *) port->ptr;
+#endif
+}
+
+void php_swoole_server_set_port_property(ListenPort *port, ServerPortProperty *property) {
+#ifdef SW_THREAD
+ if (swoole_server_port_properties.size() < (size_t) port->socket->get_fd() + 1) {
+ swoole_server_port_properties.resize((size_t) port->socket->get_fd() + 1);
+ }
+ swoole_server_port_properties[port->socket->get_fd()] = property;
+#else
+ port->ptr = property;
+#endif
}
ServerObject *php_swoole_server_get_zend_object(Server *serv) {
- return server_fetch_object(Z_OBJ_P((zval *) serv->private_data_2));
+ return server_fetch_object(Z_OBJ_P(php_swoole_server_zval_ptr(serv)));
}
bool php_swoole_server_isset_callback(Server *serv, ListenPort *port, int event_type) {
- ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->private_data_2));
+ ServerObject *server_object = server_fetch_object(Z_OBJ_P(php_swoole_server_zval_ptr(serv)));
return server_object->isset_callback(port, event_type);
}
@@ -180,9 +206,6 @@ static void server_free_object(zend_object *object) {
sw_zend_fci_cache_discard((zend_fcall_info_cache *) serv->private_data_3);
efree(serv->private_data_3);
}
- if (serv->private_data_2) {
- efree(serv->private_data_2);
- }
for (int i = 0; i < PHP_SWOOLE_SERVER_CALLBACK_NUM; i++) {
zend_fcall_info_cache *fci_cache = property->callbacks[i];
if (fci_cache) {
@@ -421,7 +444,7 @@ static zend_function_entry swoole_server_methods[] = {
PHP_ME(swoole_server, getSocket, arginfo_class_Swoole_Server_getSocket, ZEND_ACC_PUBLIC)
#endif
PHP_ME(swoole_server, bind, arginfo_class_Swoole_Server_bind, ZEND_ACC_PUBLIC)
- {nullptr, nullptr, nullptr}
+ PHP_FE_END
};
static const zend_function_entry swoole_connection_iterator_methods[] =
@@ -553,13 +576,18 @@ void php_swoole_server_minit(int module_number) {
zend_declare_property_long(swoole_server_ce, ZEND_STRL("worker_pid"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("stats_timer"), ZEND_ACC_PUBLIC);
zend_declare_property_null(swoole_server_ce, ZEND_STRL("admin_server"), ZEND_ACC_PUBLIC);
+#ifdef SW_THREAD
+ zend_declare_property_string(swoole_server_ce, ZEND_STRL("bootstrap"), "", ZEND_ACC_PUBLIC);
+#endif
/**
* mode type
*/
SW_REGISTER_LONG_CONSTANT("SWOOLE_BASE", swoole::Server::MODE_BASE);
SW_REGISTER_LONG_CONSTANT("SWOOLE_PROCESS", swoole::Server::MODE_PROCESS);
-
+#ifdef SW_THREAD
+ SW_REGISTER_LONG_CONSTANT("SWOOLE_THREAD", swoole::Server::MODE_THREAD);
+#endif
/**
* task ipc mode
*/
@@ -605,17 +633,16 @@ void php_swoole_server_minit(int module_number) {
zend_fcall_info_cache *php_swoole_server_get_fci_cache(Server *serv, int server_fd, int event_type) {
ListenPort *port = serv->get_port_by_server_fd(server_fd);
- ServerPortProperty *property;
+ ServerPortProperty *property = php_swoole_server_get_port_property(port);
zend_fcall_info_cache *fci_cache;
- ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->private_data_2));
if (sw_unlikely(!port)) {
return nullptr;
}
- if ((property = (ServerPortProperty *) port->ptr) && (fci_cache = property->caches[event_type])) {
+ if (property && (fci_cache = property->caches[event_type])) {
return fci_cache;
} else {
- return server_object->property->primary_port->caches[event_type];
+ return php_swoole_server_get_port_property(serv->get_primary_port())->caches[event_type];
}
}
@@ -674,7 +701,7 @@ void php_swoole_get_recv_data(Server *serv, zval *zdata, RecvData *req) {
} else {
if (req->info.flags & SW_EVENT_DATA_OBJ_PTR) {
zend::assign_zend_string_by_val(zdata, (char *) data, length);
- serv->message_bus.move_packet();
+ serv->get_worker_message_bus()->move_packet();
} else if (req->info.flags & SW_EVENT_DATA_POP_PTR) {
String *recv_buffer = serv->get_recv_buffer(serv->get_connection_by_session_id(req->info.fd)->socket);
zend::assign_zend_string_by_val(zdata, recv_buffer->pop(serv->recv_buffer_size), length);
@@ -716,7 +743,7 @@ static bool php_swoole_server_task_unpack(zval *zresult, EventData *task_result)
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
if (!unserialized) {
swoole_warning("unserialize() failed, Error at offset " ZEND_LONG_FMT " of %zd bytes",
- (zend_long)((char *) p - packet.data),
+ (zend_long) ((char *) p - packet.data),
l);
return false;
}
@@ -747,7 +774,7 @@ static zval *php_swoole_server_add_port(ServerObject *server_object, ListenPort
property->port = port;
/* linked */
- port->ptr = property;
+ php_swoole_server_set_port_property(port, property);
zend_update_property_string(swoole_server_port_ce, SW_Z8_OBJ_P(zport), ZEND_STRL("host"), port->get_host());
zend_update_property_long(swoole_server_port_ce, SW_Z8_OBJ_P(zport), ZEND_STRL("port"), port->get_port());
@@ -756,7 +783,7 @@ static zval *php_swoole_server_add_port(ServerObject *server_object, ListenPort
zend_update_property_bool(swoole_server_port_ce, SW_Z8_OBJ_P(zport), ZEND_STRL("ssl"), port->ssl);
do {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
zval *zports = sw_zend_read_and_convert_property_array(Z_OBJCE_P(zserv), zserv, ZEND_STRL("ports"), 0);
(void) add_next_index_zval(zports, zport);
} while (0);
@@ -786,7 +813,7 @@ void ServerObject::on_before_start() {
return;
}
- zval *zobject = get_object();
+ zval *zobject = php_swoole_server_zval_ptr(serv);
auto primary_port = serv->get_primary_port();
#ifdef SW_LOG_TRACE_OPEN
@@ -810,7 +837,7 @@ void ServerObject::on_before_start() {
serv->message_bus.set_allocator(sw_zend_string_allocator());
- if (serv->is_base_mode()) {
+ if (serv->is_base_mode() || serv->is_thread_mode()) {
serv->recv_buffer_allocator = sw_zend_string_allocator();
}
@@ -1026,9 +1053,9 @@ static int php_swoole_server_task_finish(Server *serv, zval *zdata, EventData *c
}
static void php_swoole_server_onPipeMessage(Server *serv, EventData *req) {
- ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->private_data_2));
+ ServerObject *server_object = server_fetch_object(Z_OBJ_P(php_swoole_server_zval_ptr(serv)));
zend_fcall_info_cache *fci_cache = server_object->property->callbacks[SW_SERVER_CB_onPipeMessage];
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
zend::Variable zresult;
if (UNEXPECTED(!php_swoole_server_task_unpack(zresult.ptr(), req))) {
@@ -1081,7 +1108,7 @@ int php_swoole_server_onReceive(Server *serv, RecvData *req) {
auto fci_cache = php_swoole_server_get_fci_cache(serv, req->info.server_fd, SW_SERVER_CB_onReceive);
if (fci_cache) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
zval args[4];
int argc;
@@ -1123,7 +1150,7 @@ int php_swoole_server_onReceive(Server *serv, RecvData *req) {
}
int php_swoole_server_onPacket(Server *serv, RecvData *req) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
zval args[3];
int argc;
@@ -1228,7 +1255,7 @@ static sw_inline void php_swoole_create_task_object(zval *ztask, Server *serv, E
static int php_swoole_server_onTask(Server *serv, EventData *req) {
sw_atomic_fetch_sub(&serv->gs->tasking_num, 1);
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend::Variable zresult;
@@ -1273,7 +1300,7 @@ static int php_swoole_server_onTask(Server *serv, EventData *req) {
}
static int php_swoole_server_onFinish(Server *serv, EventData *req) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
zend::Variable zresult;
@@ -1374,7 +1401,7 @@ static int php_swoole_server_onFinish(Server *serv, EventData *req) {
static void php_swoole_server_onStart(Server *serv) {
serv->lock();
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
auto fci_cache = server_object->property->callbacks[SW_SERVER_CB_onStart];
@@ -1392,7 +1419,7 @@ static void php_swoole_server_onStart(Server *serv) {
}
static void php_swoole_server_onManagerStart(Server *serv) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
auto fci_cache = server_object->property->callbacks[SW_SERVER_CB_onManagerStart];
@@ -1409,7 +1436,7 @@ static void php_swoole_server_onManagerStart(Server *serv) {
}
static void php_swoole_server_onManagerStop(Server *serv) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
auto fci_cache = server_object->property->callbacks[SW_SERVER_CB_onManagerStop];
@@ -1424,7 +1451,7 @@ static void php_swoole_server_onManagerStop(Server *serv) {
static void php_swoole_server_onBeforeShutdown(Server *serv) {
serv->lock();
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
auto fci_cache = server_object->property->callbacks[SW_SERVER_CB_onBeforeShutdown];
@@ -1440,7 +1467,7 @@ static void php_swoole_server_onBeforeShutdown(Server *serv) {
static void php_swoole_server_onShutdown(Server *serv) {
serv->lock();
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
auto fci_cache = server_object->property->callbacks[SW_SERVER_CB_onShutdown];
@@ -1455,7 +1482,7 @@ static void php_swoole_server_onShutdown(Server *serv) {
}
static void php_swoole_server_onWorkerStart(Server *serv, Worker *worker) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
auto fci_cache = server_object->property->callbacks[SW_SERVER_CB_onWorkerStart];
@@ -1469,6 +1496,8 @@ static void php_swoole_server_onWorkerStart(Server *serv, Worker *worker) {
PHPCoroutine::disable_hook();
}
+ serv->get_worker_message_bus()->set_allocator(sw_zend_string_allocator());
+
zval args[2];
args[0] = *zserv;
ZVAL_LONG(&args[1], worker->id);
@@ -1483,7 +1512,7 @@ static void php_swoole_server_onWorkerStart(Server *serv, Worker *worker) {
}
static void php_swoole_server_onBeforeReload(Server *serv) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
auto fci_cache = server_object->property->callbacks[SW_SERVER_CB_onBeforeReload];
@@ -1497,7 +1526,7 @@ static void php_swoole_server_onBeforeReload(Server *serv) {
}
static void php_swoole_server_onAfterReload(Server *serv) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
auto fci_cache = server_object->property->callbacks[SW_SERVER_CB_onAfterReload];
@@ -1516,7 +1545,7 @@ static void php_swoole_server_onWorkerStop(Server *serv, Worker *worker) {
}
SwooleWG.shutdown = true;
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
auto fci_cache = server_object->property->callbacks[SW_SERVER_CB_onWorkerStop];
zval args[2];
@@ -1533,7 +1562,7 @@ static void php_swoole_server_onWorkerStop(Server *serv, Worker *worker) {
}
static void php_swoole_server_onWorkerExit(Server *serv, Worker *worker) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
auto fci_cache = server_object->property->callbacks[SW_SERVER_CB_onWorkerExit];
@@ -1552,9 +1581,9 @@ static void php_swoole_server_onWorkerExit(Server *serv, Worker *worker) {
static void php_swoole_server_onUserWorkerStart(Server *serv, Worker *worker) {
zval *object = (zval *) worker->ptr;
- zend_update_property_long(swoole_process_ce, SW_Z8_OBJ_P(object), ZEND_STRL("id"), SwooleG.process_id);
+ zend_update_property_long(swoole_process_ce, SW_Z8_OBJ_P(object), ZEND_STRL("id"), worker->id);
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("master_pid"), serv->gs->master_pid);
zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("manager_pid"), serv->gs->manager_pid);
@@ -1562,7 +1591,7 @@ static void php_swoole_server_onUserWorkerStart(Server *serv, Worker *worker) {
}
static void php_swoole_server_onWorkerError(Server *serv, Worker *worker, const ExitStatus &exit_status) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
auto fci_cache = server_object->property->callbacks[SW_SERVER_CB_onWorkerError];
@@ -1611,7 +1640,7 @@ void php_swoole_server_onConnect(Server *serv, DataHead *info) {
return;
}
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
zval args[3];
int argc;
args[0] = *zserv;
@@ -1641,7 +1670,7 @@ void php_swoole_server_onConnect(Server *serv, DataHead *info) {
}
void php_swoole_server_onClose(Server *serv, DataHead *info) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
SessionId session_id = info->fd;
@@ -1673,7 +1702,7 @@ void php_swoole_server_onClose(Server *serv, DataHead *info) {
}
}
if (fci_cache) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
zval args[3];
int argc;
args[0] = *zserv;
@@ -1708,7 +1737,7 @@ void php_swoole_server_onClose(Server *serv, DataHead *info) {
}
void php_swoole_server_onBufferFull(Server *serv, DataHead *info) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
auto fci_cache = php_swoole_server_get_fci_cache(serv, info->server_fd, SW_SERVER_CB_onBufferFull);
if (fci_cache) {
@@ -1724,7 +1753,7 @@ void php_swoole_server_onBufferFull(Server *serv, DataHead *info) {
}
void php_swoole_server_send_yield(Server *serv, SessionId session_id, zval *zdata, zval *return_value) {
- ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->private_data_2));
+ ServerObject *server_object = server_fetch_object(Z_OBJ_P(php_swoole_server_zval_ptr(serv)));
Coroutine *co = Coroutine::get_current_safe();
char *data;
size_t length = php_swoole_get_send_data(zdata, &data);
@@ -1766,17 +1795,15 @@ static int php_swoole_server_dispatch_func(Server *serv, Connection *conn, SendD
zval retval;
zend_long worker_id = -1;
- *zserv = *((zval *) serv->private_data_2);
+ *zserv = *(php_swoole_server_zval_ptr(serv));
ZVAL_LONG(zfd, conn ? conn->session_id : data->info.fd);
- ZVAL_LONG(ztype, (zend_long)(data ? data->info.type : (int) SW_SERVER_EVENT_CLOSE));
+ ZVAL_LONG(ztype, (zend_long) (data ? data->info.type : (int) SW_SERVER_EVENT_CLOSE));
if (data && sw_zend_function_max_num_args(fci_cache->function_handler) > 3) {
// TODO: reduce memory copy
zdata = &args[3];
ZVAL_STRINGL(zdata, data->data, data->info.len > SW_IPC_BUFFER_SIZE ? SW_IPC_BUFFER_SIZE : data->info.len);
}
- HOOK_PHP_CALL_STACK(
- auto call_result = sw_zend_call_function_ex(nullptr, fci_cache, zdata ? 4 : 3, args, &retval);
- );
+ HOOK_PHP_CALL_STACK(auto call_result = sw_zend_call_function_ex(nullptr, fci_cache, zdata ? 4 : 3, args, &retval););
if (UNEXPECTED(call_result != SUCCESS)) {
php_swoole_error(E_WARNING, "%s->onDispatch handler error", SW_Z_OBJCE_NAME_VAL_P(zserv));
} else if (!ZVAL_IS_NULL(&retval)) {
@@ -1802,7 +1829,7 @@ static int php_swoole_server_dispatch_func(Server *serv, Connection *conn, SendD
}
void php_swoole_server_onBufferEmpty(Server *serv, DataHead *info) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
if (serv->send_yield) {
@@ -1833,6 +1860,38 @@ void php_swoole_server_onBufferEmpty(Server *serv, DataHead *info) {
}
}
+static void server_ctor(zval *zserv, Server *serv) {
+ ServerObject *server_object = server_fetch_object(Z_OBJ_P(zserv));
+ *php_swoole_server_zval_ptr(serv) = *zserv;
+ server_set_ptr(zserv, serv);
+
+ /* primary port */
+ for (auto ls : serv->ports) {
+ php_swoole_server_add_port(server_object, ls);
+ }
+
+ /* iterator */
+ do {
+ zval connection_iterator;
+ object_init_ex(&connection_iterator, swoole_connection_iterator_ce);
+
+ ConnectionIterator *iterator = php_swoole_connection_iterator_get_ptr(&connection_iterator);
+ iterator->serv = serv;
+
+ zend_update_property(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("connections"), &connection_iterator);
+ zval_ptr_dtor(&connection_iterator);
+ } while (0);
+
+ /* info */
+ auto port = serv->get_primary_port();
+ zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("mode"), serv->get_mode());
+ zend_update_property_stringl(
+ swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("host"), port->host.c_str(), port->host.length());
+ zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("port"), port->get_port());
+ zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("type"), port->get_type());
+ zend_update_property_bool(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("ssl"), port->ssl);
+}
+
static PHP_METHOD(swoole_server, __construct) {
ServerObject *server_object = server_fetch_object(Z_OBJ_P(ZEND_THIS));
Server *serv = server_object->serv;
@@ -1848,19 +1907,12 @@ static PHP_METHOD(swoole_server, __construct) {
zend_long serv_port = 0;
zend_long serv_mode = Server::MODE_BASE;
- // only cli env
if (!SWOOLE_G(cli)) {
zend_throw_exception_ex(
swoole_exception_ce, -1, "%s can only be used in CLI mode", SW_Z_OBJCE_NAME_VAL_P(zserv));
RETURN_FALSE;
}
- if (sw_server() != nullptr) {
- zend_throw_exception_ex(
- swoole_exception_ce, -3, "server is running. unable to create %s", SW_Z_OBJCE_NAME_VAL_P(zserv));
- RETURN_FALSE;
- }
-
ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1, 4)
Z_PARAM_STRING(host, host_len)
Z_PARAM_OPTIONAL
@@ -1869,67 +1921,55 @@ static PHP_METHOD(swoole_server, __construct) {
Z_PARAM_LONG(sock_type)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
- if (serv_mode != Server::MODE_BASE && serv_mode != Server::MODE_PROCESS) {
+ if (serv_mode != Server::MODE_BASE && serv_mode != Server::MODE_PROCESS
+#ifdef SW_THREAD
+ && serv_mode != Server::MODE_THREAD
+#endif
+ ) {
zend_throw_error(NULL, "invalid $mode parameters %d", (int) serv_mode);
RETURN_FALSE;
}
+#ifdef SW_THREAD
+ if (sw_server() && sw_server()->is_worker_thread()) {
+ server_ctor(ZEND_THIS, sw_server());
+ return;
+ }
+#else
+ if (sw_server() != nullptr) {
+ zend_throw_exception_ex(
+ swoole_exception_ce, -3, "server is running. unable to create %s", SW_Z_OBJCE_NAME_VAL_P(zserv));
+ RETURN_FALSE;
+ }
+#endif
+
serv = new Server((enum Server::Mode) serv_mode);
- serv->private_data_2 = sw_zval_dup(zserv);
- server_set_ptr(zserv, serv);
if (serv_mode == Server::MODE_BASE) {
serv->reactor_num = 1;
serv->worker_num = 1;
}
- /* primary port */
- do {
- if (serv_port == 0 && strcasecmp(host, "SYSTEMD") == 0) {
- if (serv->add_systemd_socket() <= 0) {
- zend_throw_error(NULL, "failed to add systemd socket");
- RETURN_FALSE;
- }
- } else {
- ListenPort *port = serv->add_port((enum swSocketType) sock_type, host, serv_port);
- if (!port) {
- zend_throw_exception_ex(swoole_exception_ce,
- swoole_get_last_error(),
- "failed to listen server port[%s:" ZEND_LONG_FMT "], Error: %s[%d]",
- host,
- serv_port,
- swoole_strerror(swoole_get_last_error()),
- swoole_get_last_error());
- RETURN_FALSE;
- }
+ if (serv_port == 0 && strcasecmp(host, "SYSTEMD") == 0) {
+ if (serv->add_systemd_socket() <= 0) {
+ zend_throw_error(NULL, "failed to add systemd socket");
+ RETURN_FALSE;
}
-
- for (auto ls : serv->ports) {
- php_swoole_server_add_port(server_object, ls);
+ } else {
+ ListenPort *port = serv->add_port((enum swSocketType) sock_type, host, serv_port);
+ if (!port) {
+ zend_throw_exception_ex(swoole_exception_ce,
+ swoole_get_last_error(),
+ "failed to listen server port[%s:" ZEND_LONG_FMT "], Error: %s[%d]",
+ host,
+ serv_port,
+ swoole_strerror(swoole_get_last_error()),
+ swoole_get_last_error());
+ RETURN_FALSE;
}
+ }
- server_object->property->primary_port = (ServerPortProperty *) serv->get_primary_port()->ptr;
- } while (0);
-
- /* iterator */
- do {
- zval connection_iterator;
- object_init_ex(&connection_iterator, swoole_connection_iterator_ce);
-
- ConnectionIterator *iterator = php_swoole_connection_iterator_get_ptr(&connection_iterator);
- iterator->serv = serv;
-
- zend_update_property(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("connections"), &connection_iterator);
- zval_ptr_dtor(&connection_iterator);
- } while (0);
-
- /* info */
- auto port = serv->get_primary_port();
- zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("mode"), serv_mode);
- zend_update_property_stringl(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("host"), host, host_len);
- zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("port"), port->get_port());
- zend_update_property_long(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("type"), port->get_type());
- zend_update_property_bool(swoole_server_ce, SW_Z8_OBJ_P(zserv), ZEND_STRL("ssl"), port->ssl);
+ server_ctor(zserv, serv);
}
static PHP_METHOD(swoole_server, __destruct) {}
@@ -1937,6 +1977,10 @@ static PHP_METHOD(swoole_server, __destruct) {}
static PHP_METHOD(swoole_server, set) {
ServerObject *server_object = server_fetch_object(Z_OBJ_P(ZEND_THIS));
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
+ if (serv->is_worker_thread()) {
+ swoole_set_last_error(SW_ERROR_OPERATION_NOT_SUPPORT);
+ RETURN_FALSE;
+ }
if (serv->is_started()) {
php_swoole_fatal_error(
E_WARNING, "server is running, unable to execute %s->set", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS));
@@ -2010,7 +2054,7 @@ static PHP_METHOD(swoole_server, set) {
if (php_swoole_array_get_value(vht, "enable_coroutine", ztmp)) {
serv->enable_coroutine = zval_is_true(ztmp);
} else {
- serv->enable_coroutine = SWOOLE_G(enable_coroutine);
+ serv->enable_coroutine = SwooleG.enable_coroutine;
}
if (php_swoole_array_get_value(vht, "send_timeout", ztmp)) {
serv->send_timeout = zval_get_double(ztmp);
@@ -2331,6 +2375,20 @@ static PHP_METHOD(swoole_server, set) {
zend_long v = zval_get_long(ztmp);
serv->message_queue_key = SW_MAX(0, SW_MIN(v, INT64_MAX));
}
+#ifdef SW_THREAD
+ // bootstrap
+ if (php_swoole_array_get_value(vht, "bootstrap", ztmp)) {
+ zend::object_set(ZEND_THIS, ZEND_STRL("bootstrap"), ztmp);
+ } else {
+ zend::object_set(ZEND_THIS, ZEND_STRL("bootstrap"), SG(request_info).path_translated);
+ }
+ // thread arguments
+ if (php_swoole_array_get_value(vht, "init_arguments", ztmp)) {
+ server_object->init_arguments = *ztmp;
+ } else {
+ ZVAL_NULL(&server_object->init_arguments);
+ }
+#endif
if (serv->task_enable_coroutine &&
(serv->task_ipc_mode == Server::TASK_IPC_MSGQUEUE || serv->task_ipc_mode == Server::TASK_IPC_PREEMPTIVE)) {
@@ -2349,7 +2407,7 @@ static PHP_METHOD(swoole_server, set) {
static PHP_METHOD(swoole_server, on) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
- if (serv->is_started()) {
+ if (!serv->is_worker_thread() && serv->is_started()) {
php_swoole_fatal_error(E_WARNING, "server is running, unable to register event callback function");
RETURN_FALSE;
}
@@ -2453,7 +2511,7 @@ extern Worker *php_swoole_process_get_and_check_worker(zval *zobject);
static PHP_METHOD(swoole_server, addProcess) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
- if (serv->is_started()) {
+ if (!serv->is_worker_thread() && serv->is_started()) {
php_swoole_fatal_error(E_WARNING, "server is running, can't add process");
RETURN_FALSE;
}
@@ -2524,7 +2582,7 @@ static PHP_METHOD(swoole_server, addCommand) {
}
Server::Command::Handler fn = [fci_cache](Server *serv, const std::string &msg) {
- zval *zserv = (zval *) serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(serv);
zval argv[2];
argv[0] = *zserv;
ZVAL_STRINGL(&argv[1], msg.c_str(), msg.length());
@@ -2556,6 +2614,13 @@ static PHP_METHOD(swoole_server, start) {
zval *zserv = ZEND_THIS;
Server *serv = php_swoole_server_get_and_check_server(zserv);
+#ifdef SW_THREAD
+ if (serv->is_worker_thread()) {
+ worker_thread_fn();
+ RETURN_TRUE;
+ }
+#endif
+
if (serv->is_started()) {
php_swoole_fatal_error(
E_WARNING, "server is running, unable to execute %s->start()", SW_Z_OBJCE_NAME_VAL_P(zserv));
@@ -2573,7 +2638,31 @@ static PHP_METHOD(swoole_server, start) {
RETURN_FALSE;
}
- ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->private_data_2));
+ ServerObject *server_object = server_fetch_object(Z_OBJ_P(php_swoole_server_zval_ptr(serv)));
+
+#ifdef SW_THREAD
+ zend_string *bootstrap = nullptr;
+ zend_string *thread_argv_serialized = nullptr;
+ zval thread_argv = {};
+
+ if (serv->is_thread_mode()) {
+ zval *_bootstrap = zend::object_get(ZEND_THIS, ZEND_STRL("bootstrap"));
+ bootstrap = zend_string_dup(Z_STR_P(_bootstrap), 1);
+
+ if (!ZVAL_IS_NULL(&server_object->init_arguments)) {
+ call_user_function(NULL, NULL, &server_object->init_arguments, &thread_argv, 0, NULL);
+ thread_argv_serialized = php_swoole_thread_serialize(&thread_argv);
+ }
+
+ serv->worker_thread_start = [bootstrap, thread_argv_serialized](const WorkerFn &fn) {
+ worker_thread_fn = fn;
+ zend_string *bootstrap_copy = zend_string_dup(bootstrap, 1);
+ zend_string *argv_copy = thread_argv_serialized ? zend_string_dup(thread_argv_serialized, 1) : nullptr;
+ php_swoole_thread_start(bootstrap_copy, argv_copy);
+ };
+ }
+#endif
+
server_object->register_callback();
server_object->on_before_start();
@@ -2581,6 +2670,16 @@ static PHP_METHOD(swoole_server, start) {
php_swoole_fatal_error(E_ERROR, "failed to start server. Error: %s", sw_error);
}
+#ifdef SW_THREAD
+ if (bootstrap) {
+ zend_string_release(bootstrap);
+ }
+ if (thread_argv_serialized) {
+ zend_string_release(thread_argv_serialized);
+ }
+ zval_ptr_dtor(&thread_argv);
+#endif
+
RETURN_TRUE;
}
@@ -2817,10 +2916,10 @@ static PHP_METHOD(swoole_server, stats) {
add_assoc_long_ex(return_value, ZEND_STRL("min_fd"), serv->gs->min_fd);
add_assoc_long_ex(return_value, ZEND_STRL("max_fd"), serv->gs->max_fd);
- if (SwooleWG.worker) {
- add_assoc_long_ex(return_value, ZEND_STRL("worker_request_count"), SwooleWG.worker->request_count);
- add_assoc_long_ex(return_value, ZEND_STRL("worker_response_count"), SwooleWG.worker->response_count);
- add_assoc_long_ex(return_value, ZEND_STRL("worker_dispatch_count"), SwooleWG.worker->dispatch_count);
+ if (sw_worker()) {
+ add_assoc_long_ex(return_value, ZEND_STRL("worker_request_count"), sw_worker()->request_count);
+ add_assoc_long_ex(return_value, ZEND_STRL("worker_response_count"), sw_worker()->response_count);
+ add_assoc_long_ex(return_value, ZEND_STRL("worker_dispatch_count"), sw_worker()->dispatch_count);
}
if (serv->task_ipc_mode > Server::TASK_IPC_UNIXSOCK && serv->gs->task_workers.queue) {
@@ -2938,7 +3037,7 @@ static PHP_METHOD(swoole_server, taskwait) {
// coroutine
if (swoole_coroutine_is_in()) {
- ServerObject *server_object = server_fetch_object(Z_OBJ_P((zval *) serv->private_data_2));
+ ServerObject *server_object = server_fetch_object(Z_OBJ_P(php_swoole_server_zval_ptr(serv)));
buf.info.ext_flags |= (SW_TASK_NONBLOCK | SW_TASK_COROUTINE);
TaskCo task_co{};
@@ -2963,9 +3062,9 @@ static PHP_METHOD(swoole_server, taskwait) {
}
uint64_t notify;
- EventData *task_result = &(serv->task_result[SwooleG.process_id]);
+ EventData *task_result = &(serv->task_result[swoole_get_process_id()]);
sw_memset_zero(task_result, sizeof(*task_result));
- Pipe *pipe = serv->task_notify_pipes.at(SwooleG.process_id).get();
+ Pipe *pipe = serv->task_notify_pipes.at(swoole_get_process_id()).get();
network::Socket *task_notify_socket = pipe->get_socket(false);
// clear history task
@@ -3045,10 +3144,10 @@ static PHP_METHOD(swoole_server, taskWaitMulti) {
int list_of_id[SW_MAX_CONCURRENT_TASK] = {};
uint64_t notify;
- EventData *task_result = &(serv->task_result[SwooleG.process_id]);
+ EventData *task_result = &(serv->task_result[swoole_get_process_id()]);
sw_memset_zero(task_result, sizeof(*task_result));
- Pipe *pipe = serv->task_notify_pipes.at(SwooleG.process_id).get();
- Worker *worker = serv->get_worker(SwooleG.process_id);
+ Pipe *pipe = serv->task_notify_pipes.at(swoole_get_process_id()).get();
+ Worker *worker = serv->get_worker(swoole_get_process_id());
File fp = swoole::make_tmpfile();
if (!fp.ready()) {
@@ -3366,7 +3465,7 @@ static PHP_METHOD(swoole_server, sendMessage) {
Z_PARAM_LONG(worker_id)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
- if ((serv->is_worker() || serv->is_task_worker()) && worker_id == SwooleG.process_id) {
+ if ((serv->is_worker() || serv->is_task_worker()) && worker_id == swoole_get_process_id()) {
php_swoole_fatal_error(E_WARNING, "can't send messages to self");
RETURN_FALSE;
}
@@ -3502,7 +3601,7 @@ static PHP_METHOD(swoole_server, getSocket) {
RETURN_FALSE;
}
- ListenPort *lp = serv->get_port(port);
+ const ListenPort *lp = serv->get_port(port);
php_socket *socket_object = php_swoole_convert_to_socket(lp->get_fd());
if (!socket_object) {
@@ -3721,7 +3820,7 @@ static PHP_METHOD(swoole_server, getWorkerId) {
if (!serv->is_worker() && !serv->is_task_worker()) {
RETURN_FALSE;
} else {
- RETURN_LONG(SwooleG.process_id);
+ RETURN_LONG(sw_worker()->id);
}
}
@@ -3739,7 +3838,7 @@ static PHP_METHOD(swoole_server, getWorkerStatus) {
Worker *worker;
if (worker_id == -1) {
- worker = SwooleWG.worker;
+ worker = sw_worker();
} else {
worker = serv->get_worker(worker_id);
}
@@ -3757,7 +3856,7 @@ static PHP_METHOD(swoole_server, getWorkerPid) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &worker_id) == FAILURE) {
RETURN_FALSE;
}
- Worker *worker = worker_id < 0 ? SwooleWG.worker : serv->get_worker(worker_id);
+ Worker *worker = worker_id < 0 ? sw_worker() : serv->get_worker(worker_id);
if (!worker) {
RETURN_FALSE;
}
@@ -3771,29 +3870,12 @@ static PHP_METHOD(swoole_server, getManagerPid) {
static PHP_METHOD(swoole_server, getMasterPid) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
- RETURN_LONG(serv->gs->master_pid);
+ RETURN_LONG(serv->get_master_pid());
}
static PHP_METHOD(swoole_server, shutdown) {
Server *serv = php_swoole_server_get_and_check_server(ZEND_THIS);
- if (sw_unlikely(!serv->is_started())) {
- php_swoole_fatal_error(E_WARNING, "server is not running");
- RETURN_FALSE;
- }
-
- pid_t pid;
- if (serv->is_base_mode()) {
- pid = serv->get_manager_pid() == 0 ? serv->get_master_pid() : serv->get_manager_pid();
- } else {
- pid = serv->get_master_pid();
- }
-
- if (swoole_kill(pid, SIGTERM) < 0) {
- php_swoole_sys_error(E_WARNING, "failed to shutdown, kill(%d, SIGTERM) failed", pid);
- RETURN_FALSE;
- } else {
- RETURN_TRUE;
- }
+ RETURN_BOOL(serv->shutdown());
}
static PHP_METHOD(swoole_server, stop) {
@@ -3804,7 +3886,7 @@ static PHP_METHOD(swoole_server, stop) {
}
zend_bool wait_reactor = 0;
- zend_long worker_id = SwooleG.process_id;
+ zend_long worker_id = sw_worker()->id;
ZEND_PARSE_PARAMETERS_START(0, 2)
Z_PARAM_OPTIONAL
@@ -3812,7 +3894,7 @@ static PHP_METHOD(swoole_server, stop) {
Z_PARAM_BOOL(wait_reactor)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
- if (worker_id == SwooleG.process_id && wait_reactor == 0) {
+ if (worker_id == sw_worker()->id && wait_reactor == 0) {
if (SwooleTG.reactor != nullptr) {
SwooleTG.reactor->defer(
[](void *data) {
@@ -3897,7 +3979,7 @@ static PHP_METHOD(swoole_connection_iterator, count) {
static PHP_METHOD(swoole_connection_iterator, offsetExists) {
ConnectionIterator *iterator = php_swoole_connection_iterator_get_and_check_ptr(ZEND_THIS);
- zval *zserv = (zval *) iterator->serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(iterator->serv);
zval *zfd;
zval retval;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zfd) == FAILURE) {
@@ -3909,7 +3991,7 @@ static PHP_METHOD(swoole_connection_iterator, offsetExists) {
static PHP_METHOD(swoole_connection_iterator, offsetGet) {
ConnectionIterator *iterator = php_swoole_connection_iterator_get_and_check_ptr(ZEND_THIS);
- zval *zserv = (zval *) iterator->serv->private_data_2;
+ zval *zserv = php_swoole_server_zval_ptr(iterator->serv);
zval *zfd;
zval retval;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zfd) == FAILURE) {
diff --git a/ext-src/swoole_server_port.cc b/ext-src/swoole_server_port.cc
index 2a3fb703148..28b0f51197e 100644
--- a/ext-src/swoole_server_port.cc
+++ b/ext-src/swoole_server_port.cc
@@ -154,7 +154,9 @@ const zend_function_entry swoole_server_port_methods[] =
void php_swoole_server_port_minit(int module_number) {
SW_INIT_CLASS_ENTRY(swoole_server_port, "Swoole\\Server\\Port", nullptr, swoole_server_port_methods);
+#ifndef SW_THREAD
SW_SET_CLASS_NOT_SERIALIZABLE(swoole_server_port);
+#endif
SW_SET_CLASS_CLONEABLE(swoole_server_port, sw_zend_class_clone_deny);
SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_server_port, sw_zend_class_unset_property_deny);
SW_SET_CLASS_CUSTOM_OBJECT(swoole_server_port,
@@ -199,9 +201,7 @@ static ssize_t php_swoole_server_length_func(const Protocol *protocol, network::
ssize_t ret = -1;
ZVAL_STRINGL(&zdata, pl->buf, pl->buf_size);
- HOOK_PHP_CALL_STACK(
- auto call_result = sw_zend_call_function_ex(nullptr, fci_cache, 1, &zdata, &retval);
- );
+ HOOK_PHP_CALL_STACK(auto call_result = sw_zend_call_function_ex(nullptr, fci_cache, 1, &zdata, &retval););
if (UNEXPECTED(call_result) != SUCCESS) {
php_swoole_fatal_error(E_WARNING, "length function handler error");
} else {
@@ -622,7 +622,7 @@ static PHP_METHOD(swoole_server_port, on) {
ServerPortProperty *property = php_swoole_server_port_get_and_check_property(ZEND_THIS);
Server *serv = property->serv;
- if (serv->is_started()) {
+ if (!serv->is_worker_thread() && serv->is_started()) {
php_swoole_fatal_error(E_WARNING, "can't register event callback function after server started");
RETURN_FALSE;
}
diff --git a/ext-src/swoole_socket_coro.cc b/ext-src/swoole_socket_coro.cc
index a78ece50e3d..82868a979ee 100644
--- a/ext-src/swoole_socket_coro.cc
+++ b/ext-src/swoole_socket_coro.cc
@@ -17,6 +17,8 @@
*/
#include "php_swoole_cxx.h"
+#include "php_swoole_thread.h"
+
#include "swoole_string.h"
#include "swoole_socket.h"
#include "swoole_util.h"
@@ -87,6 +89,9 @@ static PHP_METHOD(swoole_socket_coro, getsockname);
static PHP_METHOD(swoole_socket_coro, getpeername);
static PHP_METHOD(swoole_socket_coro, isClosed);
static PHP_METHOD(swoole_socket_coro, import);
+#ifdef SW_THREAD
+static PHP_METHOD(swoole_socket_coro, __wakeup);
+#endif
SW_EXTERN_C_END
// clang-format off
@@ -127,6 +132,9 @@ static const zend_function_entry swoole_socket_coro_methods[] =
PHP_ME(swoole_socket_coro, getsockname, arginfo_class_Swoole_Coroutine_Socket_getsockname, ZEND_ACC_PUBLIC)
PHP_ME(swoole_socket_coro, isClosed, arginfo_class_Swoole_Coroutine_Socket_isClosed, ZEND_ACC_PUBLIC)
PHP_ME(swoole_socket_coro, import, arginfo_class_Swoole_Coroutine_Socket_import, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+#ifdef SW_THREAD
+ PHP_ME(swoole_socket_coro, __wakeup, arginfo_class_Swoole_Coroutine_Socket___wakeup, ZEND_ACC_PUBLIC)
+#endif
PHP_FE_END
};
// clang-format on
@@ -712,16 +720,18 @@ static void socket_coro_register_constants(int module_number) {
void php_swoole_socket_coro_minit(int module_number) {
SW_INIT_CLASS_ENTRY(swoole_socket_coro, "Swoole\\Coroutine\\Socket", "Co\\Socket", swoole_socket_coro_methods);
+#ifndef SW_THREAD
SW_SET_CLASS_NOT_SERIALIZABLE(swoole_socket_coro);
+#endif
SW_SET_CLASS_CLONEABLE(swoole_socket_coro, sw_zend_class_clone_deny);
SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_socket_coro, sw_zend_class_unset_property_deny);
SW_SET_CLASS_CUSTOM_OBJECT(
swoole_socket_coro, socket_coro_create_object, socket_coro_free_object, SocketObject, std);
- zend_declare_property_long(swoole_socket_coro_ce, ZEND_STRL("fd"), -1, ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_socket_coro_ce, ZEND_STRL("domain"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_socket_coro_ce, ZEND_STRL("type"), 0, ZEND_ACC_PUBLIC);
- zend_declare_property_long(swoole_socket_coro_ce, ZEND_STRL("protocol"), 0, ZEND_ACC_PUBLIC);
+ zend_declare_property_long(swoole_socket_coro_ce, ZEND_STRL("fd"), -1, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY);
+ zend_declare_property_long(swoole_socket_coro_ce, ZEND_STRL("domain"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY);
+ zend_declare_property_long(swoole_socket_coro_ce, ZEND_STRL("type"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY);
+ zend_declare_property_long(swoole_socket_coro_ce, ZEND_STRL("protocol"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY);
zend_declare_property_long(swoole_socket_coro_ce, ZEND_STRL("errCode"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_string(swoole_socket_coro_ce, ZEND_STRL("errMsg"), "", ZEND_ACC_PUBLIC);
@@ -2167,20 +2177,20 @@ static PHP_METHOD(swoole_socket_coro, import) {
}
int sock_domain = AF_INET, sock_type = SOCK_STREAM;
- php_sockaddr_storage addr;
- socklen_t addr_len = sizeof(addr);
+ php_sockaddr_storage addr;
+ socklen_t addr_len = sizeof(addr);
#ifdef SO_DOMAIN
socklen_t sock_domain_len = sizeof(sock_domain);
if (getsockopt(socket_fd, SOL_SOCKET, SO_DOMAIN, &sock_domain, &sock_domain_len) == 0) {
} else
#endif
- if (getsockname(socket_fd, (struct sockaddr*)&addr, &addr_len) == 0) {
- sock_domain = addr.ss_family;
- } else {
+ if (getsockname(socket_fd, (struct sockaddr *) &addr, &addr_len) == 0) {
+ sock_domain = addr.ss_family;
+ } else {
php_swoole_sys_error(E_WARNING, "getsockname() failed");
RETURN_FALSE;
- }
+ }
#ifdef SO_TYPE
socklen_t sock_type_len = sizeof(sock_type);
@@ -2207,3 +2217,31 @@ static PHP_METHOD(swoole_socket_coro, import) {
RETURN_OBJ(object);
}
+
+#ifdef SW_THREAD
+static PHP_METHOD(swoole_socket_coro, __wakeup) {
+ zend_long sockfd = zend::object_get_long(ZEND_THIS, ZEND_STRL("fd"));
+ if (sockfd < 0) {
+ zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE);
+ return;
+ }
+
+ zend_long new_sockfd = dup(sockfd);
+ if (sockfd < 0) {
+ zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE);
+ return;
+ }
+
+ SocketObject *sock = (SocketObject *) socket_coro_fetch_object(Z_OBJ_P(ZEND_THIS));
+
+ zend_long domain = zend::object_get_long(ZEND_THIS, ZEND_STRL("domain"));
+ zend_long type = zend::object_get_long(ZEND_THIS, ZEND_STRL("type"));
+ zend_long protocol = zend::object_get_long(ZEND_THIS, ZEND_STRL("protocol"));
+
+ php_swoole_check_reactor();
+ sock->socket = new Socket((int) new_sockfd, (int) domain, (int) type, (int) protocol);
+ sock->socket->set_zero_copy(true);
+ sock->socket->set_buffer_allocator(sw_zend_string_allocator());
+ zend_update_property_long(swoole_socket_coro_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("fd"), sock->socket->get_fd());
+}
+#endif
diff --git a/ext-src/swoole_thread.cc b/ext-src/swoole_thread.cc
new file mode 100644
index 00000000000..0fb6cc50ee7
--- /dev/null
+++ b/ext-src/swoole_thread.cc
@@ -0,0 +1,510 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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"
+
+#ifdef SW_THREAD
+
+#include
+#include
+
+#include
+#include
+
+#include "swoole_lock.h"
+
+BEGIN_EXTERN_C()
+#include "stubs/php_swoole_thread_arginfo.h"
+END_EXTERN_C()
+
+zend_class_entry *swoole_thread_ce;
+static zend_object_handlers swoole_thread_handlers;
+
+zend_class_entry *swoole_thread_stream_ce;
+static zend_object_handlers swoole_thread_stream_handlers;
+
+static struct {
+ char *path_translated;
+ zend_string *argv_serialized;
+ int argc;
+} request_info;
+
+TSRMLS_CACHE_DEFINE();
+
+typedef std::thread Thread;
+
+struct ThreadObject {
+ Thread *thread;
+ zend_object std;
+};
+
+static void php_swoole_thread_join(zend_object *object);
+static void php_swoole_thread_create(INTERNAL_FUNCTION_PARAMETERS, zval *zobject);
+static int php_swoole_thread_stream_fileno(zval *zstream);
+static bool php_swoole_thread_stream_restore(zend_long sockfd, zval *return_value);
+
+static thread_local zval thread_argv;
+static zend_long thread_resource_id = 0;
+static std::unordered_map thread_resources;
+
+ThreadResourceId php_swoole_thread_resource_insert(ThreadResource *res) {
+ std::unique_lock _lock(sw_thread_lock);
+ zend_long resource_id = ++thread_resource_id;
+ thread_resources[resource_id] = res;
+ return resource_id;
+}
+
+ThreadResource *php_swoole_thread_resource_fetch(ThreadResourceId resource_id) {
+ ThreadResource *res = nullptr;
+ std::unique_lock _lock(sw_thread_lock);
+ auto iter = thread_resources.find(resource_id);
+ if (iter != thread_resources.end()) {
+ res = iter->second;
+ res->add_ref();
+ }
+ return res;
+}
+
+bool php_swoole_thread_resource_free(ThreadResourceId resource_id, ThreadResource *res) {
+ std::unique_lock _lock(sw_thread_lock);
+ if (res->del_ref() == 0) {
+ thread_resources.erase(resource_id);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static sw_inline ThreadObject *php_swoole_thread_fetch_object(zend_object *obj) {
+ return (ThreadObject *) ((char *) obj - swoole_thread_handlers.offset);
+}
+
+static void php_swoole_thread_free_object(zend_object *object) {
+ php_swoole_thread_join(object);
+ zend_object_std_dtor(object);
+}
+
+static zend_object *php_swoole_thread_create_object(zend_class_entry *ce) {
+ ThreadObject *to = (ThreadObject *) zend_object_alloc(sizeof(ThreadObject), ce);
+ zend_object_std_init(&to->std, ce);
+ object_properties_init(&to->std, ce);
+ to->std.handlers = &swoole_thread_handlers;
+ return &to->std;
+}
+
+static void php_swoole_thread_join(zend_object *object) {
+ ThreadObject *to = php_swoole_thread_fetch_object(object);
+ if (to->thread && to->thread->joinable()) {
+ to->thread->join();
+ delete to->thread;
+ to->thread = nullptr;
+ }
+}
+
+SW_EXTERN_C_BEGIN
+static PHP_METHOD(swoole_thread, __construct);
+static PHP_METHOD(swoole_thread, join);
+static PHP_METHOD(swoole_thread, joinable);
+static PHP_METHOD(swoole_thread, detach);
+static PHP_METHOD(swoole_thread, exec);
+static PHP_METHOD(swoole_thread, getArguments);
+static PHP_METHOD(swoole_thread, getId);
+static PHP_METHOD(swoole_thread, getTsrmInfo);
+SW_EXTERN_C_END
+
+// clang-format off
+static const zend_function_entry swoole_thread_methods[] = {
+ PHP_ME(swoole_thread, __construct, arginfo_class_Swoole_Thread___construct, ZEND_ACC_PUBLIC)
+ PHP_ME(swoole_thread, join, arginfo_class_Swoole_Thread_join, ZEND_ACC_PUBLIC)
+ PHP_ME(swoole_thread, joinable, arginfo_class_Swoole_Thread_joinable, ZEND_ACC_PUBLIC)
+ PHP_ME(swoole_thread, detach, arginfo_class_Swoole_Thread_detach, ZEND_ACC_PUBLIC)
+ PHP_ME(swoole_thread, exec, arginfo_class_Swoole_Thread_exec, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(swoole_thread, getArguments, arginfo_class_Swoole_Thread_getArguments, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(swoole_thread, getId, arginfo_class_Swoole_Thread_getId, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(swoole_thread, getTsrmInfo, arginfo_class_Swoole_Thread_getTsrmInfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_FE_END
+};
+// clang-format on
+
+void php_swoole_thread_minit(int module_number) {
+ SW_INIT_CLASS_ENTRY(swoole_thread, "Swoole\\Thread", nullptr, swoole_thread_methods);
+ SW_SET_CLASS_NOT_SERIALIZABLE(swoole_thread);
+ SW_SET_CLASS_CLONEABLE(swoole_thread, sw_zend_class_clone_deny);
+ SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_thread, sw_zend_class_unset_property_deny);
+ SW_SET_CLASS_CUSTOM_OBJECT(
+ swoole_thread, php_swoole_thread_create_object, php_swoole_thread_free_object, ThreadObject, std);
+
+ zend_declare_property_long(swoole_thread_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY);
+ zend_declare_class_constant_long(
+ swoole_thread_ce, ZEND_STRL("HARDWARE_CONCURRENCY"), std::thread::hardware_concurrency());
+
+ // only used for thread argument forwarding
+ SW_INIT_CLASS_ENTRY_DATA_OBJECT(swoole_thread_stream, "Swoole\\Thread\\Stream");
+ zend_declare_property_long(swoole_thread_stream_ce, ZEND_STRL("fd"), 0, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY);
+}
+
+static PHP_METHOD(swoole_thread, __construct) {
+ php_swoole_thread_create(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_THIS);
+}
+
+static PHP_METHOD(swoole_thread, join) {
+ ThreadObject *to = php_swoole_thread_fetch_object(Z_OBJ_P(ZEND_THIS));
+ if (!to || !to->thread || !to->thread->joinable()) {
+ RETURN_FALSE;
+ }
+ php_swoole_thread_join(Z_OBJ_P(ZEND_THIS));
+ RETURN_TRUE;
+}
+
+static PHP_METHOD(swoole_thread, joinable) {
+ ThreadObject *to = php_swoole_thread_fetch_object(Z_OBJ_P(ZEND_THIS));
+ if (to == nullptr || !to->thread) {
+ RETURN_FALSE;
+ }
+ RETURN_BOOL(to->thread->joinable());
+}
+
+static PHP_METHOD(swoole_thread, detach) {
+ ThreadObject *to = php_swoole_thread_fetch_object(Z_OBJ_P(ZEND_THIS));
+ if (to == nullptr || !to->thread) {
+ RETURN_FALSE;
+ }
+ to->thread->detach();
+ delete to->thread;
+ to->thread = nullptr;
+ RETURN_TRUE;
+}
+
+zval *php_swoole_thread_get_arguments() {
+ if (!ZVAL_IS_ARRAY(&thread_argv)) {
+ array_init(&thread_argv);
+ }
+ return &thread_argv;
+}
+
+static PHP_METHOD(swoole_thread, getArguments) {
+ RETURN_ZVAL(php_swoole_thread_get_arguments(), 1, 0);
+}
+
+static PHP_METHOD(swoole_thread, getId) {
+ RETURN_LONG(pthread_self());
+}
+
+zend_string *php_swoole_thread_serialize(zval *zdata) {
+ php_serialize_data_t var_hash;
+ smart_str serialized_data = {0};
+
+ if (ZVAL_IS_ARRAY(zdata)) {
+ zval *elem;
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zdata), elem) {
+ ZVAL_DEREF(elem);
+ if (Z_TYPE_P(elem) != IS_RESOURCE) {
+ continue;
+ }
+ int sockfd = php_swoole_thread_stream_fileno(elem);
+ if (sockfd < 0) {
+ continue;
+ }
+ zval_ptr_dtor(elem);
+ object_init_ex(elem, swoole_thread_stream_ce);
+ zend_update_property_long(swoole_thread_stream_ce, SW_Z8_OBJ_P(elem), ZEND_STRL("fd"), sockfd);
+ }
+ ZEND_HASH_FOREACH_END();
+ }
+
+ PHP_VAR_SERIALIZE_INIT(var_hash);
+ php_var_serialize(&serialized_data, zdata, &var_hash);
+ PHP_VAR_SERIALIZE_DESTROY(var_hash);
+
+ zend_string *result = nullptr;
+ if (!EG(exception)) {
+ result = zend_string_init(serialized_data.s->val, serialized_data.s->len, 1);
+ }
+ smart_str_free(&serialized_data);
+ return result;
+}
+
+bool php_swoole_thread_unserialize(zend_string *data, zval *zv) {
+ php_unserialize_data_t var_hash;
+ const char *p = ZSTR_VAL(data);
+ size_t l = ZSTR_LEN(data);
+
+ PHP_VAR_UNSERIALIZE_INIT(var_hash);
+ zend_bool unserialized = php_var_unserialize(zv, (const uchar **) &p, (const uchar *) (p + l), &var_hash);
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ if (!unserialized) {
+ swoole_warning("unserialize() failed, Error at offset " ZEND_LONG_FMT " of %zd bytes",
+ (zend_long) ((char *) p - ZSTR_VAL(data)),
+ l);
+ } else {
+ if (ZVAL_IS_ARRAY(zv)) {
+ zval *elem;
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zv), elem) {
+ ZVAL_DEREF(elem);
+ if (Z_TYPE_P(elem) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(elem), swoole_thread_stream_ce)) {
+ continue;
+ }
+ zend_long sockfd = zend::object_get_long(elem, ZEND_STRL("fd"));
+ zval_ptr_dtor(elem);
+ zval zstream;
+ php_swoole_thread_stream_restore(sockfd, &zstream);
+ ZVAL_COPY(elem, &zstream);
+ }
+ ZEND_HASH_FOREACH_END();
+ }
+ }
+ return unserialized;
+}
+
+void php_swoole_thread_rinit() {
+ if (tsrm_is_main_thread()) {
+ if (SG(request_info).path_translated) {
+ request_info.path_translated = strdup(SG(request_info).path_translated);
+ }
+ // Return reference
+ zval *global_argv = zend_hash_find_ind(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_ARGV));
+ if (global_argv) {
+ request_info.argv_serialized = php_swoole_thread_serialize(global_argv);
+ request_info.argc = SG(request_info).argc;
+ }
+ }
+}
+
+void php_swoole_thread_rshutdown() {
+ zval_dtor(&thread_argv);
+ if (tsrm_is_main_thread()) {
+ if (request_info.path_translated) {
+ free((void *) request_info.path_translated);
+ request_info.path_translated = nullptr;
+ }
+ if (request_info.argv_serialized) {
+ zend_string_release(request_info.argv_serialized);
+ request_info.argv_serialized = nullptr;
+ }
+ }
+}
+
+static void php_swoole_thread_create(INTERNAL_FUNCTION_PARAMETERS, zval *zobject) {
+ char *script_file;
+ size_t l_script_file;
+ zval *args;
+ int argc;
+
+ ZEND_PARSE_PARAMETERS_START(1, -1)
+ Z_PARAM_STRING(script_file, l_script_file)
+ Z_PARAM_VARIADIC('+', args, argc)
+ ZEND_PARSE_PARAMETERS_END();
+
+ if (l_script_file < 1) {
+ zend_throw_exception(swoole_exception_ce, "exec file name is empty", SW_ERROR_INVALID_PARAMS);
+ return;
+ }
+
+ ThreadObject *to = php_swoole_thread_fetch_object(Z_OBJ_P(zobject));
+ zend_string *file = zend_string_init(script_file, l_script_file, 1);
+
+ zval zargv;
+ array_init(&zargv);
+ for (int i = 0; i < argc; i++) {
+ zend::array_add(&zargv, &args[i]);
+ }
+ zend_string *argv = php_swoole_thread_serialize(&zargv);
+ zval_dtor(&zargv);
+
+ if (!argv) {
+ zend_string_release(file);
+ return;
+ }
+
+ to->thread = new std::thread([file, argv]() { php_swoole_thread_start(file, argv); });
+ zend_update_property_long(swoole_thread_ce, SW_Z8_OBJ_P(zobject), ZEND_STRL("id"), to->thread->native_handle());
+}
+
+void php_swoole_thread_start(zend_string *file, zend_string *argv_serialized) {
+ ts_resource(0);
+ TSRMLS_CACHE_UPDATE();
+ zend_file_handle file_handle{};
+ zval global_argc, global_argv;
+
+ PG(expose_php) = 0;
+ PG(auto_globals_jit) = 1;
+#if PHP_VERSION_ID >= 80100
+ PG(enable_dl) = false;
+#else
+ PG(enable_dl) = 0;
+#endif
+
+ swoole_thread_init();
+
+ if (php_request_startup() != SUCCESS) {
+ EG(exit_status) = 1;
+ goto _startup_error;
+ }
+
+ PG(during_request_startup) = 0;
+ SG(sapi_started) = 0;
+ SG(headers_sent) = 1;
+ SG(request_info).no_headers = 1;
+ SG(request_info).path_translated = request_info.path_translated;
+ SG(request_info).argc = request_info.argc;
+
+ zend_stream_init_filename(&file_handle, ZSTR_VAL(file));
+ file_handle.primary_script = 1;
+
+ zend_first_try {
+ if (argv_serialized == nullptr || ZSTR_LEN(argv_serialized) == 0) {
+ array_init(&thread_argv);
+ } else {
+ php_swoole_thread_unserialize(argv_serialized, &thread_argv);
+ }
+ if (request_info.argv_serialized) {
+ php_swoole_thread_unserialize(request_info.argv_serialized, &global_argv);
+ ZVAL_LONG(&global_argc, request_info.argc);
+ zend_hash_update(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_ARGV), &global_argv);
+ zend_hash_update(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_ARGC), &global_argc);
+ }
+ php_execute_script(&file_handle);
+ }
+ zend_end_try();
+
+ zend_destroy_file_handle(&file_handle);
+ php_request_shutdown(NULL);
+ file_handle.filename = NULL;
+
+_startup_error:
+ zend_string_release(file);
+ zend_string_release(argv_serialized);
+ ts_free_thread();
+ swoole_thread_clean();
+}
+
+static int php_swoole_thread_stream_fileno(zval *zstream) {
+ php_stream *stream;
+ int sockfd;
+ int cast_flags = PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL;
+ if ((php_stream_from_zval_no_verify(stream, zstream))) {
+ if (php_stream_cast(stream, cast_flags, (void **) &sockfd, 1) == SUCCESS && sockfd >= 0) {
+ return dup(sockfd);
+ }
+ }
+ return -1;
+}
+
+static bool php_swoole_thread_stream_restore(zend_long sockfd, zval *return_value) {
+ std::string path = "php://fd/" + std::to_string(sockfd);
+ php_stream *stream = php_stream_open_wrapper_ex(path.c_str(), "", 0, NULL, NULL);
+ if (stream) {
+ php_stream_to_zval(stream, return_value);
+ return true;
+ }
+ return false;
+}
+
+static PHP_METHOD(swoole_thread, exec) {
+ object_init_ex(return_value, swoole_thread_ce);
+ php_swoole_thread_create(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value);
+}
+
+static PHP_METHOD(swoole_thread, getTsrmInfo) {
+ array_init(return_value);
+ add_assoc_bool(return_value, "is_main_thread", tsrm_is_main_thread());
+ add_assoc_bool(return_value, "is_shutdown", tsrm_is_shutdown());
+ add_assoc_string(return_value, "api_name", tsrm_api_name());
+}
+
+void ArrayItem::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;
+ case IS_RESOURCE: {
+ int sock_fd = php_swoole_thread_stream_fileno(zvalue);
+ if (sock_fd != -1) {
+ value.lval = sock_fd;
+ type = IS_STREAM_SOCKET;
+ break;
+ }
+ }
+ /* no 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 ArrayItem::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_STREAM_SOCKET:
+ php_swoole_thread_stream_restore(value.lval, return_value);
+ break;
+ case IS_SERIALIZED_OBJECT:
+ php_swoole_thread_unserialize(value.serialized_object, return_value);
+ break;
+ default:
+ break;
+ }
+}
+
+void ArrayItem::release() {
+ if (type == IS_STRING) {
+ zend_string_release(value.str);
+ value.str = nullptr;
+ } else if (type == IS_STREAM_SOCKET) {
+ ::close(value.lval);
+ value.lval = -1;
+ } else if (type == IS_SERIALIZED_OBJECT) {
+ zend_string_release(value.serialized_object);
+ value.serialized_object = nullptr;
+ }
+}
+
+#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..b9dc88088c4
--- /dev/null
+++ b/ext-src/swoole_thread_atomic.cc
@@ -0,0 +1,368 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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);
+ o->res->value = value;
+}
+
+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);
+ o->res->value = value;
+}
+
+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..bccd45cd6ac
--- /dev/null
+++ b/ext-src/swoole_thread_lock.cc
@@ -0,0 +1,234 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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"
+
+#ifdef SW_THREAD
+
+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;
+ }
+}
+
+#endif
diff --git a/ext-src/swoole_thread_map.cc b/ext-src/swoole_thread_map.cc
new file mode 100644
index 00000000000..9da7a653a04
--- /dev/null
+++ b/ext-src/swoole_thread_map.cc
@@ -0,0 +1,195 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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/ext-src/swoole_timer.cc b/ext-src/swoole_timer.cc
index 4f27ef1a258..750898df568 100644
--- a/ext-src/swoole_timer.cc
+++ b/ext-src/swoole_timer.cc
@@ -36,7 +36,6 @@ static zend_object_handlers swoole_timer_handlers;
static zend_class_entry *swoole_timer_iterator_ce;
SW_EXTERN_C_BEGIN
-static PHP_FUNCTION(swoole_timer_set);
static PHP_FUNCTION(swoole_timer_after);
static PHP_FUNCTION(swoole_timer_tick);
static PHP_FUNCTION(swoole_timer_exists);
@@ -50,7 +49,6 @@ SW_EXTERN_C_END
// clang-format off
static const zend_function_entry swoole_timer_methods[] =
{
- ZEND_FENTRY(set, ZEND_FN(swoole_timer_set), arginfo_swoole_timer_set, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC | ZEND_ACC_DEPRECATED)
ZEND_FENTRY(tick, ZEND_FN(swoole_timer_tick), arginfo_swoole_timer_tick, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FENTRY(after, ZEND_FN(swoole_timer_after), arginfo_swoole_timer_after, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FENTRY(exists, ZEND_FN(swoole_timer_exists), arginfo_swoole_timer_exists, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
@@ -69,8 +67,6 @@ void php_swoole_timer_minit(int module_number) {
SW_INIT_CLASS_ENTRY_BASE(swoole_timer_iterator, "Swoole\\Timer\\Iterator", nullptr, nullptr, spl_ce_ArrayIterator);
- SW_FUNCTION_ALIAS(
- &swoole_timer_ce->function_table, "set", CG(function_table), "swoole_timer_set", arginfo_swoole_timer_set);
SW_FUNCTION_ALIAS(
&swoole_timer_ce->function_table, "after", CG(function_table), "swoole_timer_after", arginfo_swoole_timer_tick);
SW_FUNCTION_ALIAS(
@@ -203,21 +199,6 @@ static void timer_add(INTERNAL_FUNCTION_PARAMETERS, bool persistent) {
RETURN_LONG(tnode->id);
}
-static PHP_FUNCTION(swoole_timer_set) {
- zval *zset = nullptr;
- zval *ztmp;
-
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ARRAY(zset)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
-
- HashTable *vht = Z_ARRVAL_P(zset);
-
- if (php_swoole_array_get_value(vht, "enable_coroutine", ztmp)) {
- SWOOLE_G(enable_coroutine) = zval_is_true(ztmp);
- }
-}
-
static PHP_FUNCTION(swoole_timer_after) {
timer_add(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
}
diff --git a/ext-src/swoole_websocket_server.cc b/ext-src/swoole_websocket_server.cc
index 386516ffe79..e471a738b24 100644
--- a/ext-src/swoole_websocket_server.cc
+++ b/ext-src/swoole_websocket_server.cc
@@ -44,7 +44,7 @@ static zend_object_handlers swoole_websocket_frame_handlers;
static zend_class_entry *swoole_websocket_closeframe_ce;
static zend_object_handlers swoole_websocket_closeframe_handlers;
-static String *swoole_websocket_buffer = nullptr;
+static SW_THREAD_LOCAL String *swoole_websocket_buffer = nullptr;
SW_EXTERN_C_BEGIN
static PHP_METHOD(swoole_websocket_server, push);
@@ -257,7 +257,7 @@ void swoole_websocket_onBeforeHandshakeResponse(Server *serv, int server_fd, Htt
php_swoole_server_get_fci_cache(serv, server_fd, SW_SERVER_CB_onBeforeHandshakeResponse);
if (fci_cache) {
zval args[3];
- args[0] = *((zval *) serv->private_data_2);
+ args[0] = *php_swoole_server_zval_ptr(serv);
args[1] = *ctx->request.zobject;
args[2] = *ctx->response.zobject;
if (UNEXPECTED(!zend::function::call(fci_cache, 3, args, nullptr, serv->is_enable_coroutine()))) {
@@ -277,7 +277,7 @@ void swoole_websocket_onOpen(Server *serv, HttpContext *ctx) {
zend_fcall_info_cache *fci_cache = php_swoole_server_get_fci_cache(serv, conn->server_fd, SW_SERVER_CB_onOpen);
if (fci_cache) {
zval args[2];
- args[0] = *((zval *) serv->private_data_2);
+ args[0] = *php_swoole_server_zval_ptr(serv);
args[1] = *ctx->request.zobject;
if (UNEXPECTED(!zend::function::call(fci_cache, 2, args, nullptr, serv->is_enable_coroutine()))) {
php_swoole_error(E_WARNING, "%s->onOpen handler error", ZSTR_VAL(swoole_websocket_server_ce->name));
@@ -561,7 +561,7 @@ int swoole_websocket_onMessage(Server *serv, RecvData *req) {
php_swoole_server_get_fci_cache(serv, req->info.server_fd, SW_SERVER_CB_onMessage);
zval args[2];
- args[0] = *(zval *) serv->private_data_2;
+ args[0] = *php_swoole_server_zval_ptr(serv);
php_swoole_websocket_construct_frame(&args[1], opcode, &zdata, flags);
zend_update_property_long(swoole_websocket_frame_ce, SW_Z8_OBJ_P(&args[1]), ZEND_STRL("fd"), fd);
@@ -593,7 +593,9 @@ void php_swoole_websocket_server_minit(int module_number) {
nullptr,
swoole_websocket_server_methods,
swoole_http_server);
+#ifndef SW_THREAD
SW_SET_CLASS_NOT_SERIALIZABLE(swoole_websocket_server);
+#endif
SW_SET_CLASS_CLONEABLE(swoole_websocket_server, sw_zend_class_clone_deny);
SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_websocket_server, sw_zend_class_unset_property_deny);
diff --git a/include/swoole.h b/include/swoole.h
index ee12b283ab3..3f423821aec 100644
--- a/include/swoole.h
+++ b/include/swoole.h
@@ -60,6 +60,7 @@
#include
#include
#include
+#include
#ifdef SW_USE_IOURING
#include
@@ -177,6 +178,20 @@ typedef unsigned long ulong_t;
#endif
#define SW_START_SLEEP usleep(100000) // sleep 1s,wait fork and pthread_create
+#ifdef SW_THREAD
+#define SW_THREAD_LOCAL thread_local
+extern std::mutex sw_thread_lock;
+#else
+#define SW_THREAD_LOCAL
+#endif
+
+/**
+ * API naming rules
+ * -----------------------------------
+ * - starts with swoole_, means it is ready or has been used as an external API
+ * - starts with sw_, internal use only
+ */
+
/*-----------------------------------Memory------------------------------------*/
void *sw_malloc(size_t size);
void sw_free(void *ptr);
@@ -320,9 +335,9 @@ static inline const char *swoole_strnstr(const char *haystack,
}
static inline const char *swoole_strncasestr(const char *haystack,
- uint32_t haystack_length,
- const char *needle,
- uint32_t needle_length) {
+ uint32_t haystack_length,
+ const char *needle,
+ uint32_t needle_length) {
assert(needle_length > 0);
uint32_t i;
@@ -535,6 +550,7 @@ enum swProcessType {
SW_PROCESS_MASTER = 1,
SW_PROCESS_WORKER = 2,
SW_PROCESS_MANAGER = 3,
+ SW_PROCESS_EVENTWORKER = 2,
SW_PROCESS_TASKWORKER = 4,
SW_PROCESS_USERWORKER = 5,
};
@@ -567,6 +583,8 @@ void swoole_init(void);
void swoole_clean(void);
pid_t swoole_fork(int flags);
pid_t swoole_fork_exec(const std::function &child_fn);
+void swoole_thread_init(void);
+void swoole_thread_clean(void);
void swoole_redirect_stdout(int new_fd);
int swoole_shell_exec(const char *command, pid_t *pid, bool get_error_stream);
int swoole_daemon(int nochdir, int noclose);
@@ -663,6 +681,10 @@ struct RecvData {
struct ThreadGlobal {
uint16_t id;
uint8_t type;
+#ifdef SW_THREAD
+ uint8_t process_type;
+ uint32_t process_id;
+#endif
String *buffer_stack;
Reactor *reactor;
Timer *timer;
@@ -717,8 +739,9 @@ struct Global {
uchar dns_lookup_random : 1;
uchar use_async_resolver : 1;
uchar use_name_resolver : 1;
+ uchar enable_coroutine : 1;
- int process_type;
+ uint8_t process_type;
uint32_t process_id;
TaskId current_task_id;
pid_t pid;
@@ -778,20 +801,56 @@ static inline void swoole_set_last_error(int error) {
SwooleTG.error = error;
}
-static inline int swoole_get_last_error() {
+static inline int swoole_get_last_error(void) {
return SwooleTG.error;
}
-static inline int swoole_get_thread_id() {
+static inline int swoole_get_thread_id(void) {
return SwooleTG.id;
}
-static inline int swoole_get_process_type() {
- return SwooleG.process_type;
+static inline int swoole_get_thread_type(void) {
+ return SwooleTG.type;
+}
+
+static inline void swoole_set_thread_id(uint16_t id) {
+ SwooleTG.id = id;
}
-static inline int swoole_get_process_id() {
+static inline void swoole_set_thread_type(uint8_t type) {
+ SwooleTG.type = type;
+}
+
+static inline swoole::WorkerId swoole_get_process_id(void) {
+#ifdef SW_THREAD
+ return SwooleTG.process_id;
+#else
return SwooleG.process_id;
+#endif
+}
+
+static inline void swoole_set_process_id(swoole::WorkerId id) {
+#ifdef SW_THREAD
+ SwooleTG.process_id = id;
+#else
+ SwooleG.process_id = id;
+#endif
+}
+
+static inline void swoole_set_process_type(int type) {
+#ifdef SW_THREAD
+ SwooleTG.process_type = type;
+#else
+ SwooleG.process_type = type;
+#endif
+}
+
+static inline int swoole_get_process_type(void) {
+#ifdef SW_THREAD
+ return SwooleTG.process_type;
+#else
+ return SwooleG.process_type;
+#endif
}
static inline uint32_t swoole_pagesize() {
@@ -848,3 +907,4 @@ static sw_inline swoole::MemoryPool *sw_mem_pool() {
static sw_inline const swoole::Allocator *sw_std_allocator() {
return &SwooleG.std_allocator;
}
+
diff --git a/include/swoole_asm_context.h b/include/swoole_asm_context.h
index 3ba14af5930..7db0fbd9452 100644
--- a/include/swoole_asm_context.h
+++ b/include/swoole_asm_context.h
@@ -29,6 +29,11 @@ SW_EXTERN_C_BEGIN
typedef void *fcontext_t;
+struct transfer_t {
+ fcontext_t fctx;
+ void * data;
+};
+
#ifdef __GNUC__
#define SW_GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
#else
@@ -41,8 +46,19 @@ typedef void *fcontext_t;
#define SW_INDIRECT_RETURN
#endif
-intptr_t swoole_jump_fcontext(fcontext_t *ofc, fcontext_t nfc, intptr_t vp, bool preserve_fpu = false);
-SW_INDIRECT_RETURN fcontext_t swoole_make_fcontext(void *sp, size_t size, void (*fn)(intptr_t));
+#undef SWOOLE_CONTEXT_CALLDECL
+#if (defined(i386) || defined(__i386__) || defined(__i386) \
+ || defined(__i486__) || defined(__i586__) || defined(__i686__) \
+ || defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \
+ || defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \
+ || defined(_M_IX86) || defined(_I86_)) && defined(BOOST_WINDOWS)
+# define SWOOLE_CONTEXT_CALLDECL __cdecl
+#else
+# define SWOOLE_CONTEXT_CALLDECL
+#endif
+
+transfer_t SWOOLE_CONTEXT_CALLDECL swoole_jump_fcontext(fcontext_t const to, void * vp);
+fcontext_t SWOOLE_CONTEXT_CALLDECL swoole_make_fcontext(void *stack, size_t stack_size, void (* fn)(transfer_t));
SW_EXTERN_C_END
diff --git a/include/swoole_async.h b/include/swoole_async.h
index 7f16bc1d0a0..1ba9858f122 100644
--- a/include/swoole_async.h
+++ b/include/swoole_async.h
@@ -100,10 +100,9 @@ struct GethostbynameRequest {
class AsyncThreads {
public:
- bool schedule = false;
size_t task_num = 0;
Pipe *pipe = nullptr;
- async::ThreadPool *pool = nullptr;
+ std::shared_ptr pool;
network::Socket *read_socket = nullptr;
network::Socket *write_socket = nullptr;
@@ -119,9 +118,6 @@ class AsyncThreads {
void notify_one();
static int callback(Reactor *reactor, Event *event);
-
- private:
- std::mutex init_lock;
};
#ifdef SW_USE_IOURING
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_coroutine.h b/include/swoole_coroutine.h
index f83453005f7..ec23f0e0e69 100644
--- a/include/swoole_coroutine.h
+++ b/include/swoole_coroutine.h
@@ -135,7 +135,7 @@ class Coroutine {
return ctx;
}
- static std::unordered_map coroutines;
+ static SW_THREAD_LOCAL std::unordered_map coroutines;
static void set_on_yield(SwapCallback func);
static void set_on_resume(SwapCallback func);
@@ -163,12 +163,6 @@ class Coroutine {
#endif
}
- static inline Coroutine *init_main_coroutine() {
- Coroutine *co = new Coroutine(0, nullptr, nullptr);
- co->state = STATE_RUNNING;
- return co;
- }
-
static void activate();
static void deactivate();
@@ -245,15 +239,15 @@ class Coroutine {
static void print_list();
protected:
- static Coroutine *current;
- static long last_cid;
- static uint64_t peak_num;
- static size_t stack_size;
- static SwapCallback on_yield; /* before yield */
- static SwapCallback on_resume; /* before resume */
- static SwapCallback on_close; /* before close */
- static BailoutCallback on_bailout; /* when bailout */
- static bool activated;
+ static SW_THREAD_LOCAL Coroutine *current;
+ static SW_THREAD_LOCAL long last_cid;
+ static SW_THREAD_LOCAL uint64_t peak_num;
+ static SW_THREAD_LOCAL size_t stack_size;
+ static SW_THREAD_LOCAL SwapCallback on_yield; /* before yield */
+ static SW_THREAD_LOCAL SwapCallback on_resume; /* before resume */
+ static SW_THREAD_LOCAL SwapCallback on_close; /* before close */
+ static SW_THREAD_LOCAL BailoutCallback on_bailout; /* when bailout */
+ static SW_THREAD_LOCAL bool activated;
enum State state = STATE_INIT;
enum ResumeCode resume_code_ = RC_OK;
diff --git a/include/swoole_coroutine_context.h b/include/swoole_coroutine_context.h
index de3727444ba..0dffd6f326c 100644
--- a/include/swoole_coroutine_context.h
+++ b/include/swoole_coroutine_context.h
@@ -42,6 +42,11 @@
typedef ucontext_t coroutine_context_t;
#elif defined(USE_ASM_CONTEXT)
typedef fcontext_t coroutine_context_t;
+typedef transfer_t coroutine_transfer_t;
+#endif
+
+#if defined(USE_UCONTEXT) || defined(SW_USE_THREAD_CONTEXT)
+typedef void * coroutine_transfer_t;
#endif
typedef std::function CoroutineFunc;
@@ -89,7 +94,7 @@ class Context {
void *private_data_;
bool end_;
- static void context_func(void *arg);
+ static void context_func(coroutine_transfer_t arg);
};
} // namespace coroutine
diff --git a/include/swoole_error.h b/include/swoole_error.h
index 603d0cd38bc..c608de54eec 100644
--- a/include/swoole_error.h
+++ b/include/swoole_error.h
@@ -35,6 +35,8 @@ enum swErrorCode {
SW_ERROR_PROTOCOL_ERROR,
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/include/swoole_lock.h b/include/swoole_lock.h
index b5b851902a1..870ec02a80f 100644
--- a/include/swoole_lock.h
+++ b/include/swoole_lock.h
@@ -29,9 +29,7 @@ class Lock {
enum Type {
NONE,
RW_LOCK = 1,
- FILE_LOCK = 2,
MUTEX = 3,
- SEM = 4,
SPIN_LOCK = 5,
ATOMIC_LOCK = 6,
};
diff --git a/include/swoole_process_pool.h b/include/swoole_process_pool.h
index cf6fc72f289..74f70754018 100644
--- a/include/swoole_process_pool.h
+++ b/include/swoole_process_pool.h
@@ -107,6 +107,7 @@ struct WorkerGlobal {
bool shutdown;
uint32_t max_request;
Worker *worker;
+ Worker *worker_copy;
time_t exit_time;
};
@@ -288,6 +289,7 @@ struct ProcessPool {
int get_max_request();
bool detach();
int wait();
+ int start_check();
int start();
void shutdown();
bool reload();
@@ -325,5 +327,10 @@ static sw_inline int swoole_kill(pid_t __pid, int __sig) {
return kill(__pid, __sig);
}
-extern swoole::WorkerGlobal SwooleWG; // Worker Global Variable
typedef swoole::ProtocolType swProtocolType;
+
+extern SW_THREAD_LOCAL swoole::WorkerGlobal SwooleWG;
+
+static inline swoole::Worker *sw_worker() {
+ return SwooleWG.worker;
+}
diff --git a/include/swoole_server.h b/include/swoole_server.h
index 0ef0f43fff2..e75f0185c86 100644
--- a/include/swoole_server.h
+++ b/include/swoole_server.h
@@ -27,6 +27,9 @@
#include "swoole_pipe.h"
#include "swoole_channel.h"
#include "swoole_message_bus.h"
+#ifdef SW_THREAD
+#include "swoole_lock.h"
+#endif
#ifdef SW_USE_OPENSSL
#include "swoole_dtls.h"
@@ -43,6 +46,7 @@
#include
#include
#include
+#include
//------------------------------------Server-------------------------------------------
namespace swoole {
@@ -54,6 +58,8 @@ struct Request;
class Server;
struct Manager;
+typedef std::function WorkerFn;
+
struct Session {
SessionId id;
int fd;
@@ -153,6 +159,9 @@ struct ReactorThread {
MessageBus message_bus;
int init(Server *serv, Reactor *reactor, uint16_t reactor_id);
+ void shutdown(Reactor *reactor);
+ int close_connection(Reactor *reactor, SessionId session_id);
+ void clean();
};
struct ServerPortGS {
@@ -319,6 +328,8 @@ struct ListenPort {
void close();
bool import(int sock);
const char *get_protocols();
+ int create_socket(Server *server);
+ void close_socket();
#ifdef SW_USE_OPENSSL
bool ssl_create_context(SSLContext *context);
@@ -337,20 +348,20 @@ struct ListenPort {
network::Socket *get_socket() {
return socket;
}
- int get_port() {
+ int get_port() const {
return port;
}
- const char *get_host() {
+ const char *get_host() const {
return host.c_str();
}
- SocketType get_type() {
+ SocketType get_type() const {
return type;
}
- int get_fd() {
+ int get_fd() const {
return socket ? socket->fd : -1;
}
- size_t get_connection_num();
+ size_t get_connection_num() const;
};
struct ServerGS {
@@ -400,6 +411,13 @@ class Factory {
Factory(Server *_server) {
server_ = _server;
}
+ pid_t spawn_event_worker(Worker *worker);
+ pid_t spawn_user_worker(Worker *worker);
+ pid_t spawn_task_worker(Worker *worker);
+ void kill_user_workers();
+ void kill_event_workers();
+ void kill_task_workers();
+ void check_worker_exit_status(Worker *worker, const ExitStatus &exit_status);
virtual ~Factory() {}
virtual bool start() = 0;
virtual bool shutdown() = 0;
@@ -411,7 +429,7 @@ class Factory {
class BaseFactory : public Factory {
public:
- BaseFactory(Server *server) : Factory(server) {}
+ BaseFactory(Server *server);
~BaseFactory();
bool start() override;
bool shutdown() override;
@@ -422,9 +440,6 @@ class BaseFactory : public Factory {
};
class ProcessFactory : public Factory {
- private:
- std::vector> pipes;
-
public:
ProcessFactory(Server *server);
~ProcessFactory();
@@ -436,6 +451,28 @@ class ProcessFactory : public Factory {
bool end(SessionId sesion_id, int flags) override;
};
+class ThreadFactory : public BaseFactory {
+ private:
+ std::vector threads_;
+ std::mutex lock_;
+ std::condition_variable cv_;
+ std::queue queue_;
+ Worker manager;
+ template
+ void create_thread(int i, _Callable fn);
+ void at_thread_exit(Worker *worker);
+ public:
+ ThreadFactory(Server *server);
+ ~ThreadFactory();
+ void spawn_event_worker(WorkerId i);
+ void spawn_task_worker(WorkerId i);
+ void spawn_user_worker(WorkerId i);
+ void spawn_manager_thread(WorkerId i);
+ void wait();
+ bool start() override;
+ bool shutdown() override;
+};
+
enum ServerEventType {
// recv data payload
SW_SERVER_EVENT_RECV_DATA,
@@ -488,6 +525,7 @@ class Server {
enum Mode {
MODE_BASE = 1,
MODE_PROCESS = 2,
+ MODE_THREAD = 3,
};
enum TaskIpcMode {
@@ -501,6 +539,7 @@ class Server {
THREAD_MASTER = 1,
THREAD_REACTOR = 2,
THREAD_HEARTBEAT = 3,
+ THREAD_WORKER = 4,
};
enum DispatchMode {
@@ -726,12 +765,17 @@ class Server {
Manager *manager = nullptr;
std::vector ports;
+ std::vector> worker_pipes;
ListenPort *get_primary_port() {
return ports.front();
}
- ListenPort *get_port(int _port) {
+ enum Mode get_mode() const {
+ return mode_;
+ };
+
+ const ListenPort *get_port(int _port) const {
for (auto port : ports) {
if (port->port == _port || _port == 0) {
return port;
@@ -922,6 +966,14 @@ class Server {
void add_http_compression_type(const std::string &type);
int create();
+ Factory *create_base_factory();
+ Factory *create_thread_factory();
+ Factory *create_process_factory();
+ bool create_worker_pipes();
+ void destroy_base_factory();
+ void destroy_thread_factory();
+ void destroy_process_factory();
+
int start();
bool reload(bool reload_all_workers);
bool shutdown();
@@ -983,6 +1035,14 @@ class Server {
return buffer;
}
+ MessageBus *get_worker_message_bus() {
+#ifdef SW_THREAD
+ return sw_likely(is_thread_mode()) ? &get_thread(swoole_get_thread_id())->message_bus : &message_bus;
+#else
+ return &message_bus;
+#endif
+ }
+
uint32_t get_worker_buffer_num() {
return is_base_mode() ? 1 : reactor_num + dgram_port_num;
}
@@ -1003,6 +1063,10 @@ class Server {
return mode_ == MODE_BASE;
}
+ bool is_thread_mode() {
+ return mode_ == MODE_THREAD;
+ }
+
bool is_enable_coroutine() {
if (is_task_worker()) {
return task_enable_coroutine;
@@ -1013,6 +1077,10 @@ class Server {
}
}
+ bool is_master_thread() {
+ return swoole_get_thread_type() == Server::THREAD_MASTER;
+ }
+
bool is_hash_dispatch_mode() {
return dispatch_mode == DISPATCH_FDMOD || dispatch_mode == DISPATCH_IPMOD ||
dispatch_mode == DISPATCH_CO_CONN_LB;
@@ -1038,6 +1106,10 @@ class Server {
#endif
}
+ bool if_forward_message(Session *session) {
+ return session->reactor_id != swoole_get_process_id();
+ }
+
Worker *get_worker(uint16_t worker_id) {
// Event Worker
if (worker_id < worker_num) {
@@ -1060,6 +1132,7 @@ class Server {
}
void stop_async_worker(Worker *worker);
+ void stop_master_thread();
Pipe *get_pipe_object(int pipe_fd) {
return (Pipe *) connection_list[pipe_fd].object;
@@ -1085,28 +1158,40 @@ class Server {
return factory != nullptr;
}
+ bool is_running() {
+ return running;
+ }
+
bool is_master() {
- return SwooleG.process_type == SW_PROCESS_MASTER;
+ return swoole_get_process_type() == SW_PROCESS_MASTER;
}
bool is_worker() {
- return SwooleG.process_type == SW_PROCESS_WORKER;
+ return swoole_get_process_type() == SW_PROCESS_EVENTWORKER;
}
bool is_task_worker() {
- return SwooleG.process_type == SW_PROCESS_TASKWORKER;
+ return swoole_get_process_type() == SW_PROCESS_TASKWORKER;
}
bool is_manager() {
- return SwooleG.process_type == SW_PROCESS_MANAGER;
+ return swoole_get_process_type() == SW_PROCESS_MANAGER;
}
bool is_user_worker() {
- return SwooleG.process_type == SW_PROCESS_USERWORKER;
+ return swoole_get_process_type() == SW_PROCESS_USERWORKER;
+ }
+
+ bool is_worker_thread() {
+ return is_thread_mode() && swoole_get_thread_type() == Server::THREAD_WORKER;
+ }
+
+ bool is_worker_process() {
+ return !is_thread_mode() && (is_worker() || is_task_worker());
}
bool is_reactor_thread() {
- return SwooleG.process_type == SW_PROCESS_MASTER && SwooleTG.type == Server::THREAD_REACTOR;
+ return swoole_get_thread_type() == Server::THREAD_REACTOR;
}
bool isset_hook(enum HookType type) {
@@ -1232,7 +1317,7 @@ class Server {
void call_hook(enum HookType type, void *arg);
void call_worker_start_callback(Worker *worker);
- ResultCode call_command_handler(MessageBus &mb, uint16_t worker_id, network::Socket *sock);
+ void call_command_handler(MessageBus &mb, uint16_t worker_id, network::Socket *sock);
std::string call_command_handler_in_master(int command_id, const std::string &msg);
void call_command_callback(int64_t request_id, const std::string &result);
void foreach_connection(const std::function &callback);
@@ -1326,7 +1411,7 @@ class Server {
int schedule_worker(int fd, SendData *data);
- size_t get_connection_num() {
+ size_t get_connection_num() const {
if (gs->connection_nums) {
size_t num = 0;
for (uint32_t i = 0; i < worker_num; i++) {
@@ -1338,35 +1423,39 @@ class Server {
}
}
- /**
- * [Manager]
- */
- pid_t spawn_event_worker(Worker *worker);
- pid_t spawn_user_worker(Worker *worker);
- pid_t spawn_task_worker(Worker *worker);
-
- void kill_user_workers();
- void kill_event_workers();
- void kill_task_workers();
-
static int wait_other_worker(ProcessPool *pool, const ExitStatus &exit_status);
static void read_worker_message(ProcessPool *pool, EventData *msg);
void drain_worker_pipe();
- void check_worker_exit_status(Worker *worker, const ExitStatus &exit_status);
-
/**
* [Worker]
*/
void worker_start_callback(Worker *worker);
void worker_stop_callback(Worker *worker);
void worker_accept_event(DataHead *info);
+ void worker_signal_init(void);
+ std::function worker_thread_start;
+
+ /**
+ * [Master]
+ */
+ bool signal_handler_shutdown();
+ bool signal_handler_child_exit();
+ bool signal_handler_reload(bool reload_all_workers);
+ bool signal_handler_read_message();
+ bool signal_handler_reopen_logger();
+
+ static int worker_main_loop(ProcessPool *pool, Worker *worker);
static void worker_signal_handler(int signo);
- static void worker_signal_init(void);
+ static void reactor_thread_main_loop(Server *serv, int reactor_id);
static bool task_pack(EventData *task, const void *data, size_t data_len);
static bool task_unpack(EventData *task, String *buffer, PacketPtr *packet);
+ int start_master_thread(Reactor *reactor);
+ int start_event_worker(Worker *worker);
+ void start_heartbeat_thread();
+
private:
enum Mode mode_;
Connection *connection_list = nullptr;
@@ -1389,15 +1478,9 @@ class Server {
int start_check();
void check_port_type(ListenPort *ls);
void destroy();
- void destroy_reactor_threads();
- void destroy_reactor_processes();
- int create_reactor_processes();
- int create_reactor_threads();
int start_reactor_threads();
int start_reactor_processes();
- int start_master_thread();
- int start_event_worker(Worker *worker);
- void start_heartbeat_thread();
+ int start_worker_threads();
void join_reactor_thread();
TimerCallback get_timeout_callback(ListenPort *port, Reactor *reactor, Connection *conn);
diff --git a/include/swoole_socket.h b/include/swoole_socket.h
index 1626d8d09d0..8d647565d9b 100644
--- a/include/swoole_socket.h
+++ b/include/swoole_socket.h
@@ -336,6 +336,7 @@ struct Socket {
ssize_t peek(void *__buf, size_t __n, int __flags);
Socket *accept();
int bind(const std::string &_host, int *port);
+ Socket *dup();
ssize_t readv(IOVector *io_vector);
ssize_t writev(IOVector *io_vector);
diff --git a/include/swoole_version.h b/include/swoole_version.h
index 468380e451e..990e0dbf6e5 100644
--- a/include/swoole_version.h
+++ b/include/swoole_version.h
@@ -18,12 +18,12 @@
#ifndef SWOOLE_VERSION_H_
#define SWOOLE_VERSION_H_
-#define SWOOLE_MAJOR_VERSION 5
-#define SWOOLE_MINOR_VERSION 1
-#define SWOOLE_RELEASE_VERSION 2
-#define SWOOLE_EXTRA_VERSION ""
-#define SWOOLE_VERSION "5.1.2"
-#define SWOOLE_VERSION_ID 50102
+#define SWOOLE_MAJOR_VERSION 6
+#define SWOOLE_MINOR_VERSION 0
+#define SWOOLE_RELEASE_VERSION 0
+#define SWOOLE_EXTRA_VERSION "dev"
+#define SWOOLE_VERSION "6.0.0-dev"
+#define SWOOLE_VERSION_ID 60000
#define SWOOLE_API_VERSION_ID 0x202208a
#define SWOOLE_BUG_REPORT \
diff --git a/package.xml b/package.xml
index ac34fe5c845..0a9c5ed15f6 100644
--- a/package.xml
+++ b/package.xml
@@ -2407,21 +2407,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/php_swoole.h b/php_swoole.h
index aa6cb096f06..539ea21fefd 100644
--- a/php_swoole.h
+++ b/php_swoole.h
@@ -51,7 +51,6 @@ ZEND_BEGIN_MODULE_GLOBALS(swoole)
zend_bool display_errors;
zend_bool cli;
zend_bool use_shortname;
- zend_bool enable_coroutine;
zend_bool enable_preemptive_scheduler;
zend_bool enable_library;
zend_bool enable_fiber_mock;
diff --git a/scripts/code-stats.sh b/scripts/code-stats.sh
index d044e3cfd93..eed0fce4386 100755
--- a/scripts/code-stats.sh
+++ b/scripts/code-stats.sh
@@ -1,2 +1,7 @@
-#!/bin/sh
+#!/bin/sh -e
+__CURRENT__=$(pwd)
+__DIR__=$(cd "$(dirname "$0")";pwd)
+
+# enter the dir
+cd "${__DIR__}"
cloc ../ --exclude-dir=thirdparty,Debug,CMakeFiles,build,CMakeFiles,.git
diff --git a/scripts/docker-compile-with-thread.sh b/scripts/docker-compile-with-thread.sh
new file mode 100755
index 00000000000..99c32bc48b3
--- /dev/null
+++ b/scripts/docker-compile-with-thread.sh
@@ -0,0 +1,34 @@
+#!/bin/sh -e
+__CURRENT__=$(pwd)
+__DIR__=$(cd "$(dirname "$0")";pwd)
+
+sh library.sh
+
+if [ ! -f "/.dockerenv" ]; then
+ echo "" && echo "❌ This script is just for Docker!"
+ exit
+fi
+
+cd "${__DIR__}" && cd ..
+./scripts/clear.sh
+phpize
+./configure \
+--enable-openssl \
+--enable-sockets \
+--enable-mysqlnd \
+--enable-swoole-curl \
+--enable-cares \
+--enable-swoole-pgsql \
+--enable-swoole-thread \
+--with-swoole-odbc=unixODBC,/usr \
+--with-swoole-oracle=instantclient,/usr/local/instantclient \
+--enable-swoole-sqlite
+
+make -j$(cat /proc/cpuinfo | grep processor | wc -l)
+make install
+docker-php-ext-enable swoole
+php -v
+php -m
+php --ri curl
+php --ri swoole
+
diff --git a/scripts/docker-thread-route.sh b/scripts/docker-thread-route.sh
new file mode 100755
index 00000000000..d6af300e654
--- /dev/null
+++ b/scripts/docker-thread-route.sh
@@ -0,0 +1,22 @@
+#!/bin/sh -e
+__CURRENT__=$(pwd)
+__DIR__=$(cd "$(dirname "$0")";pwd)
+export SWOOLE_THREAD=1
+
+# enter the dir
+cd "${__DIR__}"
+
+# show system info
+date && echo ""
+uname -a && echo ""
+
+# show php info
+php -v && echo ""
+
+# compile in docker
+echo "" && echo "📦 Compile ext-swoole[thread] in docker..." && echo ""
+./docker-compile-with-thread.sh
+
+# run unit tests
+echo "" && echo "📋 Run phpt tests[thread] in docker..." && echo ""
+./run-tests.sh
diff --git a/scripts/make.sh b/scripts/make.sh
index d72285c3617..0bddf4ea2d5 100755
--- a/scripts/make.sh
+++ b/scripts/make.sh
@@ -6,8 +6,8 @@ COMPILE_PARAMS="--enable-openssl \
--enable-mysqlnd \
--enable-swoole-curl \
--enable-cares \
+--enable-swoole-thread \
--enable-swoole-pgsql \
---enable-iouring \
--with-swoole-odbc=unixODBC,/usr \
--enable-swoole-sqlite"
@@ -89,9 +89,4 @@ else
fi
make clean
make -j ${CPU_COUNT}
-
-if [ "$(whoami)" = "root" ]; then
- make install
-else
- sudo make install
-fi
+make install
diff --git a/scripts/route.sh b/scripts/route.sh
index 07272ae87aa..0b7d9af0ea7 100755
--- a/scripts/route.sh
+++ b/scripts/route.sh
@@ -3,14 +3,6 @@ __CURRENT__=`pwd`
__DIR__=$(cd "$(dirname "$0")";pwd)
export DOCKER_COMPOSE_VERSION="1.21.0"
-[ -z "${SWOOLE_BRANCH}" ] && export SWOOLE_BRANCH="master"
-[ -z "${SWOOLE_BUILD_DIR}" ] && export SWOOLE_BUILD_DIR=$(cd "$(dirname "$0")";cd ../;pwd)
-[ -z "${PHP_VERSION_ID}" ] && export PHP_VERSION_ID=`php -r "echo PHP_VERSION_ID;"`
-if [ ${PHP_VERSION_ID} -lt 80300 ]; then
- export PHP_VERSION="`php -r "echo PHP_MAJOR_VERSION;"`.`php -r "echo PHP_MINOR_VERSION;"`"
-else
- export PHP_VERSION="rc"
-fi
if [ "${SWOOLE_BRANCH}" = "alpine" ]; then
export PHP_VERSION="${PHP_VERSION}-alpine"
fi
@@ -90,6 +82,16 @@ run_tests_in_docker(){
fi
}
+run_thread_tests_in_docker(){
+ docker exec swoole touch /.cienv && \
+ docker exec swoole /swoole-src/scripts/docker-thread-route.sh
+ code=$?
+ if [ $code -ne 0 ]; then
+ echo "\n❌ Run thread tests failed! ExitCode: $code"
+ exit 1
+ fi
+}
+
remove_tests_resources(){
remove_docker_containers
remove_data_files
@@ -104,6 +106,11 @@ echo "📦 Start docker containers...\n"
start_docker_containers # && trap "remove_tests_resources"
echo "\n⏳ Run tests in docker...\n"
-run_tests_in_docker
+
+if [ "$SWOOLE_THREAD" = 1 ]; then
+ run_thread_tests_in_docker
+else
+ run_tests_in_docker
+fi
echo "\n🚀🚀🚀Completed successfully🚀🚀🚀\n"
diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh
index da9497b644b..774bbf14059 100755
--- a/scripts/run-tests.sh
+++ b/scripts/run-tests.sh
@@ -59,9 +59,12 @@ echo "" && echo "🌵️️ Current branch is ${SWOOLE_BRANCH}" && echo ""
if [ "${SWOOLE_BRANCH}" = "valgrind" ]; then
dir="base"
options="${options} -m"
+elif [ "$SWOOLE_THREAD" = 1 ]; then
+ dir="swoole_thread"
else
dir="swoole_*"
fi
+echo "${dir}"
echo "${dir}" > tests.list
for i in 1 2 3 4 5
do
diff --git a/src/core/base.cc b/src/core/base.cc
index 37b723a6dc6..f966974f6ba 100644
--- a/src/core/base.cc
+++ b/src/core/base.cc
@@ -98,6 +98,7 @@ static ssize_t getrandom(void *buffer, size_t size, unsigned int __flags) {
swoole::Global SwooleG = {};
__thread swoole::ThreadGlobal SwooleTG = {};
+std::mutex sw_thread_lock;
static std::unordered_map functions;
static swoole::Logger *g_logger_instance = nullptr;
@@ -161,6 +162,7 @@ void swoole_init(void) {
SwooleG.running = 1;
SwooleG.init = 1;
+ SwooleG.enable_coroutine = 1;
SwooleG.std_allocator = {malloc, calloc, realloc, free};
SwooleG.fatal_error = swoole_fatal_error_impl;
SwooleG.cpu_num = SW_MAX(1, sysconf(_SC_NPROCESSORS_ONLN));
@@ -430,6 +432,20 @@ pid_t swoole_fork(int flags) {
return pid;
}
+void swoole_thread_init(void) {
+ if (!SwooleTG.buffer_stack) {
+ SwooleTG.buffer_stack = new String(SW_STACK_BUFFER_SIZE);
+ }
+ swoole_signal_block_all();
+}
+
+void swoole_thread_clean(void) {
+ if (SwooleTG.buffer_stack) {
+ delete SwooleTG.buffer_stack;
+ SwooleTG.buffer_stack = nullptr;
+ }
+}
+
void swoole_dump_ascii(const char *data, size_t size) {
for (size_t i = 0; i < size; i++) {
printf("%u ", (unsigned) data[i]);
diff --git a/src/core/base64.cc b/src/core/base64.cc
index dd9b452b353..0c430bfbf24 100644
--- a/src/core/base64.cc
+++ b/src/core/base64.cc
@@ -131,4 +131,4 @@ size_t base64_decode(const char *in, size_t inlen, char *out) {
return j;
}
-}
+} // namespace swoole
diff --git a/src/core/string.cc b/src/core/string.cc
index fab2edb13df..e6b50065fc0 100644
--- a/src/core/string.cc
+++ b/src/core/string.cc
@@ -180,7 +180,12 @@ ssize_t String::split(const char *delimiter, size_t delimiter_length, const Stri
off_t _offset = offset;
size_t ret;
- swoole_trace_log(SW_TRACE_EOF_PROTOCOL, "#[0] count=%d, length=%ld, size=%ld, offset=%jd", count, length, size, (intmax_t) offset);
+ swoole_trace_log(SW_TRACE_EOF_PROTOCOL,
+ "#[0] count=%d, length=%ld, size=%ld, offset=%jd",
+ count,
+ length,
+ size,
+ (intmax_t) offset);
while (delimiter_addr) {
size_t _length = delimiter_addr - start_addr + delimiter_length;
@@ -207,9 +212,11 @@ ssize_t String::split(const char *delimiter, size_t delimiter_length, const Stri
ret = start_addr - str - _offset;
if (ret > 0 && ret < length) {
- swoole_trace_log(SW_TRACE_EOF_PROTOCOL, "#[5] count=%d, remaining_length=%zu", count, (size_t) (length - offset));
+ swoole_trace_log(
+ SW_TRACE_EOF_PROTOCOL, "#[5] count=%d, remaining_length=%zu", count, (size_t) (length - offset));
} else if (ret >= length) {
- swoole_trace_log(SW_TRACE_EOF_PROTOCOL, "#[3] length=%ld, size=%zu, offset=%jd", length, size, (intmax_t) offset);
+ swoole_trace_log(
+ SW_TRACE_EOF_PROTOCOL, "#[3] length=%ld, size=%zu, offset=%jd", length, size, (intmax_t) offset);
}
return ret;
diff --git a/src/coroutine/base.cc b/src/coroutine/base.cc
index 330f9f6d634..c479ce9d742 100644
--- a/src/coroutine/base.cc
+++ b/src/coroutine/base.cc
@@ -19,17 +19,17 @@
namespace swoole {
-Coroutine *Coroutine::current = nullptr;
-long Coroutine::last_cid = 0;
-std::unordered_map Coroutine::coroutines;
-uint64_t Coroutine::peak_num = 0;
-bool Coroutine::activated = false;
-
-size_t Coroutine::stack_size = SW_DEFAULT_C_STACK_SIZE;
-Coroutine::SwapCallback Coroutine::on_yield = nullptr;
-Coroutine::SwapCallback Coroutine::on_resume = nullptr;
-Coroutine::SwapCallback Coroutine::on_close = nullptr;
-Coroutine::BailoutCallback Coroutine::on_bailout = nullptr;
+SW_THREAD_LOCAL Coroutine *Coroutine::current = nullptr;
+SW_THREAD_LOCAL long Coroutine::last_cid = 0;
+SW_THREAD_LOCAL std::unordered_map Coroutine::coroutines;
+SW_THREAD_LOCAL uint64_t Coroutine::peak_num = 0;
+SW_THREAD_LOCAL bool Coroutine::activated = false;
+
+SW_THREAD_LOCAL size_t Coroutine::stack_size = SW_DEFAULT_C_STACK_SIZE;
+SW_THREAD_LOCAL Coroutine::SwapCallback Coroutine::on_yield = nullptr;
+SW_THREAD_LOCAL Coroutine::SwapCallback Coroutine::on_resume = nullptr;
+SW_THREAD_LOCAL Coroutine::SwapCallback Coroutine::on_close = nullptr;
+SW_THREAD_LOCAL Coroutine::BailoutCallback Coroutine::on_bailout = nullptr;
#ifdef SW_USE_THREAD_CONTEXT
namespace coroutine {
diff --git a/src/coroutine/context.cc b/src/coroutine/context.cc
index fdca66e0e68..8a6c10a9143 100644
--- a/src/coroutine/context.cc
+++ b/src/coroutine/context.cc
@@ -57,7 +57,7 @@ Context::Context(size_t stack_size, CoroutineFunc fn, void *private_data)
valgrind_stack_id = VALGRIND_STACK_REGISTER(sp, stack_);
#endif
-#if USE_UCONTEXT
+#ifdef USE_UCONTEXT
if (-1 == getcontext(&ctx_)) {
swoole_throw_error(SW_ERROR_CO_GETCONTEXT_FAILED);
sw_free(stack_);
@@ -68,7 +68,7 @@ Context::Context(size_t stack_size, CoroutineFunc fn, void *private_data)
ctx_.uc_link = nullptr;
makecontext(&ctx_, (void (*)(void)) & context_func, 1, this);
#else
- ctx_ = swoole_make_fcontext(sp, stack_size_, (void (*)(intptr_t)) & context_func);
+ ctx_ = swoole_make_fcontext(sp, stack_size_, (void (*)(transfer_t)) & context_func);
swap_ctx_ = nullptr;
#endif
@@ -120,25 +120,32 @@ ssize_t Context::get_stack_usage() {
#endif
bool Context::swap_in() {
-#if USE_UCONTEXT
+#ifdef USE_UCONTEXT
return 0 == swapcontext(&swap_ctx_, &ctx_);
#else
- swoole_jump_fcontext(&swap_ctx_, ctx_, (intptr_t) this, true);
+ coroutine_transfer_t transfer_data = swoole_jump_fcontext(ctx_, (void *) this);
+ ctx_ = transfer_data.fctx;
return true;
#endif
}
bool Context::swap_out() {
-#if USE_UCONTEXT
+#ifdef USE_UCONTEXT
return 0 == swapcontext(&ctx_, &swap_ctx_);
#else
- swoole_jump_fcontext(&ctx_, swap_ctx_, (intptr_t) this, true);
+ coroutine_transfer_t transfer_data = swoole_jump_fcontext(swap_ctx_, (void *) this);
+ swap_ctx_ = transfer_data.fctx;
return true;
#endif
}
-void Context::context_func(void *arg) {
+void Context::context_func(coroutine_transfer_t arg) {
+#if defined(USE_UCONTEXT) || defined(SW_USE_THREAD_CONTEXT)
auto *_this = (Context *) arg;
+#else
+ auto *_this = (Context *) arg.data;
+ _this->swap_ctx_ = arg.fctx;
+#endif
_this->fn_(_this->private_data_);
_this->end_ = true;
_this->swap_out();
diff --git a/src/coroutine/hook.cc b/src/coroutine/hook.cc
index 96525bbd13f..3e2c5e7249a 100644
--- a/src/coroutine/hook.cc
+++ b/src/coroutine/hook.cc
@@ -213,11 +213,11 @@ int swoole_coroutine_socket_create(int fd) {
int _fd = socket->get_fd();
if (sw_unlikely(_fd < 0)) {
return -1;
- } else {
- std::unique_lock _lock(socket_map_lock);
- socket_map[fd] = socket;
- return 0;
}
+ socket->get_socket()->set_nonblock();
+ std::unique_lock _lock(socket_map_lock);
+ socket_map[fd] = socket;
+ return 0;
}
int swoole_coroutine_socket_unwrap(int fd) {
diff --git a/src/coroutine/thread_context.cc b/src/coroutine/thread_context.cc
index 8dc232249bf..b670d495719 100644
--- a/src/coroutine/thread_context.cc
+++ b/src/coroutine/thread_context.cc
@@ -88,7 +88,7 @@ bool Context::swap_out() {
return true;
}
-void Context::context_func(void *arg) {
+void Context::context_func(coroutine_transfer_t arg) {
swoole_signal_block_all();
Context *_this = (Context *) arg;
SwooleTG.reactor = g_reactor;
diff --git a/src/network/socket.cc b/src/network/socket.cc
index a201aa4854b..eac5107f3e9 100644
--- a/src/network/socket.cc
+++ b/src/network/socket.cc
@@ -441,6 +441,13 @@ bool Socket::set_timeout(double timeout) {
return set_recv_timeout(timeout) and set_send_timeout(timeout);
}
+Socket *Socket::dup() {
+ Socket *_socket = new Socket();
+ *_socket = *this;
+ _socket->fd = ::dup(fd);
+ return _socket;
+}
+
static bool _set_timeout(int fd, int type, double timeout) {
int ret;
struct timeval timeo;
diff --git a/src/os/async_thread.cc b/src/os/async_thread.cc
index c09d620de0a..8fca0974b9b 100644
--- a/src/os/async_thread.cc
+++ b/src/os/async_thread.cc
@@ -32,6 +32,9 @@
#include
#include
+static std::mutex async_thread_lock;
+static std::shared_ptr async_thread_pool;
+
namespace swoole {
namespace async {
//-------------------------------------------------------------------------------
@@ -82,6 +85,10 @@ class ThreadPool {
shutdown();
}
+ bool is_running() {
+ return running;
+ }
+
bool start() {
running = true;
current_task_id = 0;
@@ -110,16 +117,14 @@ class ThreadPool {
}
delete _thread;
}
+ threads.clear();
return true;
}
void schedule() {
if (n_waiting == 0 && threads.size() < worker_num && max_wait_time > 0) {
- event_mutex.lock();
double _max_wait_time = _queue.get_max_wait_time();
- event_mutex.unlock();
-
if (_max_wait_time > max_wait_time) {
size_t n = 1;
/**
@@ -141,14 +146,12 @@ class ThreadPool {
}
AsyncEvent *dispatch(const AsyncEvent *request) {
- if (SwooleTG.async_threads->schedule) {
- schedule();
- }
auto _event_copy = new AsyncEvent(*request);
+ event_mutex.lock();
+ schedule();
_event_copy->task_id = current_task_id++;
_event_copy->timestamp = microtime();
_event_copy->pipe_socket = SwooleTG.async_threads->write_socket;
- event_mutex.lock();
_queue.push(_event_copy);
_cv.notify_one();
event_mutex.unlock();
@@ -204,6 +207,7 @@ class ThreadPool {
private:
void create_thread(const bool is_core_worker = false);
+ void main_func(const bool is_core_worker);
size_t core_worker_num;
size_t worker_num;
@@ -221,102 +225,99 @@ class ThreadPool {
std::condition_variable _cv;
};
-void ThreadPool::create_thread(const bool is_core_worker) {
- try {
- std::thread *_thread = new std::thread([this, is_core_worker]() {
- bool exit_flag = false;
- SwooleTG.buffer_stack = new String(SW_STACK_BUFFER_SIZE);
- ON_SCOPE_EXIT {
- delete SwooleTG.buffer_stack;
- SwooleTG.buffer_stack = nullptr;
- };
-
- swoole_signal_block_all();
-
- while (running) {
- event_mutex.lock();
- AsyncEvent *event = _queue.pop();
- event_mutex.unlock();
-
- swoole_debug("%s: %f", event ? "pop 1 event" : "no event", microtime());
-
- if (event) {
- if (sw_unlikely(event->handler == nullptr)) {
- event->error = SW_ERROR_AIO_BAD_REQUEST;
- event->retval = -1;
- } else if (sw_unlikely(event->canceled)) {
- event->error = SW_ERROR_AIO_CANCELED;
- event->retval = -1;
- } else {
- event->handler(event);
- }
+void ThreadPool::main_func(bool is_core_worker) {
+ bool exit_flag = false;
+ swoole_thread_init();
- swoole_trace_log(SW_TRACE_AIO,
- "aio_thread %s. ret=%ld, error=%d",
- event->retval > 0 ? "ok" : "failed",
- event->retval,
- event->error);
-
- _send_event:
- while (true) {
- ssize_t ret = event->pipe_socket->write(&event, sizeof(event));
- if (ret < 0) {
- if (errno == EAGAIN) {
- event->pipe_socket->wait_event(1000, SW_EVENT_WRITE);
- continue;
- } else if (errno == EINTR) {
- continue;
- } else {
- delete event;
- swoole_sys_warning("sendto swoole_aio_pipe_write failed");
- }
- }
- break;
- }
+ while (running) {
+ event_mutex.lock();
+ AsyncEvent *event = _queue.pop();
+ event_mutex.unlock();
- // exit
- if (exit_flag) {
- n_closing--;
- break;
- }
- } else {
- std::unique_lock lock(event_mutex);
- if (_queue.count() > 0) {
+ swoole_debug("%s: %f", event ? "pop 1 event" : "no event", microtime());
+
+ if (event) {
+ if (sw_unlikely(event->handler == nullptr)) {
+ event->error = SW_ERROR_AIO_BAD_REQUEST;
+ event->retval = -1;
+ } else if (sw_unlikely(event->canceled)) {
+ event->error = SW_ERROR_AIO_CANCELED;
+ event->retval = -1;
+ } else {
+ event->handler(event);
+ }
+
+ swoole_trace_log(SW_TRACE_AIO,
+ "aio_thread %s. ret=%ld, error=%d",
+ event->retval > 0 ? "ok" : "failed",
+ event->retval,
+ event->error);
+
+ _send_event:
+ while (true) {
+ ssize_t ret = event->pipe_socket->write(&event, sizeof(event));
+ if (ret < 0) {
+ if (errno == EAGAIN) {
+ event->pipe_socket->wait_event(1000, SW_EVENT_WRITE);
+ continue;
+ } else if (errno == EINTR) {
continue;
- }
- if (!running) {
- break;
- }
- ++n_waiting;
- if (is_core_worker || max_idle_time <= 0) {
- _cv.wait(lock);
} else {
- while (true) {
- if (_cv.wait_for(lock, std::chrono::microseconds((size_t) (max_idle_time * 1000 * 1000))) ==
- std::cv_status::timeout) {
- if (running && n_closing != 0) {
- // wait for the next round
- continue;
- }
- /* notifies the main thread to release this thread */
- event = new AsyncEvent;
- event->object = new std::thread::id(std::this_thread::get_id());
- event->callback = release_callback;
- event->pipe_socket = SwooleG.aio_default_socket;
- event->canceled = false;
-
- --n_waiting;
- ++n_closing;
- exit_flag = true;
- goto _send_event;
- }
- break;
+ delete event;
+ swoole_sys_warning("sendto swoole_aio_pipe_write failed");
+ }
+ }
+ break;
+ }
+
+ // exit
+ if (exit_flag) {
+ n_closing--;
+ break;
+ }
+ } else {
+ std::unique_lock lock(event_mutex);
+ if (_queue.count() > 0) {
+ continue;
+ }
+ if (!running) {
+ break;
+ }
+ ++n_waiting;
+ if (is_core_worker || max_idle_time <= 0) {
+ _cv.wait(lock);
+ } else {
+ while (true) {
+ if (_cv.wait_for(lock, std::chrono::microseconds((size_t) (max_idle_time * 1000 * 1000))) ==
+ std::cv_status::timeout) {
+ if (running && n_closing != 0) {
+ // wait for the next round
+ continue;
}
+ /* notifies the main thread to release this thread */
+ event = new AsyncEvent;
+ event->object = new std::thread::id(std::this_thread::get_id());
+ event->callback = release_callback;
+ event->pipe_socket = SwooleG.aio_default_socket;
+ event->canceled = false;
+
+ --n_waiting;
+ ++n_closing;
+ exit_flag = true;
+ goto _send_event;
}
- --n_waiting;
+ break;
}
}
- });
+ --n_waiting;
+ }
+ }
+ swoole_thread_clean();
+}
+
+void ThreadPool::create_thread(const bool is_core_worker) {
+ try {
+ std::thread *_thread = new std::thread([this, is_core_worker]() { main_func(is_core_worker); });
threads[_thread->get_id()] = _thread;
} catch (const std::system_error &e) {
swoole_sys_notice("create aio thread failed, please check your system configuration or adjust aio_worker_num");
@@ -339,10 +340,6 @@ AsyncEvent *dispatch(const AsyncEvent *request) {
} // namespace async
int AsyncThreads::callback(Reactor *reactor, Event *event) {
- if (SwooleTG.async_threads->schedule) {
- SwooleTG.async_threads->pool->schedule();
- }
-
AsyncEvent *events[SW_AIO_EVENT_NUM];
ssize_t n = event->socket->read(events, sizeof(AsyncEvent *) * SW_AIO_EVENT_NUM);
if (n < 0) {
@@ -411,20 +408,32 @@ AsyncThreads::AsyncThreads() {
return true;
});
- init_lock.lock();
- pool = new async::ThreadPool(
- SwooleG.aio_core_worker_num, SwooleG.aio_worker_num, SwooleG.aio_max_wait_time, SwooleG.aio_max_idle_time);
- pool->start();
- schedule = true;
- init_lock.unlock();
+ async_thread_lock.lock();
+ if (!async_thread_pool) {
+ async_thread_pool = std::make_shared(
+ SwooleG.aio_core_worker_num, SwooleG.aio_worker_num, SwooleG.aio_max_wait_time, SwooleG.aio_max_idle_time);
+ }
+ if (!async_thread_pool->is_running()) {
+ async_thread_pool->start();
+ }
+ pool = async_thread_pool;
+ async_thread_lock.unlock();
SwooleG.aio_default_socket = write_socket;
SwooleTG.async_threads = this;
}
AsyncThreads::~AsyncThreads() {
- delete pool;
- pool = nullptr;
+ pool.reset();
+ async_thread_lock.lock();
+ /**
+ * When the reference count is 1, it means that all reactor threads have ended
+ * and all aio threads can be terminated.
+ */
+ if (async_thread_pool.use_count() == 1) {
+ async_thread_pool->shutdown();
+ }
+ async_thread_lock.unlock();
pipe->close();
read_socket = nullptr;
write_socket = nullptr;
diff --git a/src/os/msg_queue.cc b/src/os/msg_queue.cc
index f40e2c1a151..89d98448a07 100644
--- a/src/os/msg_queue.cc
+++ b/src/os/msg_queue.cc
@@ -86,7 +86,6 @@ bool MsgQueue::push(QueueNode *in, size_t mdata_length) {
}
swoole_set_last_error(errno);
break;
-
}
return false;
}
diff --git a/src/os/process_pool.cc b/src/os/process_pool.cc
index 8c6212ea0ae..b04db48cc49 100644
--- a/src/os/process_pool.cc
+++ b/src/os/process_pool.cc
@@ -25,6 +25,8 @@
#include "swoole_process_pool.h"
#include "swoole_client.h"
+SW_THREAD_LOCAL swoole::WorkerGlobal SwooleWG = {};
+
namespace swoole {
using network::Socket;
@@ -220,26 +222,22 @@ void ProcessPool::set_protocol(enum ProtocolType _protocol_type) {
protocol_type_ = _protocol_type;
}
-/**
- * start workers
- */
-int ProcessPool::start() {
+int ProcessPool::start_check() {
if (ipc_mode == SW_IPC_SOCKET && (stream_info_ == nullptr || stream_info_->socket == 0)) {
swoole_warning("must first listen to an tcp port");
return SW_ERR;
}
- uint32_t i;
running = started = true;
master_pid = getpid();
reload_workers = new Worker[worker_num]();
- SwooleG.process_type = SW_PROCESS_MASTER;
+ swoole_set_process_type(SW_PROCESS_MASTER);
if (async) {
main_loop = ProcessPool_worker_loop_async;
}
- for (i = 0; i < worker_num; i++) {
+ SW_LOOP_N(worker_num) {
workers[i].pool = this;
workers[i].id = start_id + i;
workers[i].type = type;
@@ -251,12 +249,21 @@ int ProcessPool::start() {
}
}
- for (i = 0; i < worker_num; i++) {
+ return SW_OK;
+}
+
+/**
+ * start workers
+ */
+int ProcessPool::start() {
+ if (start_check() < 0) {
+ return SW_ERR;
+ }
+ SW_LOOP_N(worker_num) {
if (spawn(&(workers[i])) < 0) {
return SW_ERR;
}
}
-
return SW_OK;
}
@@ -458,8 +465,9 @@ pid_t ProcessPool::spawn(Worker *worker) {
// child
case 0:
worker->pid = SwooleG.pid;
- SwooleG.process_id = worker->id;
- SwooleG.process_type = SW_PROCESS_WORKER;
+ swoole_set_process_type(SW_PROCESS_WORKER);
+ swoole_set_process_id(worker->id);
+ SwooleWG.worker = worker;
if (async) {
if (swoole_event_init(SW_EVENTLOOP_WAIT_EXIT) < 0) {
exit(254);
@@ -581,7 +589,7 @@ static int ProcessPool_worker_loop_with_task_protocol(ProcessPool *pool, Worker
continue;
}
- if (n != (ssize_t)(out.buf.info.len + sizeof(out.buf.info))) {
+ if (n != (ssize_t) (out.buf.info.len + sizeof(out.buf.info))) {
swoole_warning("bad task packet, The received data-length[%ld] is inconsistent with the packet-length[%ld]",
n,
out.buf.info.len + sizeof(out.buf.info));
@@ -811,7 +819,7 @@ bool ProcessPool::detach() {
WorkerStopMessage msg;
msg.pid = getpid();
- msg.worker_id = SwooleG.process_id;
+ msg.worker_id = swoole_get_process_id();
if (push_message(SW_WORKER_MESSAGE_STOP, &msg, sizeof(msg)) < 0) {
return false;
diff --git a/src/os/unix_socket.cc b/src/os/unix_socket.cc
index 08b34422dfb..c1db228dedd 100644
--- a/src/os/unix_socket.cc
+++ b/src/os/unix_socket.cc
@@ -18,8 +18,7 @@
#include "swoole_socket.h"
namespace swoole {
-UnixSocket::UnixSocket(bool blocking, int _protocol) :
- SocketPair(blocking), protocol_(_protocol) {
+UnixSocket::UnixSocket(bool blocking, int _protocol) : SocketPair(blocking), protocol_(_protocol) {
if (socketpair(AF_UNIX, protocol_, 0, socks) < 0) {
swoole_sys_warning("socketpair() failed");
return;
@@ -39,4 +38,4 @@ bool UnixSocket::set_buffer_size(size_t _size) {
}
return true;
}
-}
+} // namespace swoole
diff --git a/src/server/base.cc b/src/server/base.cc
index bdb5ef37e47..9ce1964e15b 100644
--- a/src/server/base.cc
+++ b/src/server/base.cc
@@ -18,8 +18,44 @@
namespace swoole {
+Factory *Server::create_base_factory() {
+ reactor_num = worker_num;
+ connection_list = (Connection *) sw_calloc(max_connection, sizeof(Connection));
+ if (connection_list == nullptr) {
+ swoole_sys_warning("calloc[2](%d) failed", (int) (max_connection * sizeof(Connection)));
+ return nullptr;
+ }
+ gs->connection_nums = (sw_atomic_t *) sw_shm_calloc(worker_num, sizeof(sw_atomic_t));
+ if (gs->connection_nums == nullptr) {
+ swoole_error("sw_shm_calloc(%ld) for gs->connection_nums failed", worker_num * sizeof(sw_atomic_t));
+ return nullptr;
+ }
+
+ for (auto port : ports) {
+ port->gs->connection_nums = (sw_atomic_t *) sw_shm_calloc(worker_num, sizeof(sw_atomic_t));
+ if (port->gs->connection_nums == nullptr) {
+ swoole_error("sw_shm_calloc(%ld) for port->connection_nums failed", worker_num * sizeof(sw_atomic_t));
+ return nullptr;
+ }
+ }
+
+ return new BaseFactory(this);
+}
+
+void Server::destroy_base_factory() {
+ sw_free(connection_list);
+ sw_shm_free((void *) gs->connection_nums);
+ for (auto port : ports) {
+ sw_shm_free((void *) port->gs->connection_nums);
+ }
+ gs->connection_nums = nullptr;
+}
+
+BaseFactory::BaseFactory(Server *server) : Factory(server) {}
+
+BaseFactory::~BaseFactory() {}
+
bool BaseFactory::start() {
- SwooleWG.run_always = true;
return true;
}
@@ -54,8 +90,9 @@ bool BaseFactory::dispatch(SendData *task) {
}
}
- server_->message_bus.pass(task);
- server_->worker_accept_event(&server_->message_bus.get_buffer()->info);
+ auto bus = server_->get_worker_message_bus();
+ bus->pass(task);
+ server_->worker_accept_event(&bus->get_buffer()->info);
return true;
}
@@ -89,7 +126,7 @@ bool BaseFactory::end(SessionId session_id, int flags) {
_send.info.fd = session_id;
_send.info.len = 0;
_send.info.type = SW_SERVER_EVENT_CLOSE;
- _send.info.reactor_id = SwooleG.process_id;
+ _send.info.reactor_id = swoole_get_process_id();
Session *session = server_->get_session(session_id);
if (!session->fd) {
@@ -100,7 +137,12 @@ bool BaseFactory::end(SessionId session_id, int flags) {
return false;
}
- if (session->reactor_id != SwooleG.process_id) {
+ if (server_->if_forward_message(session)) {
+ swoole_trace_log(SW_TRACE_SERVER,
+ "session_id=%ld, fd=%d, session->reactor_id=%d",
+ session_id,
+ session->fd,
+ session->reactor_id);
Worker *worker = server_->get_worker(session->reactor_id);
if (worker->pipe_master->send_async((const char *) &_send.info, sizeof(_send.info)) < 0) {
swoole_sys_warning("failed to send %lu bytes to pipe_master", sizeof(_send.info));
@@ -167,13 +209,17 @@ bool BaseFactory::finish(SendData *data) {
SessionId session_id = data->info.fd;
Session *session = server_->get_session(session_id);
- if (session->reactor_id != SwooleG.process_id) {
- swoole_trace("session->reactor_id=%d, SwooleG.process_id=%d", session->reactor_id, SwooleG.process_id);
+ if (server_->if_forward_message(session)) {
+ swoole_trace_log(SW_TRACE_SERVER,
+ "session_id=%ld, fd=%d, session->reactor_id=%d",
+ session_id,
+ session->fd,
+ session->reactor_id);
Worker *worker = server_->gs->event_workers.get_worker(session->reactor_id);
EventData proxy_msg{};
if (data->info.type == SW_SERVER_EVENT_SEND_DATA) {
- if (!server_->message_bus.write(worker->pipe_master, data)) {
+ if (!server_->get_worker_message_bus()->write(worker->pipe_master, data)) {
swoole_sys_warning("failed to send %u bytes to pipe_master", data->info.len);
return false;
}
@@ -194,6 +240,4 @@ bool BaseFactory::finish(SendData *data) {
}
}
-BaseFactory::~BaseFactory() {}
-
} // namespace swoole
diff --git a/src/server/manager.cc b/src/server/manager.cc
index 5c0bc36d09f..8d0f564ca78 100644
--- a/src/server/manager.cc
+++ b/src/server/manager.cc
@@ -114,7 +114,7 @@ int Server::start_manager_process() {
}
auto fn = [this](void) {
- SwooleG.process_type = SW_PROCESS_MANAGER;
+ swoole_set_process_type(SW_PROCESS_MANAGER);
gs->manager_pid = SwooleG.pid = getpid();
if (task_worker_num > 0) {
@@ -126,7 +126,7 @@ int Server::start_manager_process() {
SW_LOOP_N(worker_num) {
Worker *worker = get_worker(i);
- if (spawn_event_worker(worker) < 0) {
+ if (factory->spawn_event_worker(worker) < 0) {
swoole_sys_error("failed to fork event worker");
return;
}
@@ -134,7 +134,7 @@ int Server::start_manager_process() {
if (!user_worker_list.empty()) {
for (auto worker : user_worker_list) {
- if (spawn_user_worker(worker) < 0) {
+ if (factory->spawn_user_worker(worker) < 0) {
swoole_sys_error("failed to fork user worker");
return;
}
@@ -156,22 +156,6 @@ int Server::start_manager_process() {
return SW_OK;
}
-void Server::check_worker_exit_status(Worker *worker, const ExitStatus &exit_status) {
- if (exit_status.get_status() != 0) {
- swoole_warning("worker(pid=%d, id=%d) abnormal exit, status=%d, signal=%d"
- "%s",
- exit_status.get_pid(),
- worker->id,
- exit_status.get_code(),
- exit_status.get_signal(),
- exit_status.get_signal() == SIGSEGV ? SwooleG.bug_report_message.c_str() : "");
-
- if (onWorkerError != nullptr) {
- onWorkerError(this, worker, exit_status);
- }
- }
-}
-
void Manager::wait(Server *_server) {
server_ = _server;
server_->manager = this;
@@ -244,10 +228,10 @@ void Manager::wait(Server *_server) {
WorkerStopMessage worker_stop_msg;
memcpy(&worker_stop_msg, msg.data, sizeof(worker_stop_msg));
if (worker_stop_msg.worker_id >= _server->worker_num) {
- _server->spawn_task_worker(_server->get_worker(worker_stop_msg.worker_id));
+ _server->factory->spawn_task_worker(_server->get_worker(worker_stop_msg.worker_id));
} else {
Worker *worker = _server->get_worker(worker_stop_msg.worker_id);
- _server->spawn_event_worker(worker);
+ _server->factory->spawn_event_worker(worker);
}
}
pool->read_message = false;
@@ -339,10 +323,10 @@ void Manager::wait(Server *_server) {
}
// check the process return code and signal
- _server->check_worker_exit_status(worker, exit_status);
+ _server->factory->check_worker_exit_status(worker, exit_status);
do {
- if (_server->spawn_event_worker(worker) < 0) {
+ if (_server->factory->spawn_event_worker(worker) < 0) {
SW_START_SLEEP;
continue;
}
@@ -353,8 +337,8 @@ void Manager::wait(Server *_server) {
if (_server->gs->task_workers.map_) {
auto iter = _server->gs->task_workers.map_->find(exit_status.get_pid());
if (iter != _server->gs->task_workers.map_->end()) {
- _server->check_worker_exit_status(iter->second, exit_status);
- _server->spawn_task_worker(iter->second);
+ _server->factory->check_worker_exit_status(iter->second, exit_status);
+ _server->factory->spawn_task_worker(iter->second);
}
}
// user process
@@ -414,9 +398,9 @@ void Manager::wait(Server *_server) {
*/
alarm(_server->max_wait_time * 2);
}
- _server->kill_event_workers();
- _server->kill_task_workers();
- _server->kill_user_workers();
+ _server->factory->kill_event_workers();
+ _server->factory->kill_task_workers();
+ _server->factory->kill_user_workers();
// force kill
if (_server->max_wait_time) {
alarm(0);
@@ -493,16 +477,16 @@ int Server::wait_other_worker(ProcessPool *pool, const ExitStatus &exit_status)
return SW_ERR;
} while (0);
- serv->check_worker_exit_status(exit_worker, exit_status);
+ serv->factory->check_worker_exit_status(exit_worker, exit_status);
pid_t new_process_pid = -1;
switch (worker_type) {
case SW_PROCESS_TASKWORKER:
- new_process_pid = serv->spawn_task_worker(exit_worker);
+ new_process_pid = serv->factory->spawn_task_worker(exit_worker);
break;
case SW_PROCESS_USERWORKER:
- new_process_pid = serv->spawn_user_worker(exit_worker);
+ new_process_pid = serv->factory->spawn_user_worker(exit_worker);
break;
default:
/* never here */
@@ -543,116 +527,6 @@ void Server::read_worker_message(ProcessPool *pool, EventData *msg) {
serv->message_bus.write(serv->get_command_reply_socket(), &task);
}
-/**
- * kill and wait all user process
- */
-void Server::kill_user_workers() {
- if (user_worker_map.empty()) {
- return;
- }
-
- for (auto &kv : user_worker_map) {
- swoole_kill(kv.second->pid, SIGTERM);
- }
-
- for (auto &kv : user_worker_map) {
- int __stat_loc;
- if (swoole_waitpid(kv.second->pid, &__stat_loc, 0) < 0) {
- swoole_sys_warning("waitpid(%d) failed", kv.second->pid);
- }
- }
-}
-
-/**
- * [Manager] kill and wait all event worker process
- */
-void Server::kill_event_workers() {
- int status;
-
- if (worker_num == 0) {
- return;
- }
-
- SW_LOOP_N(worker_num) {
- swoole_trace("kill worker#%d[pid=%d]", workers[i].id, workers[i].pid);
- swoole_kill(workers[i].pid, SIGTERM);
- }
- SW_LOOP_N(worker_num) {
- swoole_trace("wait worker#%d[pid=%d]", workers[i].id, workers[i].pid);
- if (swoole_waitpid(workers[i].pid, &status, 0) < 0) {
- swoole_sys_warning("waitpid(%d) failed", workers[i].pid);
- }
- }
-}
-
-/**
- * [Manager] kill and wait task worker process
- */
-void Server::kill_task_workers() {
- if (task_worker_num == 0) {
- return;
- }
- gs->task_workers.shutdown();
-}
-
-pid_t Server::spawn_event_worker(Worker *worker) {
- pid_t pid = swoole_fork(0);
-
- if (pid < 0) {
- swoole_sys_warning("failed to fork event worker");
- return SW_ERR;
- } else if (pid == 0) {
- worker->pid = SwooleG.pid;
- } else {
- worker->pid = pid;
- return pid;
- }
-
- if (is_base_mode()) {
- gs->connection_nums[worker->id] = 0;
- gs->event_workers.main_loop(&gs->event_workers, worker);
- } else {
- start_event_worker(worker);
- }
-
- exit(0);
- return 0;
-}
-
-pid_t Server::spawn_user_worker(Worker *worker) {
- pid_t pid = swoole_fork(0);
- if (worker->pid) {
- user_worker_map.erase(worker->pid);
- }
- if (pid < 0) {
- swoole_sys_warning("Fork Worker failed");
- return SW_ERR;
- }
- // child
- else if (pid == 0) {
- SwooleG.process_type = SW_PROCESS_USERWORKER;
- SwooleG.process_id = worker->id;
- SwooleWG.worker = worker;
- worker->pid = SwooleG.pid;
- onUserWorkerStart(this, worker);
- exit(0);
- }
- // parent
- else {
- /**
- * worker: local memory
- * user_workers: shared memory
- */
- get_worker(worker->id)->pid = worker->pid = pid;
- user_worker_map.emplace(std::make_pair(pid, worker));
- return pid;
- }
-}
-
-pid_t Server::spawn_task_worker(Worker *worker) {
- return gs->task_workers.spawn(worker);
-}
-
bool Server::reload(bool reload_all_workers) {
if (gs->manager_pid == 0) {
return false;
diff --git a/src/server/master.cc b/src/server/master.cc
index 6c38338fb13..e41d8fa20d1 100644
--- a/src/server/master.cc
+++ b/src/server/master.cc
@@ -93,13 +93,13 @@ void Server::call_command_callback(int64_t request_id, const std::string &result
iter->second(this, result);
}
-ResultCode Server::call_command_handler(MessageBus &mb, uint16_t worker_id, Socket *sock) {
+void Server::call_command_handler(MessageBus &mb, uint16_t worker_id, Socket *sock) {
PipeBuffer *buffer = mb.get_buffer();
int command_id = buffer->info.server_fd;
auto iter = command_handlers.find(command_id);
if (iter == command_handlers.end()) {
swoole_error_log(SW_LOG_ERROR, SW_ERROR_SERVER_INVALID_COMMAND, "Unknown command[command_id=%d]", command_id);
- return SW_OK;
+ return;
}
Server::Command::Handler handler = iter->second;
@@ -114,7 +114,7 @@ ResultCode Server::call_command_handler(MessageBus &mb, uint16_t worker_id, Sock
task.info.len = result.length();
task.data = result.c_str();
- return mb.write(sock, &task) ? SW_OK : SW_ERR;
+ mb.write(sock, &task);
}
std::string Server::call_command_handler_in_master(int command_id, const std::string &msg) {
@@ -147,7 +147,7 @@ int Server::accept_command_result(Reactor *reactor, Event *event) {
int Server::accept_connection(Reactor *reactor, Event *event) {
Server *serv = (Server *) reactor->ptr;
- ListenPort *listen_host = serv->get_port_by_server_fd(event->fd);
+ ListenPort *listen_host = (ListenPort *) event->socket->object;
for (int i = 0; i < SW_ACCEPT_MAX_COUNT; i++) {
Socket *sock = event->socket->accept();
@@ -398,7 +398,7 @@ int Server::start_check() {
/**
* OpenSSL thread-safe
*/
- if (is_process_mode() && !single_thread) {
+ if ((is_process_mode() && !single_thread) || is_thread_mode()) {
swoole_ssl_init_thread_safety();
}
#endif
@@ -406,11 +406,9 @@ int Server::start_check() {
return SW_OK;
}
-int Server::start_master_thread() {
- SwooleTG.type = THREAD_MASTER;
- SwooleTG.id = single_thread ? 0 : reactor_num;
-
- Reactor *reactor = sw_reactor();
+int Server::start_master_thread(Reactor *reactor) {
+ swoole_set_thread_type(THREAD_MASTER);
+ swoole_set_thread_id(single_thread ? 0 : reactor_num);
if (SwooleTG.timer && SwooleTG.timer->get_reactor() == nullptr) {
SwooleTG.timer->reinit(reactor);
@@ -419,7 +417,7 @@ int Server::start_master_thread() {
init_signal_handler();
SwooleG.pid = getpid();
- SwooleG.process_type = SW_PROCESS_MASTER;
+ swoole_set_process_type(SW_PROCESS_MASTER);
reactor->ptr = this;
reactor->set_handler(SW_FD_STREAM_SERVER, Server::accept_connection);
@@ -443,7 +441,9 @@ int Server::start_master_thread() {
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
SW_START_SLEEP;
#else
- pthread_barrier_wait(&gs->manager_barrier);
+ if (is_process_mode()) {
+ pthread_barrier_wait(&gs->manager_barrier);
+ }
#endif
#else
SW_START_SLEEP;
@@ -471,6 +471,7 @@ void Server::store_listen_socket() {
connection_list[sockfd].socket_type = ls->type;
connection_list[sockfd].object = ls;
connection_list[sockfd].info.assign(ls->type, ls->host, ls->port);
+ ls->socket->object = ls;
if (sockfd >= 0) {
set_minfd(sockfd);
set_maxfd(sockfd);
@@ -560,30 +561,15 @@ void Server::destroy_worker(Worker *worker) {
* [Worker]
*/
void Server::init_worker(Worker *worker) {
-#ifdef HAVE_CPU_AFFINITY
- if (open_cpu_affinity) {
- cpu_set_t cpu_set;
- CPU_ZERO(&cpu_set);
- if (cpu_affinity_available_num) {
- CPU_SET(cpu_affinity_available[SwooleG.process_id % cpu_affinity_available_num], &cpu_set);
- } else {
- CPU_SET(SwooleG.process_id % SW_CPU_NUM, &cpu_set);
- }
- if (swoole_set_cpu_affinity(&cpu_set) < 0) {
- swoole_sys_warning("swoole_set_cpu_affinity() failed");
- }
- }
-#endif
-
if (max_request < 1) {
SwooleWG.run_always = true;
} else {
+ SwooleWG.run_always = false;
SwooleWG.max_request = max_request;
if (max_request_grace > 0) {
SwooleWG.max_request += swoole_system_random(1, max_request_grace);
}
}
-
worker->start_time = ::time(nullptr);
worker->request_count = 0;
}
@@ -698,8 +684,13 @@ int Server::start() {
int ret;
if (is_base_mode()) {
ret = start_reactor_processes();
- } else {
+ } else if (is_process_mode()) {
ret = start_reactor_threads();
+ } else if (is_thread_mode()) {
+ ret = start_worker_threads();
+ } else {
+ abort();
+ return SW_ERR;
}
// failed to start
if (ret < 0) {
@@ -717,8 +708,6 @@ int Server::start() {
* initializing server config, set default
*/
Server::Server(enum Mode _mode) {
- swoole_init();
-
reactor_num = SW_CPU_NUM > SW_REACTOR_MAX_THREAD ? SW_REACTOR_MAX_THREAD : SW_CPU_NUM;
worker_num = SW_CPU_NUM;
max_connection = SW_MIN(SW_MAX_CONNECTION, SwooleG.max_sockets);
@@ -760,14 +749,6 @@ int Server::create() {
return SW_ERR;
}
- if (is_base_mode()) {
- gs->connection_nums = (sw_atomic_t *) sw_shm_calloc(worker_num, sizeof(sw_atomic_t));
- if (gs->connection_nums == nullptr) {
- swoole_error("sw_shm_calloc(%ld) for gs->connection_nums failed", worker_num * sizeof(sw_atomic_t));
- return SW_ERR;
- }
- }
-
if (swoole_isset_hook(SW_GLOBAL_HOOK_BEFORE_SERVER_CREATE)) {
swoole_call_hook(SW_GLOBAL_HOOK_BEFORE_SERVER_CREATE, this);
}
@@ -787,13 +768,6 @@ int Server::create() {
int index = 0;
for (auto port : ports) {
port->gs = &port_gs_list[index++];
- if (is_base_mode()) {
- port->gs->connection_nums = (sw_atomic_t *) sw_shm_calloc(worker_num, sizeof(sw_atomic_t));
- if (port->gs->connection_nums == nullptr) {
- swoole_error("sw_shm_calloc(%ld) for port->connection_nums failed", worker_num * sizeof(sw_atomic_t));
- return SW_ERR;
- }
- }
}
if (enable_static_handler and locations == nullptr) {
@@ -850,17 +824,19 @@ int Server::create() {
return SW_ERR;
}
- int retval;
if (is_base_mode()) {
- factory = new BaseFactory(this);
- retval = create_reactor_processes();
+ factory = create_base_factory();
+ } else if (is_thread_mode()) {
+ factory = create_thread_factory();
} else {
- factory = new ProcessFactory(this);
- retval = create_reactor_threads();
+ factory = create_process_factory();
+ }
+ if (!factory) {
+ return SW_ERR;
}
#ifdef HAVE_PTHREAD_BARRIER
- if (is_process_mode()) {
+ if (is_process_mode() || is_thread_mode()) {
pthread_barrier_init(&reactor_thread_barrier, nullptr, reactor_num + 1);
#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__))
pthread_barrierattr_setpshared(&gs->manager_barrier_attr, PTHREAD_PROCESS_SHARED);
@@ -873,7 +849,7 @@ int Server::create() {
swoole_call_hook(SW_GLOBAL_HOOK_AFTER_SERVER_CREATE, this);
}
- return retval;
+ return SW_OK;
}
void Server::clear_timer() {
@@ -892,24 +868,107 @@ void Server::clear_timer() {
}
bool Server::shutdown() {
- swoole_trace_log(SW_TRACE_SERVER, "shutdown begin");
+ if (sw_unlikely(!is_started())) {
+ swoole_set_last_error(SW_ERROR_OPERATION_NOT_SUPPORT);
+ return false;
+ }
+
+ pid_t pid;
if (is_base_mode()) {
- if (gs->manager_pid > 0) {
- if (getpid() == gs->manager_pid) {
- running = false;
- return true;
- } else {
- return swoole_kill(gs->manager_pid, SIGTERM) == 0;
- }
+ pid = get_manager_pid() == 0 ? get_master_pid() : get_manager_pid();
+ } else if (is_thread_mode()) {
+ if (is_master_thread()) {
+ stop_master_thread();
} else {
- gs->event_workers.running = 0;
- stop_async_worker(SwooleWG.worker);
+ running = false;
+ }
+ return true;
+ } else {
+ pid = get_master_pid();
+ }
+
+ if (swoole_kill(pid, SIGTERM) < 0) {
+ swoole_error_log(
+ SW_LOG_WARNING, SW_ERROR_SYSTEM_CALL_FAIL, "failed to shutdown, kill(%d, SIGTERM) failed", pid);
+ return false;
+ }
+
+ return true;
+}
+
+bool Server::signal_handler_reload(bool reload_all_workers) {
+ reload(reload_all_workers);
+ sw_logger()->reopen();
+ return true;
+}
+
+bool Server::signal_handler_read_message() {
+ gs->event_workers.read_message = true;
+ return true;
+}
+
+bool Server::signal_handler_reopen_logger() {
+ uint32_t i;
+ Worker *worker;
+ for (i = 0; i < worker_num + task_worker_num + get_user_worker_num(); i++) {
+ worker = get_worker(i);
+ swoole_kill(worker->pid, SIGRTMIN);
+ }
+ if (is_process_mode()) {
+ swoole_kill(gs->manager_pid, SIGRTMIN);
+ }
+ sw_logger()->reopen();
+ return true;
+}
+
+void Server::stop_master_thread() {
+ Reactor *reactor = SwooleTG.reactor;
+ reactor->set_wait_exit(true);
+ for (auto port : ports) {
+ if (port->is_dgram() and is_process_mode()) {
+ continue;
+ }
+ reactor->del(port->socket);
+ }
+ if (pipe_command) {
+ reactor->del(pipe_command->get_socket(true));
+ }
+ clear_timer();
+ if (max_wait_time > 0) {
+ time_t shutdown_time = std::time(nullptr);
+ auto fn = [shutdown_time, this](Reactor *reactor, size_t &) {
+ time_t now = std::time(nullptr);
+ if (now - shutdown_time > max_wait_time) {
+ swoole_error_log(SW_LOG_WARNING,
+ SW_ERROR_SERVER_WORKER_EXIT_TIMEOUT,
+ "graceful shutdown failed, forced termination");
+ reactor->running = false;
+ }
return true;
+ };
+ reactor->set_exit_condition(Reactor::EXIT_CONDITION_FORCED_TERMINATION, fn);
+ }
+ if (is_thread_mode()) {
+ SW_LOOP_N(reactor_num) {
+ auto thread = get_thread(i);
+ DataHead ev = {};
+ ev.type = SW_SERVER_EVENT_SHUTDOWN;
+ thread->notify_pipe->send_blocking((void *) &ev, sizeof(ev));
}
}
+}
- if (getpid() != gs->master_pid) {
- return swoole_kill(gs->master_pid, SIGTERM) == 0;
+bool Server::signal_handler_shutdown() {
+ swoole_trace_log(SW_TRACE_SERVER, "shutdown begin");
+ if (is_base_mode()) {
+ if (gs->manager_pid > 0) {
+ running = false;
+ } else {
+ // single process worker, exit directly
+ gs->event_workers.running = 0;
+ stop_async_worker(sw_worker());
+ }
+ return true;
}
if (swoole_isset_hook(SW_GLOBAL_HOOK_BEFORE_SERVER_SHUTDOWN)) {
swoole_call_hook(SW_GLOBAL_HOOK_BEFORE_SERVER_SHUTDOWN, this);
@@ -918,40 +977,28 @@ bool Server::shutdown() {
onBeforeShutdown(this);
}
running = false;
- // stop all thread
- if (SwooleTG.reactor) {
- Reactor *reactor = SwooleTG.reactor;
- reactor->set_wait_exit(true);
- for (auto port : ports) {
- if (port->is_dgram() and is_process_mode()) {
- continue;
- }
- reactor->del(port->socket);
- }
- if (pipe_command) {
- reactor->del(pipe_command->get_socket(true));
- }
- clear_timer();
- if (max_wait_time > 0) {
- time_t shutdown_time = std::time(nullptr);
- auto fn = [shutdown_time, this](Reactor *reactor, size_t &) {
- time_t now = std::time(nullptr);
- if (now - shutdown_time > max_wait_time) {
- swoole_error_log(SW_LOG_WARNING,
- SW_ERROR_SERVER_WORKER_EXIT_TIMEOUT,
- "graceful shutdown failed, forced termination");
- reactor->running = false;
- }
- return true;
- };
- reactor->set_exit_condition(Reactor::EXIT_CONDITION_FORCED_TERMINATION, fn);
- }
- }
-
+ stop_master_thread();
swoole_trace_log(SW_TRACE_SERVER, "shutdown end");
return true;
}
+bool Server::signal_handler_child_exit() {
+ if (!running) {
+ return false;
+ }
+ if (is_base_mode()) {
+ return false;
+ }
+ int status;
+ pid_t pid = waitpid(-1, &status, WNOHANG);
+ if (pid > 0 && pid == gs->manager_pid) {
+ swoole_warning("Fatal Error: manager process exit. status=%d, signal=[%s]",
+ WEXITSTATUS(status),
+ swoole_signal_to_str(WTERMSIG(status)));
+ }
+ return true;
+}
+
void Server::destroy() {
swoole_trace_log(SW_TRACE_SERVER, "release service");
if (swoole_isset_hook(SW_GLOBAL_HOOK_AFTER_SERVER_SHUTDOWN)) {
@@ -970,7 +1017,7 @@ void Server::destroy() {
if (task_worker_num > 0) {
gs->task_workers.destroy();
}
- } else {
+ } else if (is_process_mode()) {
swoole_trace_log(SW_TRACE_SERVER, "terminate reactor threads");
/**
* Wait until all the end of the thread
@@ -978,7 +1025,7 @@ void Server::destroy() {
join_reactor_thread();
}
- release_pipe_buffers();
+ release_pipe_buffers();
for (auto port : ports) {
port->close();
@@ -1004,11 +1051,6 @@ void Server::destroy() {
if (onShutdown) {
onShutdown(this);
}
- if (is_base_mode()) {
- destroy_reactor_processes();
- } else {
- destroy_reactor_threads();
- }
SW_LOOP_N(SW_MAX_HOOK_TYPE) {
if (hooks[i]) {
std::list *l = reinterpret_cast *>(hooks[i]);
@@ -1026,23 +1068,21 @@ void Server::destroy() {
}
#endif
- for (auto port : ports) {
- if (port->gs->connection_nums) {
- sw_shm_free((void *) port->gs->connection_nums);
- }
+ if (is_base_mode()) {
+ destroy_base_factory();
+ } else if (is_thread_mode()) {
+ destroy_thread_factory();
+ } else {
+ destroy_process_factory();
}
sw_shm_free(session_list);
sw_shm_free(port_gs_list);
sw_shm_free(workers);
- if (gs->connection_nums) {
- sw_shm_free((void *) gs->connection_nums);
- }
session_list = nullptr;
port_gs_list = nullptr;
workers = nullptr;
- gs->connection_nums = nullptr;
delete factory;
factory = nullptr;
@@ -1083,7 +1123,7 @@ bool Server::command(WorkerId process_id,
if (is_process_mode() && !is_master()) {
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_INVALID_PARAMS, "command() can only be used in master process");
return false;
- } else if (is_base_mode() && SwooleWG.worker->id != 0) {
+ } else if (is_base_mode() && sw_worker()->id != 0) {
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_INVALID_PARAMS, "command() can only be used in worker process 0");
return false;
}
@@ -1217,8 +1257,8 @@ bool Server::send(SessionId session_id, const void *data, uint32_t length) {
sw_atomic_fetch_add(&port->gs->response_count, 1);
sw_atomic_fetch_add(&port->gs->total_send_bytes, length);
}
- if (SwooleWG.worker) {
- SwooleWG.worker->response_count++;
+ if (sw_worker()) {
+ sw_worker()->response_count++;
}
return true;
}
@@ -1334,7 +1374,7 @@ int Server::send_to_connection(SendData *_send) {
assert(fd % reactor_num == SwooleTG.id);
}
- if (is_base_mode() && conn->overflow) {
+ if (!is_process_mode() && conn->overflow) {
if (send_yield) {
swoole_set_last_error(SW_ERROR_OUTPUT_SEND_YIELD);
} else {
@@ -1515,7 +1555,7 @@ bool Server::sendfile(SessionId session_id, const char *file, uint32_t l_file, o
"sendfile name[%.8s...] length %u is exceed the max name len %u",
file,
l_file,
- (uint32_t)(SW_IPC_BUFFER_SIZE - sizeof(SendfileTask) - 1));
+ (uint32_t) (SW_IPC_BUFFER_SIZE - sizeof(SendfileTask) - 1));
return false;
}
// string must be zero termination (for `state` system call)
@@ -1596,7 +1636,9 @@ void Server::init_signal_handler() {
// for test
swoole_signal_set(SIGVTALRM, Server_signal_handler);
- set_minfd(SwooleG.signal_fd);
+ if (SwooleG.signal_fd > 0) {
+ set_minfd(SwooleG.signal_fd);
+ }
}
void Server::timer_callback(Timer *timer, TimerNode *tnode) {
@@ -1617,6 +1659,11 @@ void Server::timer_callback(Timer *timer, TimerNode *tnode) {
if (serv->hooks[Server::HOOK_MASTER_TIMER]) {
serv->call_hook(Server::HOOK_MASTER_TIMER, serv);
}
+
+ if (!serv->is_running()) {
+ sw_reactor()->running = false;
+ serv->stop_master_thread();
+ }
}
int Server::add_worker(Worker *worker) {
@@ -1635,7 +1682,7 @@ bool Server::add_command(const std::string &name, int accepted_process_types, co
if (commands.find(name) != commands.end()) {
return false;
}
- if (is_process_mode() && pipe_command == nullptr) {
+ if (!is_base_mode() && pipe_command == nullptr) {
auto _pipe = new UnixSocket(false, SOCK_DGRAM);
if (!_pipe->ready()) {
delete _pipe;
@@ -1769,7 +1816,7 @@ ListenPort *Server::add_port(SocketType type, const char *host, int port) {
#ifdef SW_USE_OPENSSL
if (type & SW_SOCK_SSL) {
- type = (SocketType)(type & (~SW_SOCK_SSL));
+ type = (SocketType) (type & (~SW_SOCK_SSL));
ls->type = type;
ls->ssl = 1;
ls->ssl_context = new SSLContext();
@@ -1784,7 +1831,6 @@ ListenPort *Server::add_port(SocketType type, const char *host, int port) {
#ifdef SW_SUPPORT_DTLS
ls->ssl_context->protocols = SW_SSL_DTLS;
ls->dtls_sessions = new std::unordered_map;
-
#else
swoole_warning("DTLS support require openssl-1.1 or later");
return nullptr;
@@ -1793,24 +1839,11 @@ ListenPort *Server::add_port(SocketType type, const char *host, int port) {
}
#endif
- ls->socket = make_socket(
- ls->type, ls->is_dgram() ? SW_FD_DGRAM_SERVER : SW_FD_STREAM_SERVER, SW_SOCK_CLOEXEC | SW_SOCK_NONBLOCK);
- if (ls->socket == nullptr) {
+ if (ls->create_socket(this) < 0) {
swoole_set_last_error(errno);
return nullptr;
}
-#if defined(SW_SUPPORT_DTLS) && defined(HAVE_KQUEUE)
- if (ls->is_dtls()) {
- ls->socket->set_reuse_port();
- }
-#endif
- if (ls->socket->bind(ls->host, &ls->port) < 0) {
- swoole_set_last_error(errno);
- ls->socket->free();
- return nullptr;
- }
- ls->socket->info.assign(ls->type, ls->host, ls->port);
check_port_type(ls);
ptr.release();
ports.push_back(ls);
@@ -1825,51 +1858,27 @@ static void Server_signal_handler(int sig) {
return;
}
- int status;
- pid_t pid;
switch (sig) {
case SIGTERM:
- serv->shutdown();
+ serv->signal_handler_shutdown();
break;
case SIGCHLD:
- if (!serv->running) {
- break;
- }
- if (sw_server()->is_base_mode()) {
- break;
- }
- pid = waitpid(-1, &status, WNOHANG);
- if (pid > 0 && pid == serv->gs->manager_pid) {
- swoole_warning("Fatal Error: manager process exit. status=%d, signal=[%s]",
- WEXITSTATUS(status),
- swoole_signal_to_str(WTERMSIG(status)));
- }
+ serv->signal_handler_child_exit();
break;
case SIGVTALRM:
swoole_warning("SIGVTALRM coming");
break;
case SIGUSR1:
case SIGUSR2:
- serv->reload(sig == SIGUSR1);
- sw_logger()->reopen();
+ serv->signal_handler_reload(sig == SIGUSR1);
break;
case SIGIO:
- serv->gs->event_workers.read_message = true;
+ serv->signal_handler_read_message();
break;
default:
-
#ifdef SIGRTMIN
if (sig == SIGRTMIN) {
- uint32_t i;
- Worker *worker;
- for (i = 0; i < serv->worker_num + serv->task_worker_num + serv->get_user_worker_num(); i++) {
- worker = serv->get_worker(i);
- swoole_kill(worker->pid, SIGRTMIN);
- }
- if (serv->is_process_mode()) {
- swoole_kill(serv->gs->manager_pid, SIGRTMIN);
- }
- sw_logger()->reopen();
+ serv->signal_handler_reopen_logger();
}
#endif
break;
@@ -1902,7 +1911,7 @@ Connection *Server::add_connection(ListenPort *ls, Socket *_socket, int server_f
int fd = _socket->fd;
Connection *connection = &(connection_list[fd]);
- ReactorId reactor_id = is_base_mode() ? SwooleG.process_id : fd % reactor_num;
+ ReactorId reactor_id = is_base_mode() ? swoole_get_process_id() : fd % reactor_num;
*connection = {};
sw_spinlock(&gs->spinlock);
@@ -1934,7 +1943,7 @@ Connection *Server::add_connection(ListenPort *ls, Socket *_socket, int server_f
// TCP Nodelay
if (ls->open_tcp_nodelay && (ls->type == SW_SOCK_TCP || ls->type == SW_SOCK_TCP6)) {
- if (ls->socket->set_tcp_nodelay() != 0) {
+ if (_socket->set_tcp_nodelay() != 0) {
swoole_sys_warning("setsockopt(TCP_NODELAY) failed");
}
_socket->enable_tcp_nodelay = true;
@@ -2016,7 +2025,7 @@ int Server::create_pipe_buffers() {
}
void Server::release_pipe_buffers() {
- message_bus.free_buffer();
+ message_bus.free_buffer();
}
int Server::get_idle_worker_num() {
diff --git a/src/server/port.cc b/src/server/port.cc
index a302c869102..393b06d6073 100644
--- a/src/server/port.cc
+++ b/src/server/port.cc
@@ -780,7 +780,7 @@ const char *ListenPort::get_protocols() {
}
}
-size_t ListenPort::get_connection_num() {
+size_t ListenPort::get_connection_num() const {
if (gs->connection_nums) {
size_t num = 0;
for (uint32_t i = 0; i < sw_server()->worker_num; i++) {
@@ -792,4 +792,56 @@ size_t ListenPort::get_connection_num() {
}
}
+int ListenPort::create_socket(Server *server) {
+ if (socket) {
+#if defined(__linux__) && defined(HAVE_REUSEPORT)
+ if (server->enable_reuse_port) {
+ close_socket();
+ } else
+#endif
+ {
+ return SW_OK;
+ }
+ }
+
+ socket = make_socket(
+ type, is_dgram() ? SW_FD_DGRAM_SERVER : SW_FD_STREAM_SERVER, SW_SOCK_CLOEXEC | SW_SOCK_NONBLOCK);
+ if (socket == nullptr) {
+ swoole_set_last_error(errno);
+ return SW_ERR;
+ }
+
+#if defined(SW_SUPPORT_DTLS) && defined(HAVE_KQUEUE)
+ if (is_dtls()) {
+ socket->set_reuse_port();
+ }
+#endif
+
+#if defined(__linux__) && defined(HAVE_REUSEPORT)
+ if (server->enable_reuse_port) {
+ if (socket->set_reuse_port() < 0) {
+ socket->free();
+ return SW_ERR;
+ }
+ }
+#endif
+
+ if (socket->bind(host, &port) < 0) {
+ swoole_set_last_error(errno);
+ socket->free();
+ return SW_ERR;
+ }
+
+ socket->info.assign(type, host, port);
+ return SW_OK;
+}
+
+void ListenPort::close_socket() {
+ if (::close(socket->fd) < 0) {
+ swoole_sys_warning("close(%d) failed", socket->fd);
+ }
+ delete socket;
+ socket = nullptr;
+}
+
} // namespace swoole
diff --git a/src/server/process.cc b/src/server/process.cc
index e95c35e7d71..409111fa89d 100644
--- a/src/server/process.cc
+++ b/src/server/process.cc
@@ -14,16 +14,169 @@
+----------------------------------------------------------------------+
*/
-#include
-
#include "swoole_server.h"
namespace swoole {
using network::Socket;
+Factory *Server::create_process_factory() {
+ /**
+ * init reactor thread pool
+ */
+ reactor_threads = new ReactorThread[reactor_num]();
+ /**
+ * alloc the memory for connection_list
+ */
+ connection_list = (Connection *) sw_shm_calloc(max_connection, sizeof(Connection));
+ if (connection_list == nullptr) {
+ swoole_error("calloc[1] failed");
+ return nullptr;
+ }
+ reactor_pipe_num = worker_num / reactor_num;
+ return new ProcessFactory(this);
+}
+
+void Server::destroy_process_factory() {
+ sw_shm_free(connection_list);
+ delete[] reactor_threads;
+
+ if (gs->event_workers.message_box) {
+ gs->event_workers.message_box->destroy();
+ }
+}
+
ProcessFactory::ProcessFactory(Server *server) : Factory(server) {}
+ProcessFactory::~ProcessFactory() {}
+
+/**
+ * kill and wait all user process
+ */
+void Factory::kill_user_workers() {
+ if (server_->user_worker_map.empty()) {
+ return;
+ }
+
+ for (auto &kv : server_->user_worker_map) {
+ swoole_kill(kv.second->pid, SIGTERM);
+ }
+
+ for (auto &kv : server_->user_worker_map) {
+ int __stat_loc;
+ if (swoole_waitpid(kv.second->pid, &__stat_loc, 0) < 0) {
+ swoole_sys_warning("waitpid(%d) failed", kv.second->pid);
+ }
+ }
+}
+
+/**
+ * [Manager] kill and wait all event worker process
+ */
+void Factory::kill_event_workers() {
+ int status;
+
+ if (server_->worker_num == 0) {
+ return;
+ }
+
+ SW_LOOP_N(server_->worker_num) {
+ swoole_trace_log(SW_TRACE_SERVER, "kill worker#%d[pid=%d]", server_->workers[i].id, server_->workers[i].pid);
+ swoole_kill(server_->workers[i].pid, SIGTERM);
+ }
+ SW_LOOP_N(server_->worker_num) {
+ swoole_trace_log(SW_TRACE_SERVER, "wait worker#%d[pid=%d]", server_->workers[i].id, server_->workers[i].pid);
+ if (swoole_waitpid(server_->workers[i].pid, &status, 0) < 0) {
+ swoole_sys_warning("waitpid(%d) failed", server_->workers[i].pid);
+ }
+ }
+}
+
+/**
+ * [Manager] kill and wait task worker process
+ */
+void Factory::kill_task_workers() {
+ if (server_->task_worker_num == 0) {
+ return;
+ }
+ server_->gs->task_workers.shutdown();
+}
+
+pid_t Factory::spawn_event_worker(Worker *worker) {
+ pid_t pid = swoole_fork(0);
+
+ if (pid < 0) {
+ swoole_sys_warning("failed to fork event worker");
+ return SW_ERR;
+ } else if (pid == 0) {
+ worker->pid = SwooleG.pid;
+ SwooleWG.worker = worker;
+ } else {
+ worker->pid = pid;
+ return pid;
+ }
+
+ if (server_->is_base_mode()) {
+ server_->gs->connection_nums[worker->id] = 0;
+ server_->gs->event_workers.main_loop(&server_->gs->event_workers, worker);
+ } else {
+ server_->start_event_worker(worker);
+ }
+
+ exit(0);
+ return 0;
+}
+
+pid_t Factory::spawn_user_worker(Worker *worker) {
+ pid_t pid = swoole_fork(0);
+ if (worker->pid) {
+ server_->user_worker_map.erase(worker->pid);
+ }
+ if (pid < 0) {
+ swoole_sys_warning("Fork Worker failed");
+ return SW_ERR;
+ }
+ // child
+ else if (pid == 0) {
+ swoole_set_process_type(SW_PROCESS_USERWORKER);
+ swoole_set_process_id(worker->id);
+ worker->pid = SwooleG.pid;
+ SwooleWG.worker = worker;
+ server_->onUserWorkerStart(server_, worker);
+ exit(0);
+ }
+ // parent
+ else {
+ /**
+ * worker: local memory
+ * user_workers: shared memory
+ */
+ server_->get_worker(worker->id)->pid = worker->pid = pid;
+ server_->user_worker_map.emplace(std::make_pair(pid, worker));
+ return pid;
+ }
+}
+
+pid_t Factory::spawn_task_worker(Worker *worker) {
+ return server_->gs->task_workers.spawn(worker);
+}
+
+void Factory::check_worker_exit_status(Worker *worker, const ExitStatus &exit_status) {
+ if (exit_status.get_status() != 0) {
+ swoole_warning("worker(pid=%d, id=%d) abnormal exit, status=%d, signal=%d"
+ "%s",
+ exit_status.get_pid(),
+ worker->id,
+ exit_status.get_code(),
+ exit_status.get_signal(),
+ exit_status.get_signal() == SIGSEGV ? SwooleG.bug_report_message.c_str() : "");
+
+ if (server_->onWorkerError != nullptr) {
+ server_->onWorkerError(server_, worker, exit_status);
+ }
+ }
+}
+
bool ProcessFactory::shutdown() {
int status;
@@ -38,27 +191,31 @@ bool ProcessFactory::shutdown() {
return SW_OK;
}
-ProcessFactory::~ProcessFactory() {}
-
-bool ProcessFactory::start() {
- SW_LOOP_N(server_->worker_num) {
+bool Server::create_worker_pipes() {
+ SW_LOOP_N(worker_num) {
auto _sock = new UnixSocket(true, SOCK_DGRAM);
if (!_sock->ready()) {
delete _sock;
return false;
}
- pipes.emplace_back(_sock);
- server_->workers[i].pipe_master = _sock->get_socket(true);
- server_->workers[i].pipe_worker = _sock->get_socket(false);
- server_->workers[i].pipe_object = _sock;
+ worker_pipes.emplace_back(_sock);
+ workers[i].pipe_master = _sock->get_socket(true);
+ workers[i].pipe_worker = _sock->get_socket(false);
+ workers[i].pipe_object = _sock;
}
- server_->init_ipc_max_size();
- if (server_->create_pipe_buffers() < 0) {
+ init_ipc_max_size();
+ if (create_pipe_buffers() < 0) {
return false;
}
+ return true;
+}
+bool ProcessFactory::start() {
+ if (!server_->create_worker_pipes()) {
+ return false;
+ }
return server_->start_manager_process() == SW_OK;
}
@@ -128,7 +285,7 @@ static bool inline process_is_supported_send_yield(Server *serv, Connection *con
if (!serv->is_hash_dispatch_mode()) {
return false;
} else {
- return serv->schedule_worker(conn->fd, nullptr) == (int) SwooleG.process_id;
+ return serv->schedule_worker(conn->fd, nullptr) == (int) swoole_get_process_id();
}
}
@@ -185,7 +342,7 @@ bool ProcessFactory::finish(SendData *resp) {
memcpy(&task, resp, sizeof(SendData));
task.info.fd = session_id;
task.info.reactor_id = conn->reactor_id;
- task.info.server_fd = SwooleG.process_id;
+ task.info.server_fd = swoole_get_process_id();
swoole_trace("worker_id=%d, type=%d", SwooleG.process_id, task.info.type);
@@ -227,7 +384,7 @@ bool ProcessFactory::end(SessionId session_id, int flags) {
if (conn->close_actively) {
bool hash = server_->is_hash_dispatch_mode();
int worker_id = hash ? server_->schedule_worker(conn->fd, nullptr) : conn->fd % server_->worker_num;
- if (server_->is_worker() && (!hash || worker_id == (int) SwooleG.process_id)) {
+ if (server_->is_worker() && (!hash || worker_id == (int) swoole_get_process_id())) {
goto _close;
}
worker = server_->get_worker(worker_id);
diff --git a/src/server/reactor_process.cc b/src/server/reactor_process.cc
index 446e03f032f..d4c9370d33a 100644
--- a/src/server/reactor_process.cc
+++ b/src/server/reactor_process.cc
@@ -20,32 +20,13 @@
namespace swoole {
using network::Socket;
-static int ReactorProcess_loop(ProcessPool *pool, Worker *worker);
static int ReactorProcess_onPipeRead(Reactor *reactor, Event *event);
static int ReactorProcess_onClose(Reactor *reactor, Event *event);
static void ReactorProcess_onTimeout(Timer *timer, TimerNode *tnode);
-#ifdef HAVE_REUSEPORT
-static int ReactorProcess_reuse_port(ListenPort *ls);
-#endif
-
static bool Server_is_single(Server *serv) {
- return serv->worker_num == 1 && serv->task_worker_num == 0 && serv->max_request == 0 &&
- serv->user_worker_list.empty();
-}
-
-int Server::create_reactor_processes() {
- reactor_num = worker_num;
- connection_list = (Connection *) sw_calloc(max_connection, sizeof(Connection));
- if (connection_list == nullptr) {
- swoole_sys_warning("calloc[2](%d) failed", (int) (max_connection * sizeof(Connection)));
- return SW_ERR;
- }
- return SW_OK;
-}
-
-void Server::destroy_reactor_processes() {
- sw_free(connection_list);
+ return (serv->worker_num == 1 && serv->task_worker_num == 0 && serv->max_request == 0 &&
+ serv->user_worker_list.empty());
}
int Server::start_reactor_processes() {
@@ -54,24 +35,19 @@ int Server::start_reactor_processes() {
// listen TCP
if (have_stream_sock == 1) {
for (auto ls : ports) {
- if (ls->is_dgram()) {
- continue;
- }
-#ifdef HAVE_REUSEPORT
- if (enable_reuse_port) {
- if (::close(ls->socket->fd) < 0) {
- swoole_sys_warning("close(%d) failed", ls->socket->fd);
- }
- delete ls->socket;
- ls->socket = nullptr;
- continue;
- } else
+ if (ls->is_stream()) {
+#if defined(__linux__) && defined(HAVE_REUSEPORT)
+ if (!enable_reuse_port) {
#endif
- {
- // listen server socket
- if (ls->listen() < 0) {
- return SW_ERR;
+ // listen server socket
+ if (ls->listen() < 0) {
+ return SW_ERR;
+ }
+#if defined(__linux__) && defined(HAVE_REUSEPORT)
+ } else {
+ ls->close_socket();
}
+#endif
}
}
}
@@ -89,8 +65,8 @@ int Server::start_reactor_processes() {
gs->event_workers.ptr = this;
gs->event_workers.max_wait_time = max_wait_time;
gs->event_workers.use_msgqueue = 0;
- gs->event_workers.main_loop = ReactorProcess_loop;
- gs->event_workers.onWorkerNotFound = Server::wait_other_worker;
+ gs->event_workers.main_loop = worker_main_loop;
+ gs->event_workers.onWorkerNotFound = wait_other_worker;
memcpy(workers, gs->event_workers.workers, sizeof(*workers) * worker_num);
gs->event_workers.workers = workers;
@@ -106,7 +82,9 @@ int Server::start_reactor_processes() {
}
if (Server_is_single(this)) {
- int retval = ReactorProcess_loop(&gs->event_workers, &gs->event_workers.workers[0]);
+ Worker *worker = &gs->event_workers.workers[0];
+ SwooleWG.worker = worker;
+ int retval = worker_main_loop(&gs->event_workers, worker);
if (retval == SW_OK) {
gs->event_workers.destroy();
}
@@ -160,7 +138,7 @@ static int ReactorProcess_onPipeRead(Reactor *reactor, Event *event) {
break;
}
case SW_SERVER_EVENT_COMMAND_REQUEST: {
- serv->call_command_handler(serv->message_bus, SwooleWG.worker->id, serv->get_worker(0)->pipe_master);
+ serv->call_command_handler(serv->message_bus, sw_worker()->id, serv->get_worker(0)->pipe_master);
break;
}
case SW_SERVER_EVENT_COMMAND_RESPONSE: {
@@ -178,18 +156,16 @@ static int ReactorProcess_onPipeRead(Reactor *reactor, Event *event) {
return SW_OK;
}
-static int ReactorProcess_loop(ProcessPool *pool, Worker *worker) {
+int Server::worker_main_loop(ProcessPool *pool, Worker *worker) {
Server *serv = (Server *) pool->ptr;
-
- SwooleG.process_type = SW_PROCESS_WORKER;
SwooleG.pid = getpid();
+ swoole_set_process_type(SW_PROCESS_WORKER);
+ swoole_set_process_id(worker->id);
- SwooleG.process_id = worker->id;
if (serv->max_request > 0) {
SwooleWG.run_always = false;
}
SwooleWG.max_request = serv->max_request;
- SwooleWG.worker = worker;
SwooleTG.id = 0;
serv->init_worker(worker);
@@ -206,15 +182,19 @@ static int ReactorProcess_loop(ProcessPool *pool, Worker *worker) {
SwooleTG.timer->reinit(reactor);
}
- Server::worker_signal_init();
+ serv->worker_signal_init();
for (auto ls : serv->ports) {
-#ifdef HAVE_REUSEPORT
+#if defined(__linux__) and defined(HAVE_REUSEPORT)
if (ls->is_stream() && serv->enable_reuse_port) {
- if (ReactorProcess_reuse_port(ls) < 0) {
+ if (ls->create_socket(serv) < 0) {
swoole_event_free();
return SW_ERR;
}
+
+ if (ls->listen() < 0) {
+ return SW_ERR;
+ }
}
#endif
if (reactor->add(ls->socket, SW_EVENT_READ) < 0) {
@@ -226,11 +206,11 @@ static int ReactorProcess_loop(ProcessPool *pool, Worker *worker) {
reactor->ptr = serv;
reactor->max_socket = serv->get_max_connection();
- reactor->close = Server::close_connection;
+ reactor->close = close_connection;
// set event handler
// connect
- reactor->set_handler(SW_FD_STREAM_SERVER, Server::accept_connection);
+ reactor->set_handler(SW_FD_STREAM_SERVER, accept_connection);
// close
reactor->default_error_handler = ReactorProcess_onClose;
// pipe
@@ -268,7 +248,7 @@ static int ReactorProcess_loop(ProcessPool *pool, Worker *worker) {
}
}
- if ((serv->master_timer = swoole_timer_add(1000L, true, Server::timer_callback, serv)) == nullptr) {
+ if ((serv->master_timer = swoole_timer_add(1000L, true, timer_callback, serv)) == nullptr) {
_fail:
swoole_event_free();
return SW_ERR;
@@ -297,11 +277,11 @@ static int ReactorProcess_loop(ProcessPool *pool, Worker *worker) {
/**
* call internal serv hooks
*/
- if (serv->isset_hook(Server::HOOK_WORKER_CLOSE)) {
+ if (serv->isset_hook(HOOK_WORKER_CLOSE)) {
void *hook_args[2];
hook_args[0] = serv;
- hook_args[1] = (void *) (uintptr_t) SwooleG.process_id;
- serv->call_hook(Server::HOOK_WORKER_CLOSE, hook_args);
+ hook_args[1] = (void *) (uintptr_t) worker->id;
+ serv->call_hook(HOOK_WORKER_CLOSE, hook_args);
}
swoole_event_free();
@@ -365,21 +345,4 @@ static void ReactorProcess_onTimeout(Timer *timer, TimerNode *tnode) {
ReactorProcess_onClose(reactor, ¬ify_ev);
});
}
-
-#ifdef HAVE_REUSEPORT
-static int ReactorProcess_reuse_port(ListenPort *ls) {
- ls->socket = swoole::make_socket(
- ls->type, ls->is_dgram() ? SW_FD_DGRAM_SERVER : SW_FD_STREAM_SERVER, SW_SOCK_CLOEXEC | SW_SOCK_NONBLOCK);
- if (ls->socket->set_reuse_port() < 0) {
- ls->socket->free();
- return SW_ERR;
- }
- if (ls->socket->bind(ls->host, &ls->port) < 0) {
- ls->socket->free();
- return SW_ERR;
- }
- return ls->listen();
-}
-#endif
-
} // namespace swoole
diff --git a/src/server/reactor_thread.cc b/src/server/reactor_thread.cc
index 1f5e3335f7f..881f4ee2bdc 100644
--- a/src/server/reactor_thread.cc
+++ b/src/server/reactor_thread.cc
@@ -26,14 +26,12 @@ using std::unordered_map;
namespace swoole {
using namespace network;
-static void ReactorThread_loop(Server *serv, int reactor_id);
static int ReactorThread_onPipeWrite(Reactor *reactor, Event *ev);
static int ReactorThread_onPipeRead(Reactor *reactor, Event *ev);
static int ReactorThread_onRead(Reactor *reactor, Event *ev);
static int ReactorThread_onWrite(Reactor *reactor, Event *ev);
static int ReactorThread_onPacketReceived(Reactor *reactor, Event *event);
static int ReactorThread_onClose(Reactor *reactor, Event *event);
-static void ReactorThread_shutdown(Reactor *reactor);
static void ReactorThread_resume_data_receiving(Timer *timer, TimerNode *tnode);
#ifdef SW_USE_OPENSSL
@@ -303,7 +301,7 @@ static int ReactorThread_onClose(Reactor *reactor, Event *event) {
}
}
-static void ReactorThread_shutdown(Reactor *reactor) {
+void ReactorThread::shutdown(Reactor *reactor) {
Server *serv = (Server *) reactor->ptr;
// stop listen UDP Port
if (serv->have_dgram_sock == 1) {
@@ -317,6 +315,10 @@ static void ReactorThread_shutdown(Reactor *reactor) {
}
}
+ if (serv->is_thread_mode()) {
+ reactor->del(serv->get_worker(reactor->id)->pipe_worker);
+ }
+
serv->foreach_connection([serv, reactor](Connection *conn) {
if (conn->fd % serv->reactor_num != reactor->id) {
return;
@@ -329,6 +331,39 @@ static void ReactorThread_shutdown(Reactor *reactor) {
reactor->set_wait_exit(true);
}
+int ReactorThread::close_connection(Reactor *reactor, SessionId session_id) {
+ Server *serv = (Server *) reactor->ptr;
+ Connection *conn = serv->get_connection_verify_no_ssl(session_id);
+ if (!conn) {
+ swoole_error_log(SW_LOG_TRACE,
+ SW_ERROR_SESSION_NOT_EXIST,
+ "force close connection failed, session#%ld does not exist",
+ session_id);
+ return SW_OK;
+ }
+
+ if (serv->disable_notify || conn->close_force) {
+ return Server::close_connection(reactor, conn->socket);
+ }
+
+#ifdef SW_USE_OPENSSL
+ /**
+ * SSL connections that have not completed the handshake,
+ * do not need to notify the workers, just close
+ */
+ if (conn->ssl && !conn->ssl_ready) {
+ return Server::close_connection(reactor, conn->socket);
+ }
+#endif
+ conn->close_force = 1;
+ Event _ev = {};
+ _ev.fd = conn->fd;
+ _ev.socket = conn->socket;
+ reactor->trigger_close_event(&_ev);
+
+ return SW_OK;
+}
+
/**
* receive data from worker process pipe
*/
@@ -346,45 +381,21 @@ static int ReactorThread_onPipeRead(Reactor *reactor, Event *ev) {
if (resp->info.type == SW_SERVER_EVENT_INCOMING) {
Connection *conn = serv->get_connection_verify_no_ssl(resp->info.fd);
if (conn && serv->connection_incoming(reactor, conn) < 0) {
- return reactor->close(reactor, conn->socket);
+ reactor->close(reactor, conn->socket);
}
} else if (resp->info.type == SW_SERVER_EVENT_COMMAND_REQUEST) {
- return serv->call_command_handler(thread->message_bus, thread->id, thread->pipe_command);
+ serv->call_command_handler(thread->message_bus, thread->id, thread->pipe_command);
} else if (resp->info.type == SW_SERVER_EVENT_COMMAND_RESPONSE) {
auto packet = thread->message_bus.get_packet();
serv->call_command_callback(resp->info.fd, std::string(packet.data, packet.length));
- return SW_OK;
} else if (resp->info.type == SW_SERVER_EVENT_SHUTDOWN) {
- ReactorThread_shutdown(reactor);
+ thread->shutdown(reactor);
+ } else if (resp->info.type == SW_SERVER_EVENT_FINISH) {
+ serv->onFinish(serv, (EventData *) resp);
+ } else if (resp->info.type == SW_SERVER_EVENT_PIPE_MESSAGE) {
+ serv->onPipeMessage(serv, (EventData *) resp);
} else if (resp->info.type == SW_SERVER_EVENT_CLOSE_FORCE) {
- SessionId session_id = resp->info.fd;
- Connection *conn = serv->get_connection_verify_no_ssl(session_id);
- if (!conn) {
- swoole_error_log(SW_LOG_TRACE,
- SW_ERROR_SESSION_NOT_EXIST,
- "force close connection failed, session#%ld does not exist",
- session_id);
- return SW_OK;
- }
-
- if (serv->disable_notify || conn->close_force) {
- return Server::close_connection(reactor, conn->socket);
- }
-
-#ifdef SW_USE_OPENSSL
- /**
- * SSL connections that have not completed the handshake,
- * do not need to notify the workers, just close
- */
- if (conn->ssl && !conn->ssl_ready) {
- return Server::close_connection(reactor, conn->socket);
- }
-#endif
- conn->close_force = 1;
- Event _ev = {};
- _ev.fd = conn->fd;
- _ev.socket = conn->socket;
- reactor->trigger_close_event(&_ev);
+ thread->close_connection(reactor, resp->info.fd);
} else {
PacketPtr packet = thread->message_bus.get_packet();
_send.info = resp->info;
@@ -630,23 +641,6 @@ static int ReactorThread_onWrite(Reactor *reactor, Event *ev) {
return SW_OK;
}
-int Server::create_reactor_threads() {
- /**
- * init reactor thread pool
- */
- reactor_threads = new ReactorThread[reactor_num]();
- /**
- * alloc the memory for connection_list
- */
- connection_list = (Connection *) sw_shm_calloc(max_connection, sizeof(Connection));
- if (connection_list == nullptr) {
- swoole_error("calloc[1] failed");
- return SW_ERR;
- }
- reactor_pipe_num = worker_num / reactor_num;
- return SW_OK;
-}
-
/**
* [master]
*/
@@ -687,7 +681,11 @@ int Server::start_reactor_threads() {
}
SW_LOOP_N(reactor_num) {
- get_thread(i)->thread = std::thread(ReactorThread_loop, this, i);
+ get_thread(i)->thread = std::thread([=]() {
+ swoole_thread_init();
+ reactor_thread_main_loop(this, i);
+ swoole_thread_clean();
+ });
}
_init_master_thread:
@@ -699,7 +697,7 @@ int Server::start_reactor_threads() {
start_heartbeat_thread();
}
- return start_master_thread();
+ return start_master_thread(reactor);
}
int ReactorThread::init(Server *serv, Reactor *reactor, uint16_t reactor_id) {
@@ -745,6 +743,13 @@ int ReactorThread::init(Server *serv, Reactor *reactor, uint16_t reactor_id) {
}
serv->init_reactor(reactor);
+ if (serv->is_thread_mode()) {
+ Worker *worker = serv->get_worker(reactor_id);
+ serv->init_worker(worker);
+ worker->pipe_worker->set_nonblock();
+ worker->pipe_worker->buffer_size = UINT_MAX;
+ reactor->add(worker->pipe_worker, SW_EVENT_READ);
+ }
int max_pipe_fd = serv->get_worker(serv->worker_num - 1)->pipe_master->fd + 2;
pipe_sockets = (Socket *) sw_calloc(max_pipe_fd, sizeof(Socket));
@@ -791,47 +796,31 @@ int ReactorThread::init(Server *serv, Reactor *reactor, uint16_t reactor_id) {
return SW_OK;
}
-/**
- * ReactorThread main Loop
- */
-static void ReactorThread_loop(Server *serv, int reactor_id) {
+void ReactorThread::clean() {
+ sw_free(pipe_sockets);
+ if (pipe_command) {
+ pipe_command->fd = -1;
+ delete pipe_command;
+ }
+ message_bus.free_buffer();
+}
+
+void Server::reactor_thread_main_loop(Server *serv, int reactor_id) {
SwooleTG.id = reactor_id;
SwooleTG.type = Server::THREAD_REACTOR;
- SwooleTG.buffer_stack = new String(SW_STACK_BUFFER_SIZE);
- ON_SCOPE_EXIT {
- delete SwooleTG.buffer_stack;
- SwooleTG.buffer_stack = nullptr;
- };
-
if (swoole_event_init(0) < 0) {
return;
}
+ if (serv->is_thread_mode()) {
+ serv->call_worker_start_callback(serv->get_worker(reactor_id));
+ }
+
ReactorThread *thread = serv->get_thread(reactor_id);
thread->id = reactor_id;
Reactor *reactor = sw_reactor();
-#ifdef HAVE_CPU_AFFINITY
- // cpu affinity setting
- if (serv->open_cpu_affinity) {
- cpu_set_t cpu_set;
- CPU_ZERO(&cpu_set);
-
- if (serv->cpu_affinity_available_num) {
- CPU_SET(serv->cpu_affinity_available[reactor_id % serv->cpu_affinity_available_num], &cpu_set);
- } else {
- CPU_SET(reactor_id % SW_CPU_NUM, &cpu_set);
- }
-
- if (0 != pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set)) {
- swoole_sys_warning("pthread_setaffinity_np() failed");
- }
- }
-#endif
-
- swoole_signal_block_all();
-
if (thread->init(serv, reactor, reactor_id) < 0) {
return;
}
@@ -844,11 +833,10 @@ static void ReactorThread_loop(Server *serv, int reactor_id) {
#endif
// main loop
swoole_event_wait();
- sw_free(thread->pipe_sockets);
- if (thread->pipe_command) {
- thread->pipe_command->fd = -1;
- delete thread->pipe_command;
+ if (serv->is_thread_mode()) {
+ serv->worker_stop_callback(serv->get_worker(reactor_id));
}
+ thread->clean();
}
static void ReactorThread_resume_data_receiving(Timer *timer, TimerNode *tnode) {
@@ -954,15 +942,6 @@ void Server::join_reactor_thread() {
}
}
-void Server::destroy_reactor_threads() {
- sw_shm_free(connection_list);
- delete[] reactor_threads;
-
- if (gs->event_workers.message_box) {
- gs->event_workers.message_box->destroy();
- }
-}
-
void Server::start_heartbeat_thread() {
heartbeat_thread = std::thread([this]() {
swoole_signal_block_all();
diff --git a/src/server/static_handler.cc b/src/server/static_handler.cc
index 50bce294e30..b5b45af2562 100644
--- a/src/server/static_handler.cc
+++ b/src/server/static_handler.cc
@@ -327,7 +327,7 @@ void StaticHandler::parse_range(const char *range, const char *if_range) {
}
while (*p >= '0' && *p <= '9') {
- if (start >= cutoff && (start > cutoff || (size_t)(*p - '0') > cutlim)) {
+ if (start >= cutoff && (start > cutoff || (size_t) (*p - '0') > cutlim)) {
status_code = SW_HTTP_RANGE_NOT_SATISFIABLE;
return;
}
@@ -364,7 +364,7 @@ void StaticHandler::parse_range(const char *range, const char *if_range) {
}
while (*p >= '0' && *p <= '9') {
- if (end >= cutoff && (end > cutoff || (size_t)(*p - '0') > cutlim)) {
+ if (end >= cutoff && (end > cutoff || (size_t) (*p - '0') > cutlim)) {
status_code = SW_HTTP_RANGE_NOT_SATISFIABLE;
return;
}
diff --git a/src/server/task_worker.cc b/src/server/task_worker.cc
index 6923e3a832f..b7046907294 100644
--- a/src/server/task_worker.cc
+++ b/src/server/task_worker.cc
@@ -72,7 +72,7 @@ static int TaskWorker_call_command_handler(ProcessPool *pool, EventData *req) {
SendData task{};
task.info.fd = req->info.fd;
- task.info.reactor_id = SwooleWG.worker->id;
+ task.info.reactor_id = sw_worker()->id;
task.info.server_fd = -1;
task.info.type = SW_SERVER_EVENT_COMMAND_RESPONSE;
task.info.len = result.length();
@@ -100,8 +100,8 @@ static int TaskWorker_onTask(ProcessPool *pool, EventData *task) {
bool Server::task_pack(EventData *task, const void *_data, size_t _length) {
task->info.type = SW_SERVER_EVENT_TASK;
task->info.fd = SwooleG.current_task_id++;
- task->info.reactor_id = SwooleG.process_id;
- task->info.time = swoole::microtime();
+ task->info.reactor_id = swoole_get_process_id();
+ task->info.time = microtime();
if (_length < SW_IPC_MAX_SIZE - sizeof(task->info)) {
memcpy(task->data, _data, _length);
@@ -160,6 +160,10 @@ bool Server::task_unpack(EventData *task, String *buffer, PacketPtr *packet) {
}
static void TaskWorker_signal_init(ProcessPool *pool) {
+ Server *serv = (Server *) pool->ptr;
+ if (serv->is_thread_mode()) {
+ return;
+ }
swoole_signal_set(SIGHUP, nullptr);
swoole_signal_set(SIGPIPE, nullptr);
swoole_signal_set(SIGUSR1, Server::worker_signal_handler);
@@ -172,7 +176,7 @@ static void TaskWorker_signal_init(ProcessPool *pool) {
static void TaskWorker_onStart(ProcessPool *pool, Worker *worker) {
Server *serv = (Server *) pool->ptr;
- SwooleG.process_id = worker->id;
+ swoole_set_process_id(worker->id);
/**
* Make the task worker support asynchronous
@@ -193,8 +197,7 @@ static void TaskWorker_onStart(ProcessPool *pool, Worker *worker) {
worker->start_time = ::time(nullptr);
worker->request_count = 0;
- SwooleWG.worker = worker;
- SwooleWG.worker->status = SW_WORKER_IDLE;
+ worker->status = SW_WORKER_IDLE;
/**
* task_max_request
*/
@@ -218,7 +221,7 @@ static void TaskWorker_onStop(ProcessPool *pool, Worker *worker) {
static int TaskWorker_onPipeReceive(Reactor *reactor, Event *event) {
EventData task;
ProcessPool *pool = (ProcessPool *) reactor->ptr;
- Worker *worker = SwooleWG.worker;
+ Worker *worker = sw_worker();
Server *serv = (Server *) pool->ptr;
if (event->socket->read(&task, sizeof(task)) > 0) {
diff --git a/src/server/thread.cc b/src/server/thread.cc
new file mode 100644
index 00000000000..c576ce903e0
--- /dev/null
+++ b/src/server/thread.cc
@@ -0,0 +1,237 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 "swoole_server.h"
+#include "swoole_memory.h"
+
+namespace swoole {
+using network::Socket;
+
+Factory *Server::create_thread_factory() {
+ reactor_num = worker_num;
+ connection_list = (Connection *) sw_calloc(max_connection, sizeof(Connection));
+ if (connection_list == nullptr) {
+ swoole_sys_warning("calloc[2](%d) failed", (int) (max_connection * sizeof(Connection)));
+ return nullptr;
+ }
+ reactor_threads = new ReactorThread[reactor_num]();
+ reactor_pipe_num = 1;
+ return new ThreadFactory(this);
+}
+
+void Server::destroy_thread_factory() {
+ sw_free(connection_list);
+ delete[] reactor_threads;
+}
+
+ThreadFactory::ThreadFactory(Server *server) : BaseFactory(server) {
+ threads_.resize(server_->task_worker_num + server_->worker_num + server_->get_user_worker_num() + 1);
+}
+
+bool ThreadFactory::start() {
+ if (!server_->create_worker_pipes()) {
+ return false;
+ }
+ if (server_->task_worker_num > 0 &&
+ (server_->create_task_workers() < 0 || server_->gs->task_workers.start_check() < 0)) {
+ return false;
+ }
+ if (server_->get_user_worker_num() > 0 && server_->create_user_workers() < 0) {
+ return false;
+ }
+ return true;
+}
+
+bool ThreadFactory::shutdown() {
+ for (auto &thread : threads_) {
+ if (thread.joinable()) {
+ thread.join();
+ }
+ }
+ return true;
+}
+
+ThreadFactory::~ThreadFactory() {
+
+}
+
+void ThreadFactory::at_thread_exit(Worker *worker) {
+ std::unique_lock _lock(lock_);
+ queue_.push(worker);
+ cv_.notify_one();
+}
+
+template
+void ThreadFactory::create_thread(int i, _Callable fn) {
+ if (threads_[i].joinable()) {
+ threads_[i].join();
+ }
+ threads_[i] = std::thread(fn);
+}
+
+void ThreadFactory::spawn_event_worker(WorkerId i) {
+ create_thread(i, [=]() {
+ swoole_set_process_type(SW_PROCESS_EVENTWORKER);
+ swoole_set_thread_type(Server::THREAD_WORKER);
+ swoole_set_process_id(i);
+ swoole_set_thread_id(i);
+ Worker *worker = server_->get_worker(i);
+ worker->type = SW_PROCESS_EVENTWORKER;
+ SwooleWG.worker = worker;
+ server_->worker_thread_start([=]() { Server::reactor_thread_main_loop(server_, i); });
+ at_thread_exit(worker);
+ });
+}
+
+void ThreadFactory::spawn_task_worker(WorkerId i) {
+ create_thread(i, [=]() {
+ swoole_set_process_type(SW_PROCESS_TASKWORKER);
+ swoole_set_thread_type(Server::THREAD_WORKER);
+ swoole_set_process_id(i);
+ swoole_set_thread_id(i);
+ Worker *worker = server_->get_worker(i);
+ worker->type = SW_PROCESS_TASKWORKER;
+ worker->status = SW_WORKER_IDLE;
+ SwooleWG.worker = worker;
+ auto pool = &server_->gs->task_workers;
+ server_->worker_thread_start([=]() {
+ if (pool->onWorkerStart != nullptr) {
+ pool->onWorkerStart(pool, worker);
+ }
+ pool->main_loop(pool, worker);
+ if (pool->onWorkerStop != nullptr) {
+ pool->onWorkerStop(pool, worker);
+ }
+ });
+ at_thread_exit(worker);
+ });
+}
+
+void ThreadFactory::spawn_user_worker(WorkerId i) {
+ create_thread(i, [=]() {
+ Worker *worker = server_->user_worker_list.at(i - server_->task_worker_num - server_->worker_num);
+ swoole_set_process_type(SW_PROCESS_USERWORKER);
+ swoole_set_thread_type(Server::THREAD_WORKER);
+ swoole_set_process_id(i);
+ swoole_set_thread_id(i);
+ worker->type = SW_PROCESS_USERWORKER;
+ SwooleWG.worker = worker;
+ server_->worker_thread_start([=]() { server_->onUserWorkerStart(server_, worker); });
+ at_thread_exit(worker);
+ });
+}
+
+void ThreadFactory::spawn_manager_thread(WorkerId i) {
+ create_thread(i, [=]() {
+ swoole_set_process_type(SW_PROCESS_MANAGER);
+ swoole_set_thread_type(Server::THREAD_WORKER);
+ swoole_set_process_id(i);
+ swoole_set_thread_id(i);
+ manager.id = i;
+ manager.type = SW_PROCESS_MANAGER;
+ server_->worker_thread_start([=]() {
+ if (server_->onManagerStart) {
+ server_->onManagerStart(server_);
+ }
+ wait();
+ if (server_->onManagerStop) {
+ server_->onManagerStop(server_);
+ }
+ });
+ if (server_->running) {
+ swoole_warning("Fatal Error: manager thread exits abnormally");
+ }
+ });
+}
+
+void ThreadFactory::wait() {
+ while (server_->running) {
+ std::unique_lock _lock(lock_);
+ if (!queue_.empty()) {
+ Worker *exited_worker = queue_.front();
+ queue_.pop();
+ switch (exited_worker->type) {
+ case SW_PROCESS_EVENTWORKER:
+ spawn_event_worker(exited_worker->id);
+ break;
+ case SW_PROCESS_TASKWORKER:
+ spawn_task_worker(exited_worker->id);
+ break;
+ case SW_PROCESS_USERWORKER:
+ spawn_user_worker(exited_worker->id);
+ break;
+ default:
+ abort();
+ break;
+ }
+ _lock.unlock();
+ } else {
+ cv_.wait(_lock);
+ }
+ }
+}
+
+int Server::start_worker_threads() {
+ /**
+ * heartbeat thread
+ */
+ if (heartbeat_check_interval >= 1) {
+ start_heartbeat_thread();
+ }
+
+ ThreadFactory *_factory = dynamic_cast(factory);
+
+ if (task_worker_num > 0) {
+ SW_LOOP_N(task_worker_num) {
+ _factory->spawn_task_worker(worker_num + i);
+ }
+ }
+
+ SW_LOOP_N(worker_num) {
+ _factory->spawn_event_worker(i);
+ }
+
+ if (!user_worker_list.empty()) {
+ int i = 0;
+ for (auto worker : user_worker_list) {
+ _factory->spawn_user_worker(task_worker_num + worker_num + i);
+ i++;
+ }
+ }
+
+ int manager_thread_id = task_worker_num + worker_num + get_user_worker_num();
+ _factory->spawn_manager_thread(manager_thread_id);
+
+ if (swoole_event_init(0) < 0) {
+ return SW_ERR;
+ }
+ Reactor *reactor = sw_reactor();
+ for (auto iter = ports.begin(); iter != ports.end(); iter++) {
+ auto port = *iter;
+ if (port->is_dgram()) {
+ continue;
+ }
+ if (port->listen() < 0) {
+ swoole_event_free();
+ return SW_ERR;
+ }
+ reactor->add(port->socket, SW_EVENT_READ);
+ }
+ SwooleTG.id = reactor->id = manager_thread_id + 1;
+ store_listen_socket();
+ return start_master_thread(reactor);
+}
+} // namespace swoole
diff --git a/src/server/worker.cc b/src/server/worker.cc
index f75cb1c6b25..585350ae08d 100644
--- a/src/server/worker.cc
+++ b/src/server/worker.cc
@@ -24,8 +24,6 @@
#include "swoole_msg_queue.h"
#include "swoole_coroutine.h"
-swoole::WorkerGlobal SwooleWG = {};
-
namespace swoole {
using namespace network;
@@ -33,6 +31,9 @@ static int Worker_onPipeReceive(Reactor *reactor, Event *event);
static void Worker_reactor_try_to_exit(Reactor *reactor);
void Server::worker_signal_init(void) {
+ if (is_thread_mode()) {
+ return;
+ }
swoole_signal_set(SIGHUP, nullptr);
swoole_signal_set(SIGPIPE, SIG_IGN);
swoole_signal_set(SIGUSR1, nullptr);
@@ -47,17 +48,14 @@ void Server::worker_signal_init(void) {
}
void Server::worker_signal_handler(int signo) {
- if (!SwooleG.running || !sw_server()) {
+ if (!SwooleG.running || !sw_server() || !sw_worker()) {
return;
}
switch (signo) {
case SIGTERM:
- // Event worker
- if (swoole_event_is_available()) {
- sw_server()->stop_async_worker(SwooleWG.worker);
- }
- // Task worker
- else {
+ if (swoole_event_is_available()) { // Event worker
+ sw_server()->stop_async_worker(sw_worker());
+ } else { // Task worker
SwooleWG.shutdown = true;
}
break;
@@ -107,7 +105,7 @@ typedef std::function TaskCallback;
static sw_inline void Worker_do_task(Server *serv, Worker *worker, DataHead *info, const TaskCallback &callback) {
RecvData recv_data;
- auto packet = serv->message_bus.get_packet();
+ auto packet = serv->get_worker_message_bus()->get_packet();
recv_data.info = *info;
recv_data.info.len = packet.length;
recv_data.data = packet.data;
@@ -119,7 +117,7 @@ static sw_inline void Worker_do_task(Server *serv, Worker *worker, DataHead *inf
}
void Server::worker_accept_event(DataHead *info) {
- Worker *worker = SwooleWG.worker;
+ Worker *worker = sw_worker();
// worker busy
worker->status = SW_WORKER_BUSY;
@@ -128,7 +126,7 @@ void Server::worker_accept_event(DataHead *info) {
Connection *conn = get_connection_verify(info->fd);
if (conn) {
if (info->len > 0) {
- auto packet = message_bus.get_packet();
+ auto packet = get_worker_message_bus()->get_packet();
sw_atomic_fetch_sub(&conn->recv_queued_bytes, packet.length);
swoole_trace_log(SW_TRACE_SERVER,
"[Worker] session_id=%ld, len=%lu, qb=%d",
@@ -164,7 +162,7 @@ void Server::worker_accept_event(DataHead *info) {
if (info->len > 0) {
Connection *conn = get_connection_verify_no_ssl(info->fd);
if (conn) {
- auto packet = message_bus.get_packet();
+ auto packet = get_worker_message_bus()->get_packet();
conn->ssl_client_cert = new String(packet.data, packet.length);
conn->ssl_client_cert_pid = SwooleG.pid;
}
@@ -189,11 +187,11 @@ void Server::worker_accept_event(DataHead *info) {
break;
}
case SW_SERVER_EVENT_FINISH: {
- onFinish(this, (EventData *) message_bus.get_buffer());
+ onFinish(this, (EventData *) get_worker_message_bus()->get_buffer());
break;
}
case SW_SERVER_EVENT_PIPE_MESSAGE: {
- onPipeMessage(this, (EventData *) message_bus.get_buffer());
+ onPipeMessage(this, (EventData *) get_worker_message_bus()->get_buffer());
break;
}
case SW_SERVER_EVENT_COMMAND_REQUEST: {
@@ -215,10 +213,10 @@ void Server::worker_accept_event(DataHead *info) {
}
void Server::worker_start_callback(Worker *worker) {
- if (SwooleG.process_id >= worker_num) {
- SwooleG.process_type = SW_PROCESS_TASKWORKER;
+ if (swoole_get_process_id() >= worker_num) {
+ swoole_set_process_type(SW_PROCESS_TASKWORKER);
} else {
- SwooleG.process_type = SW_PROCESS_WORKER;
+ swoole_set_process_type(SW_PROCESS_WORKER);
}
int is_root = !geteuid();
@@ -261,7 +259,7 @@ void Server::worker_start_callback(Worker *worker) {
}
SW_LOOP_N(worker_num + task_worker_num) {
- if (SwooleG.process_id == i) {
+ if (worker->id == i) {
continue;
}
Worker *other_worker = get_worker(i);
@@ -274,7 +272,6 @@ void Server::worker_start_callback(Worker *worker) {
sw_logger()->reopen();
}
- SwooleWG.worker = worker;
worker->status = SW_WORKER_IDLE;
if (is_process_mode()) {
@@ -287,17 +284,22 @@ void Server::worker_start_callback(Worker *worker) {
void Server::worker_stop_callback(Worker *worker) {
void *hook_args[2];
hook_args[0] = this;
- hook_args[1] = (void *) (uintptr_t) SwooleG.process_id;
+ hook_args[1] = (void *) (uintptr_t) worker->id;
if (swoole_isset_hook(SW_GLOBAL_HOOK_BEFORE_WORKER_STOP)) {
swoole_call_hook(SW_GLOBAL_HOOK_BEFORE_WORKER_STOP, hook_args);
}
if (onWorkerStop) {
onWorkerStop(this, worker);
}
- if (!message_bus.empty()) {
+ if (!get_worker_message_bus()->empty()) {
swoole_error_log(
SW_LOG_WARNING, SW_ERROR_SERVER_WORKER_UNPROCESSED_DATA, "unprocessed data in the worker process buffer");
- message_bus.clear();
+ get_worker_message_bus()->clear();
+ }
+ if (SwooleWG.worker_copy) {
+ delete SwooleWG.worker_copy;
+ SwooleWG.worker_copy = nullptr;
+ SwooleWG.worker = nullptr;
}
}
@@ -320,8 +322,8 @@ void Server::stop_async_worker(Worker *worker) {
}
// Separated from the event worker process pool
- worker = (Worker *) sw_malloc(sizeof(*worker));
- *worker = *SwooleWG.worker;
+ SwooleWG.worker_copy = new Worker{};
+ *SwooleWG.worker_copy = *worker;
SwooleWG.worker = worker;
if (worker->pipe_worker && !worker->pipe_worker->removed) {
@@ -354,7 +356,7 @@ void Server::stop_async_worker(Worker *worker) {
} else {
WorkerStopMessage msg;
msg.pid = SwooleG.pid;
- msg.worker_id = SwooleG.process_id;
+ msg.worker_id = worker->id;
if (gs->event_workers.push_message(SW_WORKER_MESSAGE_STOP, &msg, sizeof(msg)) < 0) {
running = 0;
@@ -373,7 +375,7 @@ void Server::stop_async_worker(Worker *worker) {
static void Worker_reactor_try_to_exit(Reactor *reactor) {
Server *serv;
- if (SwooleG.process_type == SW_PROCESS_TASKWORKER) {
+ if (swoole_get_process_type() == SW_PROCESS_TASKWORKER) {
ProcessPool *pool = (ProcessPool *) reactor->ptr;
serv = (Server *) pool->ptr;
} else {
@@ -387,7 +389,7 @@ static void Worker_reactor_try_to_exit(Reactor *reactor) {
break;
} else {
if (serv->onWorkerExit && call_worker_exit_func == 0) {
- serv->onWorkerExit(serv, SwooleWG.worker);
+ serv->onWorkerExit(serv, sw_worker());
call_worker_exit_func = 1;
continue;
}
@@ -426,8 +428,8 @@ void Server::drain_worker_pipe() {
* main loop [Worker]
*/
int Server::start_event_worker(Worker *worker) {
- // worker_id
- SwooleG.process_id = worker->id;
+ swoole_set_process_id(worker->id);
+ swoole_set_process_type(SW_PROCESS_EVENTWORKER);
init_worker(worker);
@@ -504,14 +506,14 @@ ssize_t Server::send_to_worker_from_worker(Worker *dst_worker, const void *buf,
*/
static int Worker_onPipeReceive(Reactor *reactor, Event *event) {
Server *serv = (Server *) reactor->ptr;
- PipeBuffer *pipe_buffer = serv->message_bus.get_buffer();
+ PipeBuffer *pipe_buffer = serv->get_worker_message_bus()->get_buffer();
- if (serv->message_bus.read(event->socket) <= 0) {
+ if (serv->get_worker_message_bus()->read(event->socket) <= 0) {
return SW_OK;
}
serv->worker_accept_event(&pipe_buffer->info);
- serv->message_bus.pop();
+ serv->get_worker_message_bus()->pop();
return SW_OK;
}
diff --git a/tests/include/config.php b/tests/include/config.php
index 65063cb916b..d54a78d3848 100644
--- a/tests/include/config.php
+++ b/tests/include/config.php
@@ -15,7 +15,6 @@
define('IS_PHPTESTSING', !!getenv('PHPT'));
define('USE_VALGRIND', getenv('USE_ZEND_ALLOC') === '0');
define('HAS_SSL', defined("SWOOLE_SSL"));
-define('HAS_ASYNC_REDIS', class_exists("Swoole\\Redis", false));
define('HAS_HTTP2', class_exists("Swoole\\Http2\\Request", false));
define('DEV_NULL', '/dev/null');
@@ -148,6 +147,14 @@
]);
}
+if (IS_IN_CI) {
+ define('TEST_DOMAIN_1', 'www.google.com');
+ define('TEST_DOMAIN_2', 'www.yahoo.com');
+} else {
+ define('TEST_DOMAIN_1', 'www.baidu.com');
+ define('TEST_DOMAIN_2', 'www.qq.com');
+}
+
/** =============== IP ================ */
define('IP_REGEX', '/^(?:[\d]{1,3}\.){3}[\d]{1,3}$/');
diff --git a/tests/include/lib/src/DbWrapper.php b/tests/include/lib/src/DbWrapper.php
index 8309875b937..ad6921292e0 100644
--- a/tests/include/lib/src/DbWrapper.php
+++ b/tests/include/lib/src/DbWrapper.php
@@ -15,8 +15,14 @@ class DbWrapper
public function connect($config)
{
- $mysql = new MySQL([]);
- $res = $mysql->connect($config);
+ $mysql = new \mysqli();
+ $res = $mysql->connect(
+ $config['host'],
+ $config['user'],
+ $config['password'],
+ $config['database'],
+ $config['port'],
+ );
if (false === $res) {
throw new RuntimeException($mysql->connect_error, $mysql->errno);
@@ -31,20 +37,18 @@ public function connect($config)
public function __call($name, $arguments)
{
// $result = $this->mysql->{$name}(...$arguments);
- $result = call_user_func_array([$this->mysql, $name], $arguments);
+ // $result = call_user_func_array([$this->mysql, $name], $arguments);
$result = $this->mysql->query($arguments[0]);
if (false === $result) {
if (!$this->mysql->connected) {
- $this->mysql->connect($this->config);
-
+ $this->connect($this->config);
return call_user_func_array([$this->mysql, $name], $arguments);
}
-
- if (!empty($this->mysql->errno)) { //有错误码,则抛出弃常
+ if (!empty($this->mysql->errno)) {
throw new RuntimeException($this->mysql->error, $this->mysql->errno);
}
}
- return $result;
+ return $result->fetch_all();
}
}
diff --git a/tests/include/lib/src/MysqlPool.php b/tests/include/lib/src/MysqlPool.php
index 00f2484901c..153094157f3 100644
--- a/tests/include/lib/src/MysqlPool.php
+++ b/tests/include/lib/src/MysqlPool.php
@@ -53,7 +53,7 @@ public function put($mySQL)
public function get()
{
/**
- * @var \Swoole\Coroutine\Mysql $mysql
+ * @var mysqli
*/
$mysql = $this->pool->pop($this->config['pool_get_timeout']);
if ($mysql === false) {
diff --git a/tests/include/lib/src/ThreadManager.php b/tests/include/lib/src/ThreadManager.php
new file mode 100644
index 00000000000..9fbf19771b6
--- /dev/null
+++ b/tests/include/lib/src/ThreadManager.php
@@ -0,0 +1,20 @@
+parentFunc)();
+ } else {
+ ($this->childFunc)(...$args);
+ }
+ }
+}
diff --git a/tests/include/skipif.inc b/tests/include/skipif.inc
index faf324acd13..90eb0a62242 100644
--- a/tests/include/skipif.inc
+++ b/tests/include/skipif.inc
@@ -147,6 +147,11 @@ function skip_if_darwin()
skip('not support on darwin', stripos(PHP_OS, 'Darwin') !== false);
}
+function skip_if_nts()
+{
+ skip('not support in nts', !defined('SWOOLE_THREAD'));
+}
+
function skip_if_musl_libc()
{
skip('not support when use musl libc', !empty(`ldd 2>&1 | grep -i musl`));
diff --git a/tests/init b/tests/init
index b97a63e4d3f..0b730ce7063 100755
--- a/tests/init
+++ b/tests/init
@@ -36,17 +36,16 @@ function read_sql_file(string $file)
}
require __DIR__ . '/include/config.php';
+require __DIR__ . '/swoole_pdo_pgsql/pdo_pgsql.inc';
Swoole\Coroutine\run(function () {
echo "[DB-init] initialization MySQL database...\n";
- $mysql = new Swoole\Coroutine\MySQL();
- $connected = $mysql->connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ]);
+ $mysql = new mysqli();
+ $connected = $mysql->connect(MYSQL_SERVER_HOST,
+ MYSQL_SERVER_USER,
+ MYSQL_SERVER_PWD,
+ MYSQL_SERVER_DB,
+ MYSQL_SERVER_PORT);
if (!$connected) {
echo "[DB-init] Connect failed! Error#{$mysql->connect_errno}: {$mysql->connect_error}\n";
exit(1);
@@ -60,23 +59,6 @@ Swoole\Coroutine\run(function () {
}
echo "[DB-init] MySQL Done!\n";
- echo "[DB-init] initialization PostgreSQL database...\n";
- $pgsql = new Swoole\Coroutine\PostgreSQL();
- $connected = $pgsql->connect(PGSQL_CONNECTION_STRING);
- if (!$connected) {
- echo sprintf("[DB-init] Connect failed! Error#%s: %s", $pgsql->error, $pgsql->notices['sqlstate'] ?? ''), PHP_EOL;
- exit(1);
- }
- $sql_file = read_sql_file(__DIR__ . '/pgsql.sql');
- foreach ($sql_file as $line) {
- if (!$pgsql->query($line)) {
- echo sprintf("[DB-init] Failed! Error#%s: %s", $pgsql->error, $pgsql->notices['sqlstate'] ?? ''), PHP_EOL;
- exit(1);
- }
- }
- echo "[DB-init] PostgreSQL Done!\n";
-
-
echo "[DB-init] initialization ODBC...\n";
echo `set -ex`;
diff --git a/tests/start.sh b/tests/start.sh
index ae744e3f118..43cdac2e73a 100755
--- a/tests/start.sh
+++ b/tests/start.sh
@@ -38,8 +38,6 @@ else
swoole_http_server \
swoole_websocket_server \
swoole_redis_server \
- swoole_mysql_coro \
- swoole_redis_coro \
swoole_socket_coro \
swoole_runtime"
if [ ${#} -gt 1 ]; then
diff --git a/tests/swoole_channel_coro/pool.phpt b/tests/swoole_channel_coro/pool.phpt
index 45007d4dd71..e7622f05944 100644
--- a/tests/swoole_channel_coro/pool.phpt
+++ b/tests/swoole_channel_coro/pool.phpt
@@ -19,7 +19,7 @@ class RedisPool
{
$this->pool = new \Swoole\Coroutine\Channel($size);
for ($i = 0; $i < $size; $i++) {
- $redis = new Swoole\Coroutine\Redis();
+ $redis = new \redis();
$res = $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
if ($res == false) {
throw new \RuntimeException("failed to connect redis server.");
@@ -29,12 +29,12 @@ class RedisPool
}
}
- public function get(): \Swoole\Coroutine\Redis
+ public function get(): \redis
{
return $this->pool->pop();
}
- public function put(\Swoole\Coroutine\Redis $redis)
+ public function put(\redis $redis)
{
$this->pool->push($redis);
}
@@ -47,6 +47,7 @@ class RedisPool
}
$count = 0;
+\Swoole\Runtime::setHookFlags(SWOOLE_HOOK_ALL);
go(function () {
$pool = new RedisPool();
// max concurrency num is more than max connections
diff --git a/tests/swoole_coroutine/bug_2387.phpt b/tests/swoole_coroutine/bug_2387.phpt
index c705d2975a4..e0dffd0f898 100644
--- a/tests/swoole_coroutine/bug_2387.phpt
+++ b/tests/swoole_coroutine/bug_2387.phpt
@@ -33,7 +33,8 @@ $pm->childFunc = function () use ($pm) {
$httpServer = new Swoole\Http\Server('0.0.0.0', $pm->getFreePort(), SWOOLE_BASE);
$httpServer->set([
'log_file' => '/dev/null',
- 'worker_num' => 1
+ 'worker_num' => 1,
+ 'hook_flags' => SWOOLE_HOOK_ALL,
]);
$httpServer->on('WorkerStart', function (Swoole\Http\Server $server) use ($pm, $config) {
try {
diff --git a/tests/swoole_coroutine/check.phpt b/tests/swoole_coroutine/check.phpt
index 0c4e0b3432c..036829313dc 100644
--- a/tests/swoole_coroutine/check.phpt
+++ b/tests/swoole_coroutine/check.phpt
@@ -80,32 +80,8 @@ $map = [
(new Co\Http\Client('127.0.0.1', 1234))->get('/');
Assert::assert(0); // never here
},
- function () {
- (new Co\Mysql)->connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ]);
- Assert::assert(0); // never here
- },
- function () {
- (new Co\Redis)->connect('127.0.0.1', 6379);
- Assert::assert(0); // never here
- },
];
-function pgsql_test() {
- (new Co\Postgresql())->connect('host=127.0.0.1 port=12345 dbname=test user=root password=root');
- Assert::assert(0); // never here
-}
-
-if (class_exists(Co\Postgresql::class)) {
- $map[] = function () {
- pgsql_test();
- };
-}
if (class_exists(Co\Http2\Client::class)) {
$map[] = function () {
(new Co\Http2\Client('127.0.0.1', 1234))->connect();
diff --git a/tests/swoole_coroutine/private_access.phpt b/tests/swoole_coroutine/private_access.phpt
index 143fcdd3fc7..bfe4f9d1dcc 100644
--- a/tests/swoole_coroutine/private_access.phpt
+++ b/tests/swoole_coroutine/private_access.phpt
@@ -19,6 +19,8 @@ class Bar
public function foo()
{
+ \Swoole\Runtime::setHookFlags(SWOOLE_HOOK_ALL);
+
go(function () {
var_dump(self::$s_private);
var_dump(self::$s_protect);
@@ -47,16 +49,16 @@ class Bar
var_dump($this->private);
var_dump($this->protect);
var_dump($this->public);
- $mysql = new Swoole\Coroutine\MySQL;
- $res = $mysql->connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ]);
+ $mysql = new mysqli();
+ $res = $mysql->connect(
+ MYSQL_SERVER_HOST,
+ MYSQL_SERVER_USER,
+ MYSQL_SERVER_PWD,
+ MYSQL_SERVER_DB,
+ MYSQL_SERVER_PORT,
+ );
Assert::assert($res);
- $ret = $mysql->query('show tables', 1);
+ $ret = $mysql->query('show tables', 1)->fetch_all();
Assert::assert(is_array($ret));
Assert::assert(count($ret) > 0);
var_dump(self::$s_private);
diff --git a/tests/swoole_coroutine/signal_listener.phpt b/tests/swoole_coroutine/signal_listener.phpt
index 3e124e20734..567b17664c8 100644
--- a/tests/swoole_coroutine/signal_listener.phpt
+++ b/tests/swoole_coroutine/signal_listener.phpt
@@ -9,7 +9,7 @@ require __DIR__ . '/../include/bootstrap.php';
use Swoole\Coroutine;
use Swoole\Process;
-ini_set('swoole.enable_coroutine', 'off');
+swoole_async_set(['enable_coroutine' => false]);
$pm = new ProcessManager;
$pm->parentFunc = function () use ($pm) {
diff --git a/tests/swoole_feature/cross_close/redis.phpt b/tests/swoole_feature/cross_close/redis.phpt
index 49a9e30e6b9..b48d371cbb4 100644
--- a/tests/swoole_feature/cross_close/redis.phpt
+++ b/tests/swoole_feature/cross_close/redis.phpt
@@ -8,7 +8,8 @@ require __DIR__ . '/../../include/bootstrap.php';
$pm = new ProcessManager();
$pm->initRandomData(1);
$pm->parentFunc = function () use ($pm) {
- $redis = new Co\Redis;
+ Swoole\Runtime::setHookFlags(SWOOLE_HOOK_ALL);
+ $redis = new \redis;
go(function () use ($pm, $redis) {
$redis->connect('127.0.0.1', $pm->getFreePort());
go(function () use ($pm, $redis) {
@@ -20,14 +21,13 @@ $pm->parentFunc = function () use ($pm) {
echo "DONE\n";
$pm->kill();
});
- $ret = $redis->get($pm->getRandomData());
- echo "CLOSED\n";
- Assert::assert(!$ret);
- Assert::assert(!$redis->connected);
- Assert::assert(in_array($redis->errType, [SWOOLE_REDIS_ERR_IO, SWOOLE_REDIS_ERR_EOF], true));
- if ($redis->errType === SWOOLE_REDIS_ERR_IO) {
- Assert::same($redis->errCode, SOCKET_ECANCELED);
+ try {
+ $ret = $redis->get($pm->getRandomData());
+ } catch (\RedisException $e) {
+ $ret = false;
+ echo "CLOSED\n";
}
+ Assert::assert(!$ret);
});
});
};
@@ -37,6 +37,7 @@ $pm->childFunc = function () use ($pm) {
Assert::assert($server->bind('127.0.0.1', $pm->getFreePort()));
Assert::assert($server->listen());
go(function () use ($pm, $server) {
+ $pm->wakeup();
if (Assert::assert(($conn = $server->accept()) && $conn instanceof Co\Socket)) {
switch_process();
$data = $conn->recv();
@@ -49,7 +50,6 @@ $pm->childFunc = function () use ($pm) {
}
$server->close();
});
- $pm->wakeup();
});
};
$pm->childFirst();
diff --git a/tests/swoole_feature/cross_close/redis_by_server.phpt b/tests/swoole_feature/cross_close/redis_by_server.phpt
index ebe728b7d79..a4436cfe99e 100644
--- a/tests/swoole_feature/cross_close/redis_by_server.phpt
+++ b/tests/swoole_feature/cross_close/redis_by_server.phpt
@@ -8,14 +8,16 @@ require __DIR__ . '/../../include/bootstrap.php';
$pm = new ProcessManager();
$pm->initRandomData(1);
$pm->parentFunc = function () use ($pm) {
+ Swoole\Runtime::setHookFlags(SWOOLE_HOOK_ALL);
go(function () use ($pm) {
- $redis = new Co\Redis;
+ $redis = new \redis;
Assert::assert($redis->connect('127.0.0.1', $pm->getFreePort()));
echo "GET\n";
- Assert::assert(!$redis->get($pm->getRandomData()));
- echo "CLOSED\n";
- Assert::same($redis->errType, SWOOLE_REDIS_ERR_EOF);
- Assert::same($redis->errCode, SOCKET_ECONNRESET);
+ try {
+ $redis->get($pm->getRandomData());
+ } catch (\RedisException $e) {
+ echo "CLOSED\n";
+ }
$pm->kill();
echo "DONE\n";
});
diff --git a/tests/swoole_global/serialize_deny.phpt b/tests/swoole_global/serialize_deny.phpt
index 82a24e8ec44..6d9154d7f38 100644
--- a/tests/swoole_global/serialize_deny.phpt
+++ b/tests/swoole_global/serialize_deny.phpt
@@ -34,22 +34,6 @@ go(function () {
} catch (\Exception $exception) {
Assert::same(strpos($exception->getMessage(), 'Serialization'), 0);
}
- try {
- $hcc = new \Swoole\Coroutine\Mysql();
- serialize($hcc);
- Assert::true(false, 'never here');
- } catch (\Exception $exception) {
- Assert::same(strpos($exception->getMessage(), 'Serialization'), 0);
- }
- if (HAS_ASYNC_REDIS) {
- try {
- $hcc = new \Swoole\Coroutine\Redis();
- serialize($hcc);
- Assert::true(false, 'never here');
- } catch (\Exception $exception) {
- Assert::same(strpos($exception->getMessage(), 'Serialization'), 0);
- }
- }
try {
$hcc = new \Swoole\Table(1);
serialize($hcc);
diff --git a/tests/swoole_http_server/bug_2444.phpt b/tests/swoole_http_server/bug_2444.phpt
index ff6357a7f2e..cd4b6067b4c 100644
--- a/tests/swoole_http_server/bug_2444.phpt
+++ b/tests/swoole_http_server/bug_2444.phpt
@@ -14,7 +14,7 @@ $pm->parentFunc = function () use ($pm) {
};
$pm->childFunc = function () use ($pm) {
$server = new Swoole\Http\Server('0.0.0.0', $pm->getFreePort(), SWOOLE_BASE);
- $server->set(['log_file' => '/dev/null']);
+ $server->set(['log_file' => '/dev/null', 'hook_flags' => SWOOLE_HOOK_ALL]);
$server->on('start', function () use ($pm) {
$pm->wakeup();
});
@@ -30,18 +30,16 @@ $pm->childFunc = function () use ($pm) {
return;
}
$cli->close();
- $db = new Swoole\Coroutine\Mysql();
- if (!Assert::assert($db->connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'strict_type' => true
- ]))) {
+ $db = new mysqli();
+ $db->set_opt(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, 1);
+ if (!Assert::assert($db->connect(MYSQL_SERVER_HOST,
+ MYSQL_SERVER_USER,
+ MYSQL_SERVER_PWD,
+ MYSQL_SERVER_DB,
+ MYSQL_SERVER_PORT))) {
goto _error;
}
- if (!Assert::assert($db->query('select 1')[0][1] === 1)) {
+ if (!Assert::assert($db->query('select 1')->fetch_all()[0][0] === 1)) {
goto _error;
}
$db->close();
diff --git a/tests/swoole_mysql_coro/abandon_prepare_dtor.phpt b/tests/swoole_mysql_coro/abandon_prepare_dtor.phpt
deleted file mode 100644
index a965bf6313b..00000000000
--- a/tests/swoole_mysql_coro/abandon_prepare_dtor.phpt
+++ /dev/null
@@ -1,29 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql prepare dtor
---SKIPIF--
-
---FILE--
-connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ]);
- for ($n = MAX_REQUESTS; $n--;) {
- $statement = $mysql->prepare('SELECT ?');
- $statement = null;
- Co::sleep(0.001);
- $result = $mysql->query('show status like \'Prepared_stmt_count\'');
- Assert::eq($result[0]['Value'], '0');
- }
-});
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/aborted_clients.phpt b/tests/swoole_mysql_coro/aborted_clients.phpt
deleted file mode 100644
index 0b1b14f42f5..00000000000
--- a/tests/swoole_mysql_coro/aborted_clients.phpt
+++ /dev/null
@@ -1,25 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql-close/reconnect/aborted-client-num
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
- Assert::true($db->connect($server));
- $before_num = (int)$db->query('show status like "Aborted_clients"')[0]["Value"];
- Assert::true($db->close());
- Assert::true($db->connect($server));
- $after_num = (int)$db->query('show status like "Aborted_clients"')[0]["Value"];
- Assert::same($after_num - $before_num, 0);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/another_coroutine.phpt b/tests/swoole_mysql_coro/another_coroutine.phpt
deleted file mode 100644
index bf1dc32b0d1..00000000000
--- a/tests/swoole_mysql_coro/another_coroutine.phpt
+++ /dev/null
@@ -1,51 +0,0 @@
---TEST--
-swoole_mysql_coro: illegal another coroutine
---SKIPIF--
-
---FILE--
-query('SELECT SLEEP(1)');
- Assert::assert(false, 'never here');
- }
-
- $cli = new Co\MySQL;
- $connected = $cli->connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ]);
- if (Assert::true($connected)) {
- go(function () use ($cli) {
- $cli->query('SELECT SLEEP(1)');
- Assert::assert(false, 'never here');
- });
- go(function () use ($cli) {
- (function () use ($cli) {
- (function () use ($cli) {
- get($cli);
- })();
- })();
- });
- }
- });
- echo "end\n";
-}, false, null, false);
-$process->start();
-Swoole\Process::wait();
-?>
---EXPECTF--
-Fatal error: Uncaught Swoole\Error: Socket#%d has already been bound to another coroutine#%d, reading of the same socket in coroutine#%d at the same time is not allowed in %s:%d
-Stack trace:
-#0 %s(%d): Swoole\Coroutine\MySQL->query('SELECT SLEEP(%d)')
-#1 %s(%d): get(Object(Swoole\Coroutine\MySQL))
-#2 %s(%d): {closure}()
-#3 %s(%d): {closure}()
-%A
- thrown in %s on line %d
diff --git a/tests/swoole_mysql_coro/bc_fetchAll.phpt b/tests/swoole_mysql_coro/bc_fetchAll.phpt
deleted file mode 100644
index 02a3d15d1cc..00000000000
--- a/tests/swoole_mysql_coro/bc_fetchAll.phpt
+++ /dev/null
@@ -1,75 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql fetchAll should return empty array (#2674)
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- ];
-
- if (Assert::true($client->connect($server))) {
- defer(function () use ($server, $client) {
- $client->connect($server);
- $client->query('DROP TABLE `empty`');
- });
- if (Assert::true($client->query("CREATE TABLE `empty` (`id` int(11))"))) {
- // query
- Assert::notEmpty($client->query('SELECT * FROM `ckl`'));
- Assert::same($client->query('SELECT * FROM `empty`'), []);
- Assert::same($client->query('SELECT * FROM `notexist`'), false);
- // execute
- Assert::notEmpty($client->prepare('SELECT * FROM `ckl`')->execute());
- Assert::same(($statement = $client->prepare('SELECT * FROM `empty`'))->execute(), []);
- Assert::same($client->prepare('SELECT * FROM `notexist`'), false);
- // closed
- Assert::true($client->close());
- Assert::same($client->query('SELECT * FROM `empty`'), false);
- Assert::same($client->prepare('SELECT * FROM `empty`'), false);
- Assert::same($statement->execute(), false);
-
- if (Assert::true($client->connect($server + ['fetch_mode' => true]))) {
- // query
- Assert::true($client->query('SELECT * FROM `ckl` LIMIT 1'));
- Assert::notEmpty($client->fetch());
- Assert::null($client->fetch());
- Assert::null($client->fetch());
- Assert::same($client->fetchAll(), []);
- Assert::true($client->query('SELECT * FROM `ckl` LIMIT 1'));
- Assert::count($client->fetchAll(), 1);
- Assert::same($client->fetchAll(), []);
- // execute
- Assert::isInstanceOf(
- $statement = $client->prepare('SELECT * FROM `ckl` LIMIT 1'),
- Swoole\Coroutine\MySQL\Statement::class
- );
- Assert::same($statement->fetchAll(), []);
- Assert::true($statement->execute());
- Assert::notEmpty($statement->fetch());
- Assert::null($statement->fetch());
- Assert::true($statement->execute());
- Assert::notEmpty($statement->fetchAll());
- Assert::same($statement->fetchAll(), []);
- // closed
- Assert::true($client->close());
- Assert::false($client->query('SELECT * FROM `ckl` LIMIT 1'));
- Assert::false($client->fetch());
- Assert::false($client->fetchAll());
- Assert::false($statement->execute());
- Assert::false($statement->fetch());
- Assert::false($statement->fetchAll());
- echo "DONE\n";
- }
- }
- }
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/bc_sync_properties.phpt b/tests/swoole_mysql_coro/bc_sync_properties.phpt
deleted file mode 100644
index a23866ff9da..00000000000
--- a/tests/swoole_mysql_coro/bc_sync_properties.phpt
+++ /dev/null
@@ -1,39 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql prepare (insert)
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- ];
-
- if (Assert::true($client->connect($server))) {
- /* @var $statement Swoole\Coroutine\MySQL\Statement */
- $statement = $client->prepare('INSERT INTO ckl (`domain`,`path`,`name`) VALUES (?,?,?)');
- if (Assert::isInstanceOf($statement, Swoole\Coroutine\MySQL\Statement::class)) {
- if (Assert::true($statement->execute(['www.baidu.com', '/search', 'baidu']))) {
- Assert::same($statement->affected_rows, 1);
- Assert::greaterThan($statement->insert_id, 0);
- Assert::same($client->affected_rows, $statement->affected_rows);
- Assert::same($client->insert_id, $statement->insert_id);
- if (Assert::false($statement->execute())) {
- Assert::same($statement->errno, SWOOLE_MYSQLND_CR_INVALID_PARAMETER_NO);
- Assert::same($client->error, $statement->error);
- Assert::same($client->errno, $statement->errno);
- }
- echo "SUCCESS\n";
- }
- }
- }
-});
-?>
---EXPECT--
-SUCCESS
diff --git a/tests/swoole_mysql_coro/big_data.phpt b/tests/swoole_mysql_coro/big_data.phpt
deleted file mode 100644
index 02f6b3f6f87..00000000000
--- a/tests/swoole_mysql_coro/big_data.phpt
+++ /dev/null
@@ -1,38 +0,0 @@
---TEST--
-swoole_mysql_coro: select big data from db
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
- Assert::assert($db->connect($server));
-
- $table_name = get_safe_random(16);
- $createTable = "CREATE TABLE {$table_name} (\nid bigint PRIMARY KEY AUTO_INCREMENT,\n`content` text NOT NULL\n);";
- if (Assert::assert($db->query($createTable))) {
- $statement = $db->prepare("INSERT INTO {$table_name} VALUES (?, ?)");
- $random = [];
- for ($n = 0; $n < MAX_REQUESTS; $n++) {
- $random[$n] = str_repeat(get_safe_random(256), 128); // 32K
- $ret = $statement->execute([$n + 1, $random[$n]]);
- Assert::assert($ret);
- }
- $statement = $db->prepare("SELECT * FROM {$table_name}");
- $ret = $statement->execute();
- for ($n = 0; $n < MAX_REQUESTS; $n++) {
- Assert::same($ret[$n]['content'], $random[$n]);
- }
- Assert::assert($db->query("DROP TABLE {$table_name}"));
- }
-});
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/bug_0814.phpt b/tests/swoole_mysql_coro/bug_0814.phpt
deleted file mode 100644
index a3626e69814..00000000000
--- a/tests/swoole_mysql_coro/bug_0814.phpt
+++ /dev/null
@@ -1,72 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql prepare (select)
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- ];
-
- $ret1 = $db->connect($server);
- if (!$ret1) {
- echo "CONNECT[1] ERROR\n";
- return;
- }
-
- /**
- * 第一次执行prepare
- */
- $stmt = $db->prepare('SELECT * FROM userinfo WHERE id=?');
- if (!$stmt) {
- echo "PREPARE ERROR\n";
- return;
- }
-
- $ret3 = $stmt->execute([5]);
- if (!$ret3) {
- echo "EXECUTE ERROR#{$stmt->errno}: {$stmt->error}\n";
- return;
- }
- Assert::assert(count($ret3) > 0);
-
- $s = microtime(true);
- $ret = $db->query("select sleep(20)", 0.1);
- time_approximate(0.1, microtime(true) - $s);
- Assert::false($ret);
- Assert::same($db->errno, SWOOLE_MYSQLND_CR_SERVER_GONE_ERROR);
- $ret1 = $db->connect($server);
- if (!$ret1) {
- echo "CONNECT[2] ERROR\n";
- return;
- }
-
- /**
- * 第二次执行prepare
- */
- $stmt = $db->prepare('SELECT * FROM userinfo WHERE id=?');
- if (!$stmt) {
- echo "PREPARE ERROR\n";
- return;
- }
-
- $ret3 = $stmt->execute([5]);
- if (!$ret3) {
- echo "EXECUTE ERROR#{$stmt->errno}: {$stmt->error}\n";
- return;
- }
- Assert::assert(count($ret3) > 0);
-});
-
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/connect_timeout.phpt b/tests/swoole_mysql_coro/connect_timeout.phpt
deleted file mode 100644
index e9f4954dde0..00000000000
--- a/tests/swoole_mysql_coro/connect_timeout.phpt
+++ /dev/null
@@ -1,43 +0,0 @@
---TEST--
-swoole_mysql_coro: connect timeout
---SKIPIF--
-
---FILE--
-connect([
- 'host' => '192.0.0.1',
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'timeout' => ($timeout = mt_rand(100, 500) / 1000)
- ]);
- time_approximate($timeout, microtime(true) - $s);
- Assert::assert(!$connected);
- Assert::assert($mysql->connected === false);
- Assert::assert($mysql->connect_errno === SWOOLE_MYSQLND_CR_CONNECTION_ERROR);
- // handshake timeout
- $s = microtime(true);
- $connected = $mysql->connect([
- 'host' => REDIS_SERVER_HOST,
- 'port' => REDIS_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'timeout' => ($timeout = mt_rand(100, 500) / 1000)
- ]);
- time_approximate($timeout, microtime(true) - $s);
- Assert::false($connected);
- Assert::same($mysql->connected, false);
- Assert::same($mysql->connect_errno, SWOOLE_MYSQLND_CR_CONNECTION_ERROR);
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/db_destruct.phpt b/tests/swoole_mysql_coro/db_destruct.phpt
deleted file mode 100644
index 53d102077f8..00000000000
--- a/tests/swoole_mysql_coro/db_destruct.phpt
+++ /dev/null
@@ -1,28 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql db destruct
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
- $ret = $db->connect($server);
- if (Assert::true($ret)) {
- $statement = $db->prepare('SELECT 1');
- Assert::isInstanceOf($statement, Co\Mysql\Statement::class);
- $ret = $statement->execute();
- Assert::same($ret[0][1], 1);
- echo "DONE\n";
- }
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/defer_and_fetch.phpt b/tests/swoole_mysql_coro/defer_and_fetch.phpt
deleted file mode 100644
index 758f3459825..00000000000
--- a/tests/swoole_mysql_coro/defer_and_fetch.phpt
+++ /dev/null
@@ -1,41 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql defer and fetch
---SKIPIF--
-
---FILE--
-connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'fetch_mode' => true
- ]);
- $mysql->setDefer(true);
- for ($n = 0; $n < MAX_REQUESTS; $n++) {
- if ($n === 0 || mt_rand(0, 1)) {
- $ret = $mysql->prepare('SELECT ?+?');
- Assert::true($ret);
- $statement = $mysql->recv();
- Assert::isInstanceOf($statement, Swoole\Coroutine\MySQL\Statement::class);
- }
- $a = mt_rand(0, 65535);
- $b = mt_rand(0, 65535);
- /** @var $statement Swoole\Coroutine\MySQL\Statement */
- Assert::true($statement->execute([$a, $b]));
- Assert::true($statement->recv());
- $result = $statement->fetchAll();
- if (Assert::isArray($result)) {
- Assert::same(reset($result[0]), (float)($a + $b));
- }
- }
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/err_instead_of_eof.phpt b/tests/swoole_mysql_coro/err_instead_of_eof.phpt
deleted file mode 100644
index d453be39b51..00000000000
--- a/tests/swoole_mysql_coro/err_instead_of_eof.phpt
+++ /dev/null
@@ -1,26 +0,0 @@
---TEST--
-swoole_mysql_coro: ERR Instead of EOF
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
- $db->connect($server);
- if (!$db->query("EXPLAIN SELECT * FROM dual;")) {
- echo $db->errno . PHP_EOL;
- echo $db->error . PHP_EOL;
- }
-});
-?>
---EXPECT--
-1096
-SQLSTATE[HY000] [1096] No tables used
diff --git a/tests/swoole_mysql_coro/escape.phpt b/tests/swoole_mysql_coro/escape.phpt
deleted file mode 100644
index a58987ae935..00000000000
--- a/tests/swoole_mysql_coro/escape.phpt
+++ /dev/null
@@ -1,20 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql escape
---SKIPIF--
-
---FILE--
-connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ]);
- Assert::same($mysql->escape(""), "");
-});
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/fetch.phpt b/tests/swoole_mysql_coro/fetch.phpt
deleted file mode 100644
index 3c794d133e3..00000000000
--- a/tests/swoole_mysql_coro/fetch.phpt
+++ /dev/null
@@ -1,34 +0,0 @@
---TEST--
-swoole_mysql_coro: use fetch to get data
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'fetch_mode' => true
- ];
-
- $db->connect($server);
-
- // now we can make the responses independent
- $stmt = $db->prepare('SELECT `id` FROM `userinfo` LIMIT 2');
- Assert::true($stmt->execute());
- if (!Assert::assert(is_array($ret = $stmt->fetch()) && !empty($ret))) {
- echo "FETCH1 ERROR#{$stmt->errno}: {$stmt->error}\n";
- }
- if (!Assert::assert(is_array($ret = $stmt->fetch()) && !empty($ret))) {
- echo "FETCH2 ERROR#{$stmt->errno}: {$stmt->error}\n";
- }
- Assert::same($stmt->fetch(), null);
- Assert::same($stmt->fetchAll(), []);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/fetch_mode.phpt b/tests/swoole_mysql_coro/fetch_mode.phpt
deleted file mode 100644
index 5000a2a8cb8..00000000000
--- a/tests/swoole_mysql_coro/fetch_mode.phpt
+++ /dev/null
@@ -1,33 +0,0 @@
---TEST--
-swoole_mysql_coro: use fetch to get data
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'fetch_mode' => true
- ];
-
- $db->connect($server);
-
- // now we can make the responses independent
- $stmt1 = $db->prepare('SELECT * FROM ckl LIMIT 1');
- Assert::true($stmt1->execute());
- $stmt2 = $db->prepare('SELECT * FROM ckl LIMIT 2');
- Assert::true($stmt2->execute());
- Assert::same(count($stmt1->fetchAll()), 1);
- Assert::same(count($stmt2->fetchAll()), 2);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/fetch_mode_twice.phpt b/tests/swoole_mysql_coro/fetch_mode_twice.phpt
deleted file mode 100644
index 1a312c4b9ee..00000000000
--- a/tests/swoole_mysql_coro/fetch_mode_twice.phpt
+++ /dev/null
@@ -1,29 +0,0 @@
---TEST--
-swoole_mysql_coro: call fetch twice
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'fetch_mode' => true
- ];
-
- $db->connect($server);
-
- Assert::true($db->query("INSERT INTO ckl (`domain`,`path`,`name`) VALUES ('www.baidu.com', '/search', 'baidu')"));
- // now we can make the responses independent
- $stmt = $db->prepare('SELECT * FROM ckl LIMIT 1');
- Assert::true($stmt->execute());
- Assert::assert(($ret = $stmt->fetchAll()) && is_array($ret) && count($ret) === 1);
- Assert::same($stmt->fetchAll(), []);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/illegal_extends.phpt b/tests/swoole_mysql_coro/illegal_extends.phpt
deleted file mode 100644
index 558bade8abc..00000000000
--- a/tests/swoole_mysql_coro/illegal_extends.phpt
+++ /dev/null
@@ -1,62 +0,0 @@
---TEST--
-swoole_mysql_coro: illegal child class
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'strict_type' => true
- ];
-
- // invalid connect
- Assert::true($db->connect($server));
- Assert::false($db->connected);
- Assert::false($db->query('select 1'));
- Assert::same($db->errno, SWOOLE_MYSQLND_CR_CONNECTION_ERROR);
-
- // right implementation
- Assert::true($db->connectRaw($server));
- Assert::same($db->query('select 1')[0][1], 1);
-});
-
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/invalid_host.phpt b/tests/swoole_mysql_coro/invalid_host.phpt
deleted file mode 100644
index 2c5a945fb4f..00000000000
--- a/tests/swoole_mysql_coro/invalid_host.phpt
+++ /dev/null
@@ -1,25 +0,0 @@
---TEST--
-swoole_mysql_coro: invalid host
---SKIPIF--
-
---FILE--
-connect([
- 'host' => get_safe_random(),
- 'port' => MYSQL_SERVER_PORT,
- 'database' => MYSQL_SERVER_DB,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'timeout' => 0.5
- ]);
- echo 'Connection: ' . ($connected ? 'Connected' : 'Not connected') . PHP_EOL;
- Assert::same($mysql->connect_errno, SWOOLE_MYSQLND_CR_CONNECTION_ERROR);
- echo $mysql->connect_error . PHP_EOL;
-});
-?>
---EXPECTF--
-Connection: Not connected
-SQLSTATE[HY000] [2002] %s
diff --git a/tests/swoole_mysql_coro/kill_process.phpt b/tests/swoole_mysql_coro/kill_process.phpt
deleted file mode 100644
index 025cad9bc93..00000000000
--- a/tests/swoole_mysql_coro/kill_process.phpt
+++ /dev/null
@@ -1,56 +0,0 @@
---TEST--
-swoole_mysql_coro: kill process and check liveness
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'strict_type' => true
- ];
- $mysql = new Swoole\Coroutine\MySQL;
- Assert::true($mysql->connect($config));
- Assert::same($mysql->query('SELECT 1')[0][1], 1);
-
- $killer = new Swoole\Coroutine\MySQL;
- Assert::true($killer->connect($config));
-
- foreach (
- [
- function () use ($mysql) {
- return $mysql->query('SELECT 1');
- },
- function () use ($mysql) {
- return $mysql->begin();
- },
- function () use ($mysql) {
- return $mysql->prepare('SELECT 1');
- },
- ] as $command
- ) {
- $processList = $killer->query('show processlist');
- $processList = array_filter($processList, function (array $value) {
- return $value['db'] == MYSQL_SERVER_DB && $value['Info'] != 'show processlist';
- });
- foreach ($processList as $process) {
- $killer->query("KILL {$process['Id']}");
- }
- switch_process();
- Assert::false($command());
- Assert::same($mysql->errno, SWOOLE_MYSQLND_CR_SERVER_GONE_ERROR);
- Assert::true($mysql->connect($config));
- }
-
- echo $mysql->error . PHP_EOL;
-});
-echo "DONE\n";
-?>
---EXPECT--
-SQLSTATE[HY000] [2006] MySQL server has gone away
-DONE
diff --git a/tests/swoole_mysql_coro/many_rows.phpt b/tests/swoole_mysql_coro/many_rows.phpt
deleted file mode 100644
index 1742140cd0d..00000000000
--- a/tests/swoole_mysql_coro/many_rows.phpt
+++ /dev/null
@@ -1,43 +0,0 @@
---TEST--
-swoole_mysql_coro: insert and select many rows
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
- Assert::assert($db->connect($server));
-
- $table_name = get_safe_random(16);
- $createTable = "CREATE TABLE {$table_name} (\nid bigint PRIMARY KEY AUTO_INCREMENT,\n`content` text NOT NULL\n);";
- $row_num = [100, 200, 1000, 3000][PRESSURE_LEVEL];
- if (Assert::assert($db->query($createTable))) {
- $sql = "INSERT INTO {$table_name} (`content`) VALUES " . rtrim(str_repeat('(?), ', $row_num), ', ');
- $statement = $db->prepare($sql);
- $random = [];
- for ($n = 0; $n < $row_num; $n++) {
- $random[$n] = get_safe_random(64);
- }
- $statement->execute($random);
- $statement = $db->prepare("SELECT * FROM {$table_name}");
- $result = $statement->execute();
- if (Assert::assert(count($result) === $row_num)) {
- for ($n = 0; $n < $row_num; $n++) {
- Assert::same($result[$n]['content'], $random[$n]);
- }
- }
- Assert::assert($db->query("DROP TABLE {$table_name}"));
- echo "DONE\n";
- }
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/multi_packets.phpt b/tests/swoole_mysql_coro/multi_packets.phpt
deleted file mode 100644
index 570b31caa25..00000000000
--- a/tests/swoole_mysql_coro/multi_packets.phpt
+++ /dev/null
@@ -1,125 +0,0 @@
---TEST--
-swoole_mysql_coro: select and insert huge data from db (10M~64M)
---SKIPIF--
-
---FILE--
- -1
-]);
-go(function () {
- $mysql = new Swoole\Coroutine\Mysql;
- $mysql_server = [
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'strict_type' => true
- ];
- // set max_allowed_packet
- $mysql->connect($mysql_server);
- if (!$mysql->query('set global max_allowed_packet = 100 * 1024 * 1024')) {
- exit('unable to set max_allowed_packet to 100M.');
- }
- // reconnect and we can see changes
- $mysql->close();
- $mysql->connect($mysql_server);
- @$mysql->query('DROP TABLE `firmware`');
- $ret = $mysql->query(<<error);
- }
- $max_allowed_packet = $mysql->query('show VARIABLES like \'max_allowed_packet\'');
- $max_allowed_packet = $max_allowed_packet[0]['Value'] / 1024 / 1024;
- phpt_var_dump("max_allowed_packet: {$max_allowed_packet}M");
- if (IS_IN_CI) {
- $max_allowed_packet = 36;
- } else {
- $max_allowed_packet = 64;
- }
- $pdo = new PDO(
- "mysql:host=" . MYSQL_SERVER_HOST . ";port=" . MYSQL_SERVER_PORT . ";dbname=" . MYSQL_SERVER_DB . ";charset=utf8",
- MYSQL_SERVER_USER, MYSQL_SERVER_PWD
- );
- $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
- $mysql_query = new Swoole\Coroutine\Mysql;
- $mysql_query->connect($mysql_server);
- $mysql_prepare = new Swoole\Coroutine\Mysql;
- $mysql_prepare->connect($mysql_server);
- for ($fid = 1; $fid <= $max_allowed_packet / 10; $fid++) {
- $random_size = 2 << mt_rand(2, 9);
- $text_size = min($fid * 10 + mt_rand(1, 9), $max_allowed_packet) * 1024 * 1024; // 1xM ~ 5xM
- $firmware = str_repeat(get_safe_random($random_size), $text_size / $random_size);
- $f_md5 = md5($firmware);
- $f_remark = get_safe_random();
- if (mt_rand(0, 1)) {
- $sql = "INSERT INTO `firmware` (`fid`, `firmware`, `f_md5`, `f_remark`) " .
- "VALUES ({$fid}, '{$firmware}', '{$f_md5}', '{$f_remark}')";
- $ret = $mysql_query->query($sql);
- } else {
- $sql = "INSERT INTO `firmware` (`fid`, `firmware`, `f_md5`, `f_remark`) VALUES (?, ?, ?, ?)";
- $pdo_stmt = $mysql_prepare->prepare($sql);
- if ($pdo_stmt) {
- $ret = $pdo_stmt->execute([$fid, $firmware, $f_md5, $f_remark]);
- if (!$ret) {
- var_dump($pdo_stmt);
- exit;
- }
- } else {
- $ret = false;
- }
- }
- if (Assert::assert($ret)) {
- $sql = 'SELECT * FROM `test`.`firmware` WHERE fid=';
- $pdo_stmt = $pdo->prepare("{$sql}?");
- $mysql_stmt = $mysql_prepare->prepare("{$sql}?");
- $chan = new Chan();
- go(function () use ($chan, $pdo_stmt, $fid) {
- $pdo_stmt->execute([$fid]);
- $result = $pdo_stmt->fetch(PDO::FETCH_ASSOC);
- $chan->push(['pdo', $result]);
- });
- go(function () use ($chan, $mysql_stmt, $fid) {
- $result = $mysql_stmt->execute([$fid])[0];
- $chan->push(['mysql_prepare', $result]);
- });
- go(function () use ($chan, $mysql_query, $sql, $fid) {
- $chan->push(['mysql_query', $mysql_query->query("{$sql}{$fid}")[0]]);
- });
- for ($i = 3; $i--;) {
- list($from, $result) = $chan->pop();
- if ($result['fid'] === $fid) {
- Assert::same($result['firmware'], $firmware);
- Assert::same($result['f_md5'], $f_md5);
- Assert::same($result['f_remark'], $f_remark);
- } else {
- Assert::assert(0, 'wrong result from ' . $from);
- unset($result['firmware']); // too long to show
- phpt_var_dump($result);
- }
- phpt_var_dump(sprintf('%-16s: %s', $from, (strlen($firmware) / 1024 / 1024) . 'M'));
- }
- }
- }
- echo "DONE\n";
-});
-Swoole\Event::wait();
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/not_exist.phpt b/tests/swoole_mysql_coro/not_exist.phpt
deleted file mode 100644
index 280b1fad61c..00000000000
--- a/tests/swoole_mysql_coro/not_exist.phpt
+++ /dev/null
@@ -1,23 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql connect to wrong database
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => 'not_exist'
- ];
- $connected = $db->connect($server);
- Assert::assert(!$connected);
- Assert::same($db->connect_errno, 1049); // unknown database
- Assert::assert(strpos($db->connect_error, 'not_exist'));
-});
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/null.phpt b/tests/swoole_mysql_coro/null.phpt
deleted file mode 100644
index 9f29d660ca9..00000000000
--- a/tests/swoole_mysql_coro/null.phpt
+++ /dev/null
@@ -1,51 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql null
---SKIPIF--
-
---FILE--
-connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'strict_type' => true
- ]);
- Assert::assert($connected);
- Assert::assert($mysql->query('INSERT INTO `custom` (`content`) VALUES (NULL)'));
- Assert::assert($mysql->query('INSERT INTO `custom` (`content`) VALUES ("")'));
- Assert::assert($mysql->query('INSERT INTO `custom` (`content`) VALUES ("NULL")'));
- $result = $mysql->query('select `content` from custom');
- var_dump(array_merge_recursive(...$result)['content']);
- Assert::assert($mysql->query('TRUNCATE TABLE `custom`'));
-
- $stmt = $mysql->prepare('INSERT INTO `custom` (`content`) VALUES (?)');
- Assert::assert($stmt->execute([NULL]));
- Assert::assert($stmt->execute(['']));
- Assert::assert($stmt->execute(['NULL']));
- $result = $mysql->query('select `content` from custom');
- var_dump(array_merge_recursive(...$result)['content']);
- Assert::assert($mysql->query('TRUNCATE TABLE `custom`'));
-});
-?>
---EXPECT--
-array(3) {
- [0]=>
- NULL
- [1]=>
- string(0) ""
- [2]=>
- string(4) "NULL"
-}
-array(3) {
- [0]=>
- NULL
- [1]=>
- string(0) ""
- [2]=>
- string(4) "NULL"
-}
diff --git a/tests/swoole_mysql_coro/null_bit_map.phpt b/tests/swoole_mysql_coro/null_bit_map.phpt
deleted file mode 100644
index f8cdec902e0..00000000000
--- a/tests/swoole_mysql_coro/null_bit_map.phpt
+++ /dev/null
@@ -1,103 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql null bit map rand test
---SKIPIF--
-
---FILE--
-connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ]);
- Assert::assert($connected);
- return $mysql;
-}
-
-for ($c = MAX_CONCURRENCY_LOW; $c--;) {
- go(function () use ($c) {
- // gen table structure
- $table_name = 't' . substr(md5(mt_rand()), 0, 15);
- $field_size = mt_rand(1, 100);
- list($fields, $fields_info) = (function () use ($field_size) {
- $fields_info = [];
- $fields = '';
- for ($i = $field_size; $i--;) {
- $info = $fields_info[] = [
- 'name' => 'f' . substr(md5(mt_rand()), 0, 7),
- 'type' => gen_type()
- ];
- $fields .= "{$info['name']} {$info['type']} NULL,\n";
- }
- return [rtrim($fields, " \n,"), $fields_info];
- })();
- $mysql = mysql();
- // create table
- $createTable = <<query($createTable)) {
- trigger_error("create table error by query statement [{$createTable}]", E_USER_WARNING);
- return;
- }
- $_insert = "INSERT INTO {$table_name} VALUES (" . rtrim(str_repeat('?, ', $field_size + 1), ', ') . ")";
- $data_list = [];
- try {
- for ($n = MAX_REQUESTS; $n--;) {
- $insert = $mysql->prepare($_insert);
- Assert::assert($insert instanceof Co\Mysql\Statement);
- $data_list[] = $gen = (function ($id, $fields_info) {
- $r = ['id' => $id];
- foreach ($fields_info as $info) {
- if (mt_rand(0, 1)) {
- $r[$info['name']] = null;
- } else {
- $r[$info['name']] = gen_data_from_type($info['type']);
- }
- }
- return $r;
- })($n + 1, $fields_info);
- Assert::assert($insert->execute(array_values($gen)));
- }
- $result = $mysql->prepare("SELECT * FROM {$table_name}")->execute();
- Assert::same(array_reverse($data_list), $result);
- } catch (Throwable $e) {
- Assert::assert(0);
- } finally {
- Assert::assert($mysql->query("DROP TABLE {$table_name}"));
- }
- });
-}
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/numbers.phpt b/tests/swoole_mysql_coro/numbers.phpt
deleted file mode 100644
index 6dfd2c217b7..00000000000
--- a/tests/swoole_mysql_coro/numbers.phpt
+++ /dev/null
@@ -1,143 +0,0 @@
---TEST--
-swoole_mysql_coro: floating point value precision and unsigned big int overflow
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'strict_type' => (PHP_VERSION_ID >= 80100)
- ];
- $db->connect($server);
- $r_string1 = $db->query('SELECT * FROM numbers');
- $db->close();
- $server['strict_type'] = true;
- $db->connect($server);
- $r_strong1 = $db->query('SELECT * FROM numbers');
- $stmt = $db->prepare('SELECT * FROM numbers');
- $r_strong2 = $stmt->execute();
-
- try {
- $pdo = new PDO(
- "mysql:host=" . MYSQL_SERVER_HOST . ";port=" . MYSQL_SERVER_PORT . ";dbname=" . MYSQL_SERVER_DB . ";charset=utf8",
- MYSQL_SERVER_USER, MYSQL_SERVER_PWD
- );
- $r_string2 = $pdo->query('SELECT * FROM numbers')->fetchAll(PDO::FETCH_ASSOC);
- $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
- $stmt = $pdo->prepare('SELECT * FROM numbers');
- $stmt->execute();
- $r_strong3 = $stmt->fetchAll(PDO::FETCH_ASSOC);
- Assert::same($r_string1, $r_string2);
- Assert::same($r_strong2, $r_strong3);
- } catch (\PDOException $e) {
- Assert::same($e->getCode(), 2054); // not support auth plugin
- }
-
- if (!is_musl_libc()) {
- Assert::same($r_strong1, $r_strong2);
- }
- var_dump($r_strong2);
-});
-?>
---EXPECT--
-array(3) {
- [0]=>
- array(13) {
- ["id"]=>
- int(1)
- ["tinyint"]=>
- int(127)
- ["utinyint"]=>
- int(255)
- ["smallint"]=>
- int(32767)
- ["usmallint"]=>
- int(65535)
- ["mediumint"]=>
- int(8388607)
- ["umediumint"]=>
- int(16777215)
- ["int"]=>
- int(2147483647)
- ["uint"]=>
- int(4294967294)
- ["bigint"]=>
- int(9223372036854775807)
- ["ubigint"]=>
- string(20) "18446744073709551615"
- ["float"]=>
- float(1.23457)
- ["double"]=>
- float(1.2345678901234567)
- }
- [1]=>
- array(13) {
- ["id"]=>
- int(2)
- ["tinyint"]=>
- int(-128)
- ["utinyint"]=>
- int(123)
- ["smallint"]=>
- int(-32768)
- ["usmallint"]=>
- int(12345)
- ["mediumint"]=>
- int(-8388608)
- ["umediumint"]=>
- int(123456)
- ["int"]=>
- int(-2147483648)
- ["uint"]=>
- int(123456)
- ["bigint"]=>
- int(-9223372036854775808)
- ["ubigint"]=>
- int(123456)
- ["float"]=>
- float(-1.23457)
- ["double"]=>
- float(-1.2345678901234567)
- }
- [2]=>
- array(13) {
- ["id"]=>
- int(3)
- ["tinyint"]=>
- int(0)
- ["utinyint"]=>
- int(0)
- ["smallint"]=>
- int(0)
- ["usmallint"]=>
- int(0)
- ["mediumint"]=>
- int(0)
- ["umediumint"]=>
- int(0)
- ["int"]=>
- int(0)
- ["uint"]=>
- int(0)
- ["bigint"]=>
- int(0)
- ["ubigint"]=>
- int(0)
- ["float"]=>
- float(1.23)
- ["double"]=>
- float(1.23)
- }
-}
diff --git a/tests/swoole_mysql_coro/prepare_field_type.phpt b/tests/swoole_mysql_coro/prepare_field_type.phpt
deleted file mode 100644
index 339ef2c6e11..00000000000
--- a/tests/swoole_mysql_coro/prepare_field_type.phpt
+++ /dev/null
@@ -1,48 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql prepare field type
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'strict_type' => true,
- ];
-
- $ret1 = $db->connect($server);
- if (! $ret1) {
- echo "CONNECT ERROR\n";
-
- return;
- }
-
- $stmt = $db->prepare('SELECT ? as a, ? as b, ? as c, ? as d, ? + ? as e');
- if (! $stmt) {
- echo "PREPARE ERROR\n";
-
- return;
- }
-
- $ret3 = $stmt->execute([123, 3.14, true, false, 11, 22]);
- if (! $ret3) {
- echo "EXECUTE ERROR#{$stmt->errno}: {$stmt->error}\n";
-
- return;
- }
- if (Assert::isArray($ret3)) {
- Assert::same(reset($ret3), ['a' => 123, 'b' => 3.14, 'c' => 1, 'd' => 0, 'e' => 33]);
- }
-});
-
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/prepare_insert.phpt b/tests/swoole_mysql_coro/prepare_insert.phpt
deleted file mode 100644
index 152a5e2dd83..00000000000
--- a/tests/swoole_mysql_coro/prepare_insert.phpt
+++ /dev/null
@@ -1,43 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql prepare (insert)
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- );
-
- $ret1 = $db->connect($server);
- if (!$ret1) {
- echo "CONNECT ERROR\n";
- return;
- }
-
- $stmt = $db->prepare('INSERT INTO ckl (`domain`,`path`,`name`) VALUES (?,?,?)');
- if (!$stmt) {
- echo "PREPARE ERROR\n";
- return;
- }
-
- $ret3 = $stmt->execute(array('www.baidu.com', '/search', 'baidu'));
- if (!$ret3) {
- echo "EXECUTE ERROR\n";
- return;
- }
- Assert::assert($stmt->insert_id > 0);
- Assert::assert($db->insert_id == $stmt->insert_id);
-});
-
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/prepare_multi.phpt b/tests/swoole_mysql_coro/prepare_multi.phpt
deleted file mode 100644
index ca73c5eab19..00000000000
--- a/tests/swoole_mysql_coro/prepare_multi.phpt
+++ /dev/null
@@ -1,49 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql prepare multi (insert and delete)
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- ];
- $connected = $db->connect($server);
- if (!$connected) {
- echo "CONNECT ERROR\n";
- return;
- }
- for ($n = MAX_REQUESTS_MID; $n--;) {
- $statement = $db->prepare('INSERT INTO ckl (`domain`,`path`,`name`) VALUES (?, ?, ?)');
- if (!$statement) {
- echo "PREPARE ERROR\n";
- return;
- }
- $executed = $statement->execute(['www.baidu.com', '/search', 'baidu']);
- if (!$executed) {
- echo "EXECUTE ERROR\n";
- return;
- }
- if ($statement->insert_id > 0) {
- $deleted = $db->query("DELETE FROM ckl WHERE id={$statement->insert_id}");
- if (!$deleted) {
- echo "DELETE ERROR\n";
- }
- } else {
- echo "INSERT ERROR\n";
- }
- }
- });
-}
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/prepare_select.phpt b/tests/swoole_mysql_coro/prepare_select.phpt
deleted file mode 100644
index 46ebc89112a..00000000000
--- a/tests/swoole_mysql_coro/prepare_select.phpt
+++ /dev/null
@@ -1,42 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql prepare (select)
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- );
-
- $ret1 = $db->connect($server);
- if (!$ret1) {
- echo "CONNECT ERROR\n";
- return;
- }
-
- $stmt = $db->prepare('SELECT * FROM userinfo WHERE id=?');
- if (!$stmt) {
- echo "PREPARE ERROR\n";
- return;
- }
-
- $ret3 = $stmt->execute([5]);
- if (!$ret3) {
- echo "EXECUTE ERROR#{$stmt->errno}: {$stmt->error}\n";
- return;
- }
- Assert::assert(count($ret3) > 0);
-});
-
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/procedure.phpt b/tests/swoole_mysql_coro/procedure.phpt
deleted file mode 100644
index b0fe8966c93..00000000000
--- a/tests/swoole_mysql_coro/procedure.phpt
+++ /dev/null
@@ -1,60 +0,0 @@
---TEST--
-swoole_mysql_coro: procedure without fetch mode
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
-
- $clear = <<connect($server);
-
- if ($db->query($clear) && $db->query($procedure)) {
- $stmt = $db->prepare('CALL reply(?)');
- for ($n = MAX_REQUESTS; $n--;) {
- //SWOOLE
- $_map = $map;
- $res = $stmt->execute(['hello mysql!']);
- do {
- Assert::same(current($res[0]), array_shift($_map));
- } while ($res = $stmt->nextResult());
- Assert::same($stmt->affected_rows, 1, 'get the affected rows failed!');
- Assert::assert(empty($_map), 'there are some results lost!');
- }
- }
-
- echo "DONE\n";
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/procedure_by_query.phpt b/tests/swoole_mysql_coro/procedure_by_query.phpt
deleted file mode 100644
index 4d1a7470dbd..00000000000
--- a/tests/swoole_mysql_coro/procedure_by_query.phpt
+++ /dev/null
@@ -1,63 +0,0 @@
---TEST--
-swoole_mysql_coro: procedure without fetch mode by query
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'strict_type' => true
- ];
-
- $clear = <<connect($server);
-
- if ($db->query($clear) && $db->query($procedure)) {
- for ($n = MAX_REQUESTS; $n--;) {
- $_map = $map;
- $res = $db->query('CALL reply("hello mysql!")');
- do {
- if (is_array($res)) {
- Assert::same(current($res[0]), array_shift($_map));
- } else {
- Assert::true($res);
- }
- } while ($res = $db->nextResult());
- Assert::same($db->affected_rows, 1);
- Assert::assert(empty($_map), 'there are some results lost!');
- }
- }
-
- echo "DONE\n";
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/procedure_in_fetch.phpt b/tests/swoole_mysql_coro/procedure_in_fetch.phpt
deleted file mode 100644
index baf72fdb7cc..00000000000
--- a/tests/swoole_mysql_coro/procedure_in_fetch.phpt
+++ /dev/null
@@ -1,82 +0,0 @@
---TEST--
-swoole_mysql_coro: procedure in fetch mode
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'fetch_mode' => true
- ];
-
- $clear = <<connect($server);
- if ($db->query($clear) && $db->query($procedure)) {
-
- //SWOOLE
- $_map = $map;
- $stmt = $db->prepare('CALL reply(?)');
- Assert::true($stmt->execute(['hello mysql!']));
- do {
- $res = $stmt->fetchAll();
- Assert::same(current($res[0]), array_shift($_map));
- } while ($ret = $stmt->nextResult());
- Assert::same($stmt->affected_rows, 1);
- Assert::assert(empty($_map), 'there are some results lost!');
-
- //PDO
- if (extension_loaded('PDO')) {
- $_map = $map;
- try {
- $pdo = new PDO(
- "mysql:host=" . MYSQL_SERVER_HOST . ";port=" . MYSQL_SERVER_PORT . ";dbname=" . MYSQL_SERVER_DB . ";charset=utf8",
- MYSQL_SERVER_USER, MYSQL_SERVER_PWD
- );
- $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
- $stmt = $pdo->prepare("CALL reply(?)");
- Assert::true($stmt->execute(['hello mysql!']));
- do {
- $res = $stmt->fetchAll();
- Assert::same(current($res[0]), array_shift($_map));
- } while ($ret = $stmt->nextRowset() and count($_map) > 0);
- Assert::same($stmt->rowCount(), 1, 'get the affected rows failed!');
- Assert::assert(empty($_map), 'there are some results lost!');
- } catch (\PDOException $e) {
- Assert::same($e->getCode(), 2054); // not support auth plugin
- }
- }
- }
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/procedure_single.phpt b/tests/swoole_mysql_coro/procedure_single.phpt
deleted file mode 100644
index cc876712e77..00000000000
--- a/tests/swoole_mysql_coro/procedure_single.phpt
+++ /dev/null
@@ -1,42 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql procedure single
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
-
- $clear = <<connect($server);
- if ($db->query($clear) && $db->query($procedure)) {
- $stmt = $db->prepare('CALL say(?)');
- for ($n = MAX_REQUESTS; $n--;) {
- $ret = $stmt->execute(['hello mysql!']);
- Assert::same(current($ret[0]), 'You said: "hello mysql!"');
- Assert::null($stmt->nextResult());
- }
- }
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/procedure_with_query.phpt b/tests/swoole_mysql_coro/procedure_with_query.phpt
deleted file mode 100644
index 1fec3a58a6e..00000000000
--- a/tests/swoole_mysql_coro/procedure_with_query.phpt
+++ /dev/null
@@ -1,65 +0,0 @@
---TEST--
-swoole_mysql_coro: procedure without query (#2117)
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
-
- $clear = <<connect($server);
-
- if ($db->query($clear) && $db->query($procedure)) {
- for ($n = MAX_REQUESTS_LOW; $n--;) {
- $res = $db->query('CALL reply("hello mysql!")');
- $_map = $map;
- do {
- Assert::same(current($res[0]), array_shift($_map));
- } while ($res = $db->nextResult());
- }
- for ($n = MAX_REQUESTS_LOW; $n--;) {
- $res = $db->query('CALL reply("hello mysql!")');
- $_map = $map;
- do {
- Assert::same(current($res[0]), array_shift($_map));
- } while ($res = $db->nextResult());
- Assert::same($db->affected_rows, 1, 'get the affected rows failed!');
- Assert::assert(empty($_map), 'there are some results lost!');
- }
- }
-
- echo "DONE\n";
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/procedure_with_query_and_prepare.phpt b/tests/swoole_mysql_coro/procedure_with_query_and_prepare.phpt
deleted file mode 100644
index 22a92273e5d..00000000000
--- a/tests/swoole_mysql_coro/procedure_with_query_and_prepare.phpt
+++ /dev/null
@@ -1,39 +0,0 @@
---TEST--
-swoole_mysql_coro: query 'CALL' statement & prepare (#2117)
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
-
- $clear = <<connect($server);
- if ($db->query($clear) && $db->query($procedure)) {
- $db->query('CALL sp_whoami()');
- Assert::null($db->nextResult());
- $stmt = $db->prepare('CALL sp_whoami()');
- $ret = $stmt->execute();
- Assert::assert(strpos(current($ret[0]), MYSQL_SERVER_USER) !== false);
- Assert::null($stmt->nextResult());
- }
-});
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/query.phpt b/tests/swoole_mysql_coro/query.phpt
deleted file mode 100644
index d459d979df8..00000000000
--- a/tests/swoole_mysql_coro/query.phpt
+++ /dev/null
@@ -1,63 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql client
---SKIPIF--
-
---FILE--
-parentFunc = function ($pid) use ($pm)
-{
- go(function () use ($pm) {
- echo httpGetBody("http://127.0.0.1:{$pm->getFreePort()}/");
- $pm->kill();
- });
-};
-
-$pm->childFunc = function () use ($pm)
-{
- $http = new Swoole\Http\Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE);
- $http->set(array(
- 'log_file' => '/dev/null'
- ));
- $http->on("WorkerStart", function (Swoole\Server $serv)
- {
- /**
- * @var $pm ProcessManager
- */
- global $pm;
- $pm->wakeup();
- });
- $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response)
- {
- $mysql = new Swoole\Coroutine\MySQL();
- $res = $mysql->connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ]);
- if (!$res)
- {
- fail:
- $response->end("ERROR\n");
- return;
- }
- $ret = $mysql->query('show tables', 2);
- if (!$ret) {
- goto fail;
- }
- if (count($ret) > 0) {
- $response->end("OK\n");
- }
- });
- $http->start();
-};
-
-$pm->childFirst();
-$pm->run();
-?>
---EXPECT--
-OK
diff --git a/tests/swoole_mysql_coro/query_multifield.phpt b/tests/swoole_mysql_coro/query_multifield.phpt
deleted file mode 100644
index b39c02da277..00000000000
--- a/tests/swoole_mysql_coro/query_multifield.phpt
+++ /dev/null
@@ -1,31 +0,0 @@
---TEST--
-swoole_mysql_coro: multi field
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
- $ret = $db->connect($server);
- if (Assert::true($ret)) {
- $n = range(0, FIELD_NUM - 1);
- $fields = implode(", ", $n);
- $result = $db->query("select $fields");
- Assert::assert(count($result[0]) == FIELD_NUM);
- echo "DONE\n";
- }
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/query_timeout.phpt b/tests/swoole_mysql_coro/query_timeout.phpt
deleted file mode 100644
index 5105153f733..00000000000
--- a/tests/swoole_mysql_coro/query_timeout.phpt
+++ /dev/null
@@ -1,32 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql query timeout
---SKIPIF--
-
---FILE--
-connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ]);
- if (Assert::true($ret)) {
- $s = microtime(true);
- $timeout = mt_rand(100, 500) / 1000;
- $ret = $mysql->query('select sleep(1)', $timeout);
- time_approximate($timeout, microtime(true) - $s);
- if (Assert::false($ret)) {
- Assert::same($mysql->errno, SWOOLE_MYSQLND_CR_SERVER_GONE_ERROR);
- }
- }
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/readonly.phpt b/tests/swoole_mysql_coro/readonly.phpt
deleted file mode 100644
index 69850419b46..00000000000
--- a/tests/swoole_mysql_coro/readonly.phpt
+++ /dev/null
@@ -1,53 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql use readonly user
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
- $connected = $root->connect($server);
- Assert::assert($connected);
-
- // create read only user
- $create = $root->query('CREATE USER `readonly`@`%` IDENTIFIED BY \'123456\';');
- Assert::assert($create);
- $grant = $root->query('GRANT SELECT ON *.* TO `readonly`@`%` WITH GRANT OPTION;');
- Assert::assert($grant);
-
- // use readonly
- $server['user'] = 'readonly';
- $server['password'] = '123456';
- $readonly = new Swoole\Coroutine\MySQL;
- $connected = $readonly->connect($server);
- Assert::assert($connected);
-
- // read
- $result = $readonly->query('SELECT * FROM userinfo');
- Assert::assert(is_array($result) && count($result) > 5);
- $id = $result[0]['id'];
- // write
- $delete = $readonly->query('DELETE FROM userinfo WHERE id=' . $id);
- Assert::assert(!$delete);
- echo $readonly->errno . "\n";
- echo $readonly->error . "\n";
-
- // drop
- Assert::assert($root->query('DROP ROLE readonly'));
-});
-Swoole\Event::wait();
-?>
---EXPECTF--
-1142
-SQLSTATE[42000] [1142] DELETE command denied to user 'readonly'@'%s' for table 'userinfo'
diff --git a/tests/swoole_mysql_coro/simple_query.phpt b/tests/swoole_mysql_coro/simple_query.phpt
deleted file mode 100644
index 484696df28b..00000000000
--- a/tests/swoole_mysql_coro/simple_query.phpt
+++ /dev/null
@@ -1,24 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql simple query
---SKIPIF--
-
---FILE--
-connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ]);
- Assert::assert($res);
- $ret = $mysql->query('show tables', 2);
- Assert::assert(is_array($ret));
- Assert::assert(count($ret) > 0);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/statement_closed.phpt b/tests/swoole_mysql_coro/statement_closed.phpt
deleted file mode 100644
index 2d908376287..00000000000
--- a/tests/swoole_mysql_coro/statement_closed.phpt
+++ /dev/null
@@ -1,30 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql prepare (destruct)
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
- $ret = $db->connect($server);
- assert($ret);
- $statement = $db->prepare('SELECT 1');
- assert($statement instanceof Co\Mysql\Statement);
- $ret = $statement->execute();
- assert($ret[0][1] === 1);
- $db->close();
- $ret = $db->connect($server);
- assert($ret);
- $ret = $statement->execute();
- assert(!$ret);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/statement_destruct.phpt b/tests/swoole_mysql_coro/statement_destruct.phpt
deleted file mode 100644
index a226edb2bab..00000000000
--- a/tests/swoole_mysql_coro/statement_destruct.phpt
+++ /dev/null
@@ -1,53 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql prepare (destruct)
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- ];
-
- $ret1 = $db->connect($server);
-
- $start_prepared_num = (int)(($db->query('show status like \'Prepared_stmt_count\''))[0]['Value']);
- if (!$ret1) {
- echo "CONNECT ERROR\n";
- return;
- }
- $stmt1 = $db->prepare('SELECT * FROM userinfo WHERE id=?');
- if (!$stmt1) {
- echo "PREPARE1 ERROR\n";
- return;
- }
- $stmt2 = $db->prepare('SELECT * FROM `userinfo`');
- if (!$stmt2) {
- echo "PREPARE2 ERROR\n";
- return;
- }
- $stmt3 = $db->prepare('SELECT `id` FROM `userinfo`');
- if (!$stmt3) {
- echo "PREPARE3 ERROR\n";
- return;
- }
-
- $prepared_num1 = (int)(($db->query('show status like \'Prepared_stmt_count\''))[0]['Value']);
- Assert::same($prepared_num1 - $start_prepared_num, 3);
- $stmt1 = null; //destruct
- unset($stmt2); //destruct
- $prepared_num2 = (int)(($db->query('show status like \'Prepared_stmt_count\''))[0]['Value']);
- Assert::same($prepared_num1 - $prepared_num2, 2);
-});
-
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/timeout.phpt b/tests/swoole_mysql_coro/timeout.phpt
deleted file mode 100644
index 9c0e78abb92..00000000000
--- a/tests/swoole_mysql_coro/timeout.phpt
+++ /dev/null
@@ -1,38 +0,0 @@
---TEST--
-swoole_mysql_coro: timeout
---SKIPIF--
-
---FILE--
-connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ]);
- Assert::assert($connected);
- $statement = $mysql->prepare('SELECT SLEEP(1)');
- Assert::assert($statement instanceof Co\Mysql\Statement);
- $timeout = ms_random(0.1, 0.5);
- $s = microtime(true);
- $use_query = !!mt_rand(0, 1);
- if ($use_query) {
- $ret = $mysql->query('SELECT SLEEP(1)', $timeout);
- } else {
- $ret = $statement->execute(null, $timeout);
- }
- time_approximate($timeout, microtime(true) - $s);
- Assert::assert(!$ret);
- Assert::same($use_query ? $mysql->errno : $statement->errno, SWOOLE_MYSQLND_CR_SERVER_GONE_ERROR);
- });
-}
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/transaction.phpt b/tests/swoole_mysql_coro/transaction.phpt
deleted file mode 100644
index 34b9ff47f09..00000000000
--- a/tests/swoole_mysql_coro/transaction.phpt
+++ /dev/null
@@ -1,44 +0,0 @@
---TEST--
-swoole_mysql_coro: transaction
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
- $db->connect($server);
-
- $random = mt_rand();
- Assert::assert($db->begin());
- Assert::assert($db->query('INSERT INTO ckl (`domain`,`path`,`name`) VALUES ("www.swoole.com", "/", "' . $random . '")'));
- Assert::assert(!empty($db->query('SELECT `name` FROM `ckl` WHERE `name`="' . $random . '"')));
- Assert::assert($db->rollback());
- Assert::assert(empty($db->query('SELECT `name` FROM `ckl` WHERE `name`="' . $random . '"')));
- $random = mt_rand();
- Assert::assert($db->begin());
- Assert::assert($db->query('INSERT INTO ckl (`domain`,`path`,`name`) VALUES ("www.swoole.com", "/", "' . $random . '")'));
- Assert::assert($db->commit());
- Assert::assert(!empty($db->query('SELECT `name` FROM `ckl` WHERE `name`="' . $random . '"')));
- Assert::assert($db->query('DELETE FROM `ckl` WHERE `name`="' . $random . '"'));
- Assert::assert(empty($db->query('SELECT `name` FROM `ckl` WHERE `name`="' . $random . '"')));
-
- $db->setDefer();
- Assert::throws(function () use ($db) { $db->begin(); }, Exception::class);
- Assert::throws(function () use ($db) { $db->commit(); }, Exception::class);
- Assert::throws(function () use ($db) { $db->rollback(); }, Exception::class);
- echo "DONE\n";
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/unixsocket.phpt b/tests/swoole_mysql_coro/unixsocket.phpt
deleted file mode 100644
index 377ee006d04..00000000000
--- a/tests/swoole_mysql_coro/unixsocket.phpt
+++ /dev/null
@@ -1,26 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql connection on unix socket
---SKIPIF--
-
---FILE--
- 'unix:/' . MYSQL_SERVER_PATH,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB
- ];
- Assert::assert($db->connect($server));
- Assert::same($db->query('SELECT 1'), [['1' => '1']]);
- echo "DONE\n";
-});
-?>
---EXPECTF--
-DONE
diff --git a/tests/swoole_mysql_coro/userinfo.phpt b/tests/swoole_mysql_coro/userinfo.phpt
deleted file mode 100644
index f4af02765ac..00000000000
--- a/tests/swoole_mysql_coro/userinfo.phpt
+++ /dev/null
@@ -1,41 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql prepare dtor
---SKIPIF--
-
---FILE--
-connect([
- 'host' => MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'strict_type' => (PHP_VERSION_ID >= 80100)
- ]);
- $result = $mysql->query('SELECT * FROM `userinfo`');
- $pdo = new PDO(
- "mysql:host=" . MYSQL_SERVER_HOST . ";port=" . MYSQL_SERVER_PORT . ";dbname=" . MYSQL_SERVER_DB . ";charset=utf8",
- MYSQL_SERVER_USER, MYSQL_SERVER_PWD
- );
- $pdo_result = $pdo->query('SELECT * FROM `userinfo`')->fetchAll(PDO::FETCH_ASSOC);
- Assert::same($result, $pdo_result);
-
- $result = $mysql->prepare('SELECT * FROM `userinfo`')->execute();
- $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
- $pdo_stmt = $pdo->prepare('SELECT * FROM `userinfo`');
- $pdo_stmt->execute();
- $pdo_result =$pdo_stmt->fetchAll(PDO::FETCH_ASSOC);
-
- Assert::same($result, $pdo_result);
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_mysql_coro/without_fetch.phpt b/tests/swoole_mysql_coro/without_fetch.phpt
deleted file mode 100644
index 253444f1a36..00000000000
--- a/tests/swoole_mysql_coro/without_fetch.phpt
+++ /dev/null
@@ -1,30 +0,0 @@
---TEST--
-swoole_mysql_coro: just execute (test memory leak)
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => MYSQL_SERVER_PWD,
- 'database' => MYSQL_SERVER_DB,
- 'fetch_mode' => true
- ];
-
- $db->connect($server);
- $stmt = $db->prepare('SELECT * FROM `userinfo` LIMIT 1');
- Assert::true($stmt->execute());
- Assert::true($stmt->execute());
- Assert::true($stmt->execute());
- Assert::assert(is_array($stmt->fetchAll()));
-});
-?>
---EXPECT--
diff --git a/tests/swoole_mysql_coro/wrong_password.phpt b/tests/swoole_mysql_coro/wrong_password.phpt
deleted file mode 100644
index 8b7e619254d..00000000000
--- a/tests/swoole_mysql_coro/wrong_password.phpt
+++ /dev/null
@@ -1,25 +0,0 @@
---TEST--
-swoole_mysql_coro: mysql connect with wrong password
---SKIPIF--
-
---FILE--
- MYSQL_SERVER_HOST,
- 'port' => MYSQL_SERVER_PORT,
- 'user' => MYSQL_SERVER_USER,
- 'password' => 'i am hack',
- 'database' => MYSQL_SERVER_DB
- ];
- $connected = $db->connect($server);
- Assert::assert(!$connected);
- echo $db->connect_errno . "\n";
- echo $db->connect_error, "\n";
-});
-?>
---EXPECTF--
-1045
-SQLSTATE[28000] [1045] Access denied for user 'root'@'%s' (using password: YES)
diff --git a/tests/swoole_mysql_coro/z_reset.phpt b/tests/swoole_mysql_coro/z_reset.phpt
deleted file mode 100644
index fd307469210..00000000000
--- a/tests/swoole_mysql_coro/z_reset.phpt
+++ /dev/null
@@ -1,11 +0,0 @@
---TEST--
-swoole_mysql_coro: reset test mysql database
---SKIPIF--
-
---FILE--
- /dev/null`;
-?>
---EXPECT--
diff --git a/tests/swoole_pdo_sqlite/pdo_sqlite_createaggregate.phpt b/tests/swoole_pdo_sqlite/pdo_sqlite_createaggregate.phpt
index c1220e88bbd..cc0b145e6f8 100644
--- a/tests/swoole_pdo_sqlite/pdo_sqlite_createaggregate.phpt
+++ b/tests/swoole_pdo_sqlite/pdo_sqlite_createaggregate.phpt
@@ -22,7 +22,6 @@ run(function() {
$db->sqliteCreateAggregate('testing', function(&$a, $b) { $a .= $b; return $a; }, function(&$v) { return $v; });
-
foreach ($db->query('SELECT testing(name) FROM foobar') as $row) {
var_dump($row);
}
diff --git a/tests/swoole_pgsql_coro/bug_4911.phpt b/tests/swoole_pgsql_coro/bug_4911.phpt
deleted file mode 100644
index a50da2bc3ae..00000000000
--- a/tests/swoole_pgsql_coro/bug_4911.phpt
+++ /dev/null
@@ -1,27 +0,0 @@
---TEST--
-swoole_pgsql_coro: bug 4911 https://github.com/swoole/swoole-src/issues/4911
---SKIPIF--
-
---FILE--
-connect('host=pgsql;port=5432;dbname=test123123;user=root;password=root');
- echo $pgsql->error.PHP_EOL;
-
- $pgsql = new Swoole\Coroutine\PostgreSQL();
- $connected = $pgsql->connect('host=pgsql;port=5432;dbname=test;user=root123;password=root');
- echo $pgsql->error.PHP_EOL;
-
- $pgsql = new Swoole\Coroutine\PostgreSQL();
- $connected = $pgsql->connect('host=pgsql;port=5432;dbname=test;user=root;password=');
- echo $pgsql->error.PHP_EOL;
-});
-?>
---EXPECT--
-FATAL: database "test123123" does not exist
-
-FATAL: password authentication failed for user "root123"
-
-fe_sendauth: no password supplied
diff --git a/tests/swoole_pgsql_coro/connect.phpt b/tests/swoole_pgsql_coro/connect.phpt
deleted file mode 100644
index cb56c5d72a1..00000000000
--- a/tests/swoole_pgsql_coro/connect.phpt
+++ /dev/null
@@ -1,14 +0,0 @@
---TEST--
-swoole_pgsql_coro: connect
---SKIPIF--
-
---FILE--
-connect(PGSQL_CONNECTION_STRING);
- Assert::true($connected, (string) $pgsql->error);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_pgsql_coro/connect_failed.phpt b/tests/swoole_pgsql_coro/connect_failed.phpt
deleted file mode 100644
index 85944d81a45..00000000000
--- a/tests/swoole_pgsql_coro/connect_failed.phpt
+++ /dev/null
@@ -1,16 +0,0 @@
---TEST--
-swoole_pgsql_coro: connect failed
---SKIPIF--
-
---FILE--
-connect(''));
-
- $connected = $pgsql->connect(PGSQL_CONNECTION_STRING);
- Assert::true($connected, (string) $pgsql->error);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_pgsql_coro/error.phpt b/tests/swoole_pgsql_coro/error.phpt
deleted file mode 100644
index 0bd49f35e67..00000000000
--- a/tests/swoole_pgsql_coro/error.phpt
+++ /dev/null
@@ -1,44 +0,0 @@
---TEST--
-swoole_pgsql_coro: error
---SKIPIF--
-
---FILE--
-connect(PGSQL_CONNECTION_STRING);
- Assert::true($connected, (string) $pgsql->error);
-
- $stmt = $pgsql->query('SELECT * FROM not_exists;');
- Assert::false($stmt, (string) $pgsql->error);
-
- $stmt = $pgsql->prepare('SELECT * FROM not_exists;');
- Assert::false($stmt, (string) $pgsql->error);
-
- $stmt = $pgsql->prepare("INSERT INTO weather(city, temp_lo, temp_hi, prcp, date) VALUES ($1, $2, $3, $4, $5) RETURNING id");
- Assert::true(false !== $stmt, (string) $pgsql->error);
-
- $result = $stmt->affectedRows();
- Assert::false($result, (string) $stmt->error);
-
- $result = $stmt->numRows();
- Assert::false($result, (string) $stmt->error);
-
- $result = $stmt->fieldCount();
- Assert::false($result, (string) $stmt->error);
-
- $result = $stmt->fetchObject();
- Assert::false($result, (string) $stmt->error);
-
- $result = $stmt->fetchAssoc();
- Assert::false($result, (string) $stmt->error);
-
- $result = $stmt->fetchArray();
- Assert::false($result, (string) $stmt->error);
-
- $result = $stmt->fetchRow();
- Assert::false($result, (string) $stmt->error);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_pgsql_coro/escape.phpt b/tests/swoole_pgsql_coro/escape.phpt
deleted file mode 100644
index 59dea5223f8..00000000000
--- a/tests/swoole_pgsql_coro/escape.phpt
+++ /dev/null
@@ -1,18 +0,0 @@
---TEST--
-swoole_pgsql_coro: escape
---SKIPIF--
-
---FILE--
-connect(PGSQL_CONNECTION_STRING);
- Assert::true($connected, (string) $pgsql->error);
-
- $result = $pgsql->escape("' or 1=1 & 2");
- Assert::true(false !== $result, (string) $pgsql->error);
- Assert::eq($result, "'' or 1=1 & 2");
-});
-?>
---EXPECT--
diff --git a/tests/swoole_pgsql_coro/fetch.phpt b/tests/swoole_pgsql_coro/fetch.phpt
deleted file mode 100644
index cbfd629b70a..00000000000
--- a/tests/swoole_pgsql_coro/fetch.phpt
+++ /dev/null
@@ -1,158 +0,0 @@
---TEST--
-swoole_pgsql_coro: fetch
---SKIPIF--
-
---FILE--
-connect(PGSQL_CONNECTION_STRING);
- Assert::true($connected, (string) $pgsql->error);
-
- $stmt = $pgsql->query('SELECT * FROM weather;');
- Assert::true(false !== $stmt, (string) $pgsql->error);
-
- var_dump($stmt->fetchObject(0), $stmt->fetchObject(1));
- var_dump($stmt->fetchAssoc(0), $stmt->fetchAssoc(1));
- var_dump($stmt->fetchArray(0), $stmt->fetchArray(1));
- var_dump($stmt->fetchRow(0), $stmt->fetchRow(1));
-});
-?>
---EXPECTF--
-object(stdClass)#%d (6) {
- ["id"]=>
- int(1)
- ["city"]=>
- string(13) "San Francisco"
- ["temp_lo"]=>
- int(46)
- ["temp_hi"]=>
- int(50)
- ["prcp"]=>
- float(0.25)
- ["date"]=>
- string(10) "1994-11-27"
-}
-object(stdClass)#%d (6) {
- ["id"]=>
- int(2)
- ["city"]=>
- string(5) "Test2"
- ["temp_lo"]=>
- int(11)
- ["temp_hi"]=>
- int(22)
- ["prcp"]=>
- float(0.3)
- ["date"]=>
- string(10) "1994-11-28"
-}
-array(6) {
- ["id"]=>
- int(1)
- ["city"]=>
- string(13) "San Francisco"
- ["temp_lo"]=>
- int(46)
- ["temp_hi"]=>
- int(50)
- ["prcp"]=>
- float(0.25)
- ["date"]=>
- string(10) "1994-11-27"
-}
-array(6) {
- ["id"]=>
- int(2)
- ["city"]=>
- string(5) "Test2"
- ["temp_lo"]=>
- int(11)
- ["temp_hi"]=>
- int(22)
- ["prcp"]=>
- float(0.3)
- ["date"]=>
- string(10) "1994-11-28"
-}
-array(12) {
- [0]=>
- int(1)
- ["id"]=>
- int(1)
- [1]=>
- string(13) "San Francisco"
- ["city"]=>
- string(13) "San Francisco"
- [2]=>
- int(46)
- ["temp_lo"]=>
- int(46)
- [3]=>
- int(50)
- ["temp_hi"]=>
- int(50)
- [4]=>
- float(0.25)
- ["prcp"]=>
- float(0.25)
- [5]=>
- string(10) "1994-11-27"
- ["date"]=>
- string(10) "1994-11-27"
-}
-array(12) {
- [0]=>
- int(2)
- ["id"]=>
- int(2)
- [1]=>
- string(5) "Test2"
- ["city"]=>
- string(5) "Test2"
- [2]=>
- int(11)
- ["temp_lo"]=>
- int(11)
- [3]=>
- int(22)
- ["temp_hi"]=>
- int(22)
- [4]=>
- float(0.3)
- ["prcp"]=>
- float(0.3)
- [5]=>
- string(10) "1994-11-28"
- ["date"]=>
- string(10) "1994-11-28"
-}
-array(6) {
- [0]=>
- int(1)
- [1]=>
- string(13) "San Francisco"
- [2]=>
- int(46)
- [3]=>
- int(50)
- [4]=>
- float(0.25)
- [5]=>
- string(10) "1994-11-27"
-}
-array(6) {
- [0]=>
- int(2)
- [1]=>
- string(5) "Test2"
- [2]=>
- int(11)
- [3]=>
- int(22)
- [4]=>
- float(0.3)
- [5]=>
- string(10) "1994-11-28"
-}
diff --git a/tests/swoole_pgsql_coro/insert.phpt b/tests/swoole_pgsql_coro/insert.phpt
deleted file mode 100644
index d82e898d4f0..00000000000
--- a/tests/swoole_pgsql_coro/insert.phpt
+++ /dev/null
@@ -1,19 +0,0 @@
---TEST--
-swoole_pgsql_coro: insert
---SKIPIF--
-
---FILE--
-connect(PGSQL_CONNECTION_STRING);
- Assert::true($connected, (string) $pgsql->error);
-
- $stmt = $pgsql->query("INSERT INTO weather(city, temp_lo, temp_hi, prcp, date) VALUES ('Shanghai', 88, 10, 0.75,'1993-11-27') RETURNING id");
- Assert::true(false !== $stmt, (string) $pgsql->error);
- Assert::eq($stmt->numRows(), 1);
- Assert::greaterThan($stmt->fetchAssoc()['id'], 1);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_pgsql_coro/lob.phpt b/tests/swoole_pgsql_coro/lob.phpt
deleted file mode 100644
index 83d7fd3d141..00000000000
--- a/tests/swoole_pgsql_coro/lob.phpt
+++ /dev/null
@@ -1,110 +0,0 @@
---TEST--
-swoole_pgsql_coro: lob
---SKIPIF--
-
---FILE--
-connect(PGSQL_CONNECTION_STRING);
- Assert::true($connected, (string) $pgsql->error);
-
- $stmt = $pgsql->prepare("INSERT INTO weather(city, temp_lo, temp_hi, prcp, date) VALUES ($1, $2, $3, $4, $5) RETURNING id");
- Assert::true(false !== $stmt, (string) $pgsql->error);
-
- $fp = fopen('php://memory', 'w+');
- Assert::true(!!$fp);
- fwrite($fp, 'Wuxi');
- rewind($fp);
- $result = $stmt->execute([$fp, rand(1000, 99999), 10, 0.75, '1993-11-23']);
- fclose($fp);
- Assert::true(false !== $result, (string) $pgsql->error);
- $id = $stmt->fetchAssoc()['id'] ?? null;
- Assert::greaterThanEq($id, 1);
- $stmt2 = $pgsql->prepare('select * from weather where id = $1');
- Assert::true(false !== $stmt2, (string) $pgsql->error);
- $stmt2->execute([$id]);
- var_dump($stmt2->fetchAssoc());
-
- $result = $pgsql->query('begin');
- Assert::notEq($result, false, (string) $pgsql->error);
- $stmt = $pgsql->prepare("INSERT INTO oid(oid) VALUES ($1) RETURNING id");
- Assert::true(false !== $stmt, (string) $pgsql->error);
- $oid = $pgsql->createLOB();
- Assert::integer($oid, (string) $pgsql->error);
- $lob = $pgsql->openLOB($oid, 'wb');
- Assert::notEq($lob, false, (string) $pgsql->error);
- fwrite($lob, 'Shanghai');
- $result = $stmt->execute([$lob]);
- Assert::true(false !== $result, (string) $pgsql->error);
- $result = $pgsql->query('commit');
- Assert::notEq($result, false, (string) $pgsql->error);
-
- $result = $pgsql->query('begin');
- Assert::notEq($result, false, (string) $pgsql->error);
- $id = $stmt->fetchAssoc()['id'] ?? null;
- Assert::greaterThanEq($id, 1);
- $stmt2 = $pgsql->prepare('select * from oid where id = $1');
- Assert::true(false !== $stmt2, (string) $pgsql->error);
- $stmt2->execute([$id]);
- $row = $stmt2->fetchRow(0, SW_PGSQL_ASSOC);
- $lob = $pgsql->openLOB($row['oid']);
- Assert::notEq($lob, false, (string) $pgsql->error);
- Assert::eq(fgets($lob), 'Shanghai');
- $result = $pgsql->query('commit');
- Assert::notEq($result, false, (string) $pgsql->error);
-
- $result = $pgsql->query('begin');
- Assert::notEq($result, false, (string) $pgsql->error);
- $oid = $pgsql->createLOB();
- Assert::integer($oid, (string) $pgsql->error);
- $lob = $pgsql->openLOB($oid, 'wb');
- Assert::notEq($lob, false, (string) $pgsql->error);
- var_dump($lob);
- fwrite($lob, 'test');
- $result = $pgsql->query('rollback');
- Assert::notEq($result, false, (string) $pgsql->error);
- var_dump($lob);
-
- $result = $pgsql->query('begin');
- Assert::notEq($result, false, (string) $pgsql->error);
- $oid = $pgsql->createLOB();
- Assert::integer($oid, (string) $pgsql->error);
- $lob = $pgsql->openLOB($oid, 'wb');
- Assert::notEq($lob, false, (string) $pgsql->error);
- var_dump($lob);
- fwrite($lob, 'test');
- $result = $pgsql->query('commit');
- Assert::notEq($result, false, (string) $pgsql->error);
- var_dump($lob);
-
- $result = $pgsql->query('begin');
- Assert::notEq($result, false, (string) $pgsql->error);
- $lob = $pgsql->openLOB($oid, 'wb');
- Assert::notEq($lob, false, (string) $pgsql->error);
- var_dump($lob);
- var_dump(fgets($lob));
-});
-?>
---EXPECTF--
-array(6) {
- ["id"]=>
- int(%d)
- ["city"]=>
- string(4) "Wuxi"
- ["temp_lo"]=>
- int(%d)
- ["temp_hi"]=>
- int(10)
- ["prcp"]=>
- float(0.75)
- ["date"]=>
- string(10) "1993-11-23"
-}
-resource(%d) of type (stream)
-resource(%d) of type (Unknown)
-resource(%d) of type (stream)
-resource(%d) of type (Unknown)
-resource(%d) of type (stream)
-string(4) "test"
diff --git a/tests/swoole_pgsql_coro/no_field_name.phpt b/tests/swoole_pgsql_coro/no_field_name.phpt
deleted file mode 100644
index 35c114c510e..00000000000
--- a/tests/swoole_pgsql_coro/no_field_name.phpt
+++ /dev/null
@@ -1,22 +0,0 @@
---TEST--
-swoole_pgsql_coro: no field name
---SKIPIF--
-
---FILE--
-connect(PGSQL_CONNECTION_STRING);
- Assert::true($connected, (string) $pgsql->error);
-
- $stmt = $pgsql->query('SELECT 11, 22');
- Assert::true(false !== $stmt, (string) $pgsql->error);
-
- $arr = $stmt->fetchAll();
- Assert::isArray($arr);
- Assert::eq($arr[0]['?column?'], 11);
- Assert::eq($arr[0]['?column?1'], 22);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_pgsql_coro/not_connected.phpt b/tests/swoole_pgsql_coro/not_connected.phpt
deleted file mode 100644
index f508c5c0564..00000000000
--- a/tests/swoole_pgsql_coro/not_connected.phpt
+++ /dev/null
@@ -1,19 +0,0 @@
---TEST--
-swoole_pgsql_coro: not connected
---SKIPIF--
-
---FILE--
-escape(''));
- Assert::false($pgsql->escapeLiteral(''));
- Assert::false($pgsql->escapeIdentifier(''));
- Assert::false($pgsql->query(''));
- Assert::false($pgsql->prepare(''));
- Assert::false($pgsql->metaData(''));
-});
-?>
---EXPECT--
diff --git a/tests/swoole_pgsql_coro/prepare.phpt b/tests/swoole_pgsql_coro/prepare.phpt
deleted file mode 100644
index 8968244cc77..00000000000
--- a/tests/swoole_pgsql_coro/prepare.phpt
+++ /dev/null
@@ -1,19 +0,0 @@
---TEST--
-swoole_pgsql_coro: prepare
---SKIPIF--
-
---FILE--
-connect(PGSQL_CONNECTION_STRING);
- Assert::true($connected, (string) $pgsql->error);
-
- $stmt = $pgsql->prepare("INSERT INTO weather(city, temp_lo, temp_hi, prcp, date) VALUES ($1, $2, $3, $4, $5) RETURNING id");
- Assert::true(false !== $stmt, (string) $pgsql->error);
- $result = $stmt->execute(['Beijing', rand(1000, 99999), 10, 0.75, '1993-11-23']);
- Assert::true(false !== $result, (string) $pgsql->error);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_pgsql_coro/query.phpt b/tests/swoole_pgsql_coro/query.phpt
deleted file mode 100644
index 499f27bc6cc..00000000000
--- a/tests/swoole_pgsql_coro/query.phpt
+++ /dev/null
@@ -1,21 +0,0 @@
---TEST--
-swoole_pgsql_coro: query
---SKIPIF--
-
---FILE--
-connect(PGSQL_CONNECTION_STRING);
- Assert::true($connected, (string) $pgsql->error);
-
- $stmt = $pgsql->query('SELECT * FROM weather;');
- Assert::true(false !== $stmt, (string) $pgsql->error);
-
- $arr = $stmt->fetchAll();
- Assert::isArray($arr);
- Assert::eq($arr[0]['city'], 'San Francisco');
-});
-?>
---EXPECT--
diff --git a/tests/swoole_redis_coro/auth.phpt b/tests/swoole_redis_coro/auth.phpt
deleted file mode 100644
index c872c100022..00000000000
--- a/tests/swoole_redis_coro/auth.phpt
+++ /dev/null
@@ -1,38 +0,0 @@
---TEST--
-swoole_redis_coro: redis auth
---SKIPIF--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-if (!$redis->auth(REDIS_SERVER_PWD)) {
- skip('no auth');
-}
-?>
---FILE--
-getAuth());
- Assert::assert($redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT));
- Assert::false($redis->getAuth());
- Assert::assert(!$redis->auth(get_safe_random()));
- Assert::same($redis->errCode, SOCKET_EINVAL);
- Assert::false($redis->getAuth());
- Assert::assert($redis->auth(REDIS_SERVER_PWD));
- Assert::same($redis->getAuth(), REDIS_SERVER_PWD);
- // auth by connect
- $redis = new Swoole\Coroutine\Redis(['password' => REDIS_SERVER_PWD]);
- Assert::assert($redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT));
- Assert::assert($redis->set('foo', $random = get_safe_random()));
- Assert::same($redis->get('foo'), $random);
- // auth failed when connect
- $redis = new Swoole\Coroutine\Redis(['password' => get_safe_random()]);
- Assert::assert(!$redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT));
- echo "DONE\n";
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/auto_reconnect.phpt b/tests/swoole_redis_coro/auto_reconnect.phpt
deleted file mode 100644
index 7806f315daf..00000000000
--- a/tests/swoole_redis_coro/auto_reconnect.phpt
+++ /dev/null
@@ -1,23 +0,0 @@
---TEST--
-swoole_redis_coro: redis reconnect
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::assert($ret);
- $ret = $redis->close();
- Assert::assert($ret);
- $ret = $redis->set('foo', 'bar');
- Assert::assert($ret);
- $ret = $redis->get('foo');
- Assert::same($ret, 'bar');
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/auto_reconnect_ex.phpt b/tests/swoole_redis_coro/auto_reconnect_ex.phpt
deleted file mode 100644
index fa4dabb587f..00000000000
--- a/tests/swoole_redis_coro/auto_reconnect_ex.phpt
+++ /dev/null
@@ -1,68 +0,0 @@
---TEST--
-swoole_redis_coro: auto reconnect after server side close the connection
---SKIPIF--
-
---FILE--
-parentFunc = function () use ($pm) {
- Co\run(function () use ($pm) {
- $redis = new Swoole\Coroutine\Redis;
- $ret = $redis->connect('127.0.0.1', $pm->getFreePort());
- Assert::true($ret);
- for ($n = MAX_REQUESTS; $n--;) {
- $ret = $redis->set('random_val', $random = get_safe_random(128));
- Assert::true($ret, "code: {$redis->errCode}, msg={$redis->errMsg}");
- $ret = $redis->get('random_val');
- Assert::true($ret && $ret === $random, "code: {$redis->errCode}, msg={$redis->errMsg}");
- Co::sleep(0.001);
- }
- $redis->setOptions(['reconnect' => false]);
- for ($n = MAX_REQUESTS; $n--;) {
- $ret = $redis->set('random_val', $random = get_safe_random(128));
- Assert::true($n === MAX_REQUESTS ? $ret : !$ret);
- $ret = $redis->get('random_val');
- Assert::true($n === MAX_REQUESTS ? ($ret && $ret === $random) : !$ret);
- Co::sleep(0.001);
- }
- });
- $pm->kill();
- echo "DONE\n";
-};
-$pm->childFunc = function () use ($pm) {
- $server = new Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE);
- $server->data = [];
- $server->on('WorkerStart', function ($server) use ($pm) {
- $pm->wakeup();
- });
- $server->setHandler('GET', function ($fd, $data) use ($server) {
- if (count($data) == 0) {
- return Server::format(Server::ERROR, "ERR wrong number of arguments for 'GET' command");
- }
- $key = $data[0];
- if (empty($server->data[$key])) {
- $server->send($fd, Server::format(Server::NIL));
- } else {
- $server->send($fd, Server::format(Server::STRING, $server->data[$key]));
- }
- $server->close($fd);
- });
- $server->setHandler('SET', function ($fd, $data) use ($server) {
- if (count($data) < 2) {
- $server->send($fd, Server::format(Server::ERROR, "ERR wrong number of arguments for 'SET' command"));
- }
- $key = $data[0];
- $server->data[$key] = $data[1];
- $server->send($fd, Server::format(Server::STATUS, 'OK'));
- });
- $server->start();
-};
-$pm->childFirst();
-$pm->run();
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/basic.phpt b/tests/swoole_redis_coro/basic.phpt
deleted file mode 100644
index 8afcfcaaab8..00000000000
--- a/tests/swoole_redis_coro/basic.phpt
+++ /dev/null
@@ -1,63 +0,0 @@
---TEST--
-swoole_redis_coro: redis client
---SKIPIF--
-
---FILE--
-parentFunc = function ($pid) use ($pm)
-{
- go(function () use ($pm) {
- echo httpGetBody("http://127.0.0.1:{$pm->getFreePort()}/");
- $pm->kill();
- });
-};
-
-$pm->childFunc = function () use ($pm)
-{
- $http = new Swoole\Http\Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE);
- $http->set(array(
- 'log_file' => '/dev/null'
- ));
- $http->on("WorkerStart", function (Swoole\Server $serv)
- {
- /**
- * @var $pm ProcessManager
- */
- global $pm;
- $pm->wakeup();
- });
- $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response)
- {
- $redis = new Swoole\Coroutine\Redis();
- $res = $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- if (!$res)
- {
- fail:
- $response->end("ERROR\n");
- return;
- }
-
- $ret = $redis->set('key', 'value');
- if (!$ret) {
- goto fail;
- }
- $ret = $redis->get('key');
- if (!$ret) {
- goto fail;
- }
- Assert::same($ret, "value");
- if (strlen($ret) > 0) {
- $response->end("OK\n");
- }
- });
- $http->start();
-};
-
-$pm->childFirst();
-$pm->run();
-?>
---EXPECT--
-OK
diff --git a/tests/swoole_redis_coro/bug_lock.phpt b/tests/swoole_redis_coro/bug_lock.phpt
deleted file mode 100644
index 1eb2c6e5c3e..00000000000
--- a/tests/swoole_redis_coro/bug_lock.phpt
+++ /dev/null
@@ -1,35 +0,0 @@
---TEST--
-swoole_redis_coro: redis client
---SKIPIF--
-
---FILE--
-lock('SWOOLE_TEST_LOCK')) {
- echo "ERROR\n";
- $redis_lock->unlock('SWOOLE_TEST_LOCK');
- } else {
- echo "FREE\n";
- }
- }
- SQLPool::release();
-});
-
-Swoole\Event::wait();
-?>
---EXPECT--
-LOCK
-FREE
-LOCK
-ERROR
-LOCK
-FREE
diff --git a/tests/swoole_redis_coro/compatibility_mode/hExists.phpt b/tests/swoole_redis_coro/compatibility_mode/hExists.phpt
deleted file mode 100644
index d93df485443..00000000000
--- a/tests/swoole_redis_coro/compatibility_mode/hExists.phpt
+++ /dev/null
@@ -1,23 +0,0 @@
---TEST--
-swoole_redis_coro/compatibility_mode: hExists
---SKIPIF--
-
---FILE--
-setOptions(['compatibility_mode' => true]);
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-
- $redis->delete(KEY);
- $redis->hSet(KEY, 'field', 'val1');
-
- Assert::true($redis->hExists(KEY, 'field') === true);
- Assert::true($redis->hExists(KEY, 'field_not_found') === false);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_redis_coro/connect_timeout.phpt b/tests/swoole_redis_coro/connect_timeout.phpt
deleted file mode 100644
index cf49ac852cf..00000000000
--- a/tests/swoole_redis_coro/connect_timeout.phpt
+++ /dev/null
@@ -1,21 +0,0 @@
---TEST--
-swoole_redis_coro: redis client connect timeout
---SKIPIF--
-
---FILE--
- $timeout]);
- $s = microtime(true);
- $ret = $redis->connect('192.0.0.1', 9000);
- Assert::assert(!$ret);
- Assert::assert($redis->errCode === SOCKET_ETIMEDOUT);
- time_approximate($timeout, microtime(true) - $s);
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/connect_to_wrong.phpt b/tests/swoole_redis_coro/connect_to_wrong.phpt
deleted file mode 100644
index c58384b409e..00000000000
--- a/tests/swoole_redis_coro/connect_to_wrong.phpt
+++ /dev/null
@@ -1,19 +0,0 @@
---TEST--
-swoole_redis_coro: redis client set options
---SKIPIF--
-
---FILE--
- -1]);
-go(function () {
- $redis = new Swoole\Coroutine\Redis();
- $redis->connect(MYSQL_SERVER_HOST, MYSQL_SERVER_PORT);
- Assert::assert(!$redis->set('foo', 'bar'));
- Assert::same($redis->errType, SWOOLE_REDIS_ERR_PROTOCOL);
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/connect_twice-2.phpt b/tests/swoole_redis_coro/connect_twice-2.phpt
deleted file mode 100644
index 126862278fe..00000000000
--- a/tests/swoole_redis_coro/connect_twice-2.phpt
+++ /dev/null
@@ -1,64 +0,0 @@
---TEST--
-swoole_redis_coro: redis client
---SKIPIF--
-
---FILE--
-parentFunc = function ($pid) use ($pm)
-{
- go(function () use ($pm) {
- echo httpGetBody("http://127.0.0.1:{$pm->getFreePort()}/");
- $pm->kill();
- });
-};
-
-$pm->childFunc = function () use ($pm)
-{
- $http = new Swoole\Http\Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE);
- $http->set(array(
- 'log_file' => '/dev/null'
- ));
- $http->on("WorkerStart", function (Swoole\Server $serv)
- {
- /**
- * @var $pm ProcessManager
- */
- global $pm;
- $pm->wakeup();
- });
- $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response)
- {
- $redis = new Swoole\Coroutine\Redis();
- $res = $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- $res2 = @$redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::true($res2);
- if (!$res)
- {
- fail:
- $response->end("ERROR\n");
- return;
- }
- $ret = $redis->set('key', 'value');
- if (!$ret) {
- goto fail;
- }
- $ret = $redis->get('key');
- if (!$ret) {
- goto fail;
- }
- Assert::same($ret, "value");
- if (strlen($ret) > 0) {
- $response->end("OK\n");
- }
- });
- $http->start();
-};
-
-$pm->childFirst();
-$pm->run();
-?>
---EXPECT--
-OK
diff --git a/tests/swoole_redis_coro/connect_twice.phpt b/tests/swoole_redis_coro/connect_twice.phpt
deleted file mode 100644
index 6bc35009d85..00000000000
--- a/tests/swoole_redis_coro/connect_twice.phpt
+++ /dev/null
@@ -1,33 +0,0 @@
---TEST--
-swoole_redis_coro: connect twice
---SKIPIF--
-
---FILE--
- SWOOLE_LOG_TRACE, 'trace_flags' => SWOOLE_TRACE_ALL]);
-
-go(function () {
- $redis = new Swoole\Coroutine\Redis();
- echo "connect [1]\n";
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::true($redis->connected);
- echo "close [1]\n";
- $redis->close();
- Assert::false($redis->connected);
- echo "connect [2]\n";
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::true($redis->connected);
- echo "close [2]\n";
- $redis->close();
- Assert::false($redis->connected);
-});
-
-Swoole\Event::wait();
-?>
---EXPECT--
-connect [1]
-close [1]
-connect [2]
-close [2]
diff --git a/tests/swoole_redis_coro/curd.phpt b/tests/swoole_redis_coro/curd.phpt
deleted file mode 100644
index fb3d0e6208f..00000000000
--- a/tests/swoole_redis_coro/curd.phpt
+++ /dev/null
@@ -1,25 +0,0 @@
---TEST--
-swoole_redis_coro: use unixsocket
---SKIPIF--
-
---FILE--
- 0.5]);
- Assert::assert($redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT));
- for ($c = MAX_CONCURRENCY_MID; $c--;) {
- for ($n = MAX_REQUESTS; $n--;) {
- $key = md5(get_safe_random(mt_rand(1, 128)));
- $value = md5(get_safe_random(mt_rand(1, 128)));
- Assert::assert($redis->set($key, $value));
- Assert::same($redis->get($key), $value);
- Assert::assert($redis->delete($key));
- }
- }
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/defer.phpt b/tests/swoole_redis_coro/defer.phpt
deleted file mode 100644
index db4d238b1ed..00000000000
--- a/tests/swoole_redis_coro/defer.phpt
+++ /dev/null
@@ -1,45 +0,0 @@
---TEST--
-swoole_redis_coro: defer
---SKIPIF--
-
---FILE--
- SWOOLE_LOG_TRACE, 'trace_flags' => SWOOLE_TRACE_ALL]);
-
-go(function () {
- $redis = new Swoole\Coroutine\Redis();
- echo "CONNECT [1]\n";
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- $redis->setDefer();
- echo "SET [1]\n";
- $redis->set('key1', 'value');
-
- $redis2 = new Swoole\Coroutine\Redis();
- echo "CONNECT [2]\n";
- $redis2->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- $redis2->setDefer();
- echo "GET [2]\n";
- $redis2->get('key1');
-
- echo "RECV [1]\n";
- $result1 = $redis->recv();
- var_dump($result1);
-
- echo "RECV [2]\n";
- $result2 = $redis2->recv();
- var_dump($result2);
-});
-
-Swoole\Event::wait();
-?>
---EXPECT--
-CONNECT [1]
-SET [1]
-CONNECT [2]
-GET [2]
-RECV [1]
-bool(true)
-RECV [2]
-string(5) "value"
diff --git a/tests/swoole_redis_coro/different_connect.phpt b/tests/swoole_redis_coro/different_connect.phpt
deleted file mode 100644
index 51bcb46567c..00000000000
--- a/tests/swoole_redis_coro/different_connect.phpt
+++ /dev/null
@@ -1,47 +0,0 @@
---TEST--
-swoole_redis_coro: connect the same target and different
---SKIPIF--
-
---FILE--
- -1]);
-function test(string $host, int $port = 0)
-{
- $redis = new Swoole\Coroutine\Redis();
- Assert::same($redis->sock, -1);
-
- $real_connect_time = microtime(true);
- $ret = $redis->connect($host, $port);
- $real_connect_time = microtime(true) - $real_connect_time;
-
- Assert::assert($ret);
- Assert::assert(($fd = $redis->sock) > 0);
-
- $fake_connect_time = 0;
- for ($n = MAX_REQUESTS; $n--;) {
- $fake_connect_time = microtime(true);
- $ret = $redis->connect($host, $port);
- $fake_connect_time = microtime(true) - $fake_connect_time;
- Assert::assert($ret);
- Assert::assert($fake_connect_time < $real_connect_time);
- }
-
- $real_connect_time = microtime(true);
- $redis->connect(MYSQL_SERVER_HOST, MYSQL_SERVER_PORT);
- $real_connect_time = microtime(true) - $real_connect_time;
- Assert::assert($fake_connect_time < $real_connect_time);
- Assert::assert(!$redis->get('foo'));
- Assert::same($redis->errType, SWOOLE_REDIS_ERR_PROTOCOL);
-}
-
-go('test', REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-if (file_exists(REDIS_SERVER_PATH)) {
- go('test', 'unix:' . str_repeat('/', mt_rand(1, 3)) . REDIS_SERVER_PATH);
-}
-
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/disable_retry.phpt b/tests/swoole_redis_coro/disable_retry.phpt
deleted file mode 100644
index 6e5149a1cfe..00000000000
--- a/tests/swoole_redis_coro/disable_retry.phpt
+++ /dev/null
@@ -1,68 +0,0 @@
---TEST--
-swoole_redis_coro: disable retry
---SKIPIF--
-
---FILE--
-parentFunc = function () use ($pm) {
- go(function () use ($pm) {
- $redis = new Swoole\Coroutine\Redis;
- $ret = $redis->connect('127.0.0.1', $pm->getFreePort());
- Assert::assert($ret);
- $redis->setOptions(['retry' => false]);
- for ($n = MAX_REQUESTS; $n--;) {
- $ret = $redis->set('random_val', $random = get_safe_random(128));
- Assert::assert($ret);
- $ret = $redis->get('random_val');
- if ($n % 2) {
- Assert::same($ret, $random);
- } else {
- Assert::assert(!$ret);
- }
- }
- $pm->kill();
- echo "DONE\n";
- });
-};
-$pm->childFunc = function () use ($pm) {
- $server = new Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE);
- $server->data = [];
- $server->on('WorkerStart', function ($server) use ($pm) {
- $pm->wakeup();
- });
- $server->setHandler('GET', function ($fd, $data) use ($server) {
- static $rid = 0;
- if (count($data) == 0) {
- $server->send($fd, Server::format(Server::ERROR, "ERR wrong number of arguments for 'GET' command"));
- }
- $key = $data[0];
- if ($rid++ % 2) {
- $server->close($fd);
- } else {
- if (empty($server->data[$key])) {
- $server->send($fd, Server::format(Server::NIL));
- } else {
- $server->send($fd, Server::format(Server::STRING, $server->data[$key]));
- }
- }
- });
- $server->setHandler('SET', function ($fd, $data) use ($server) {
- if (count($data) < 2) {
- $server->send($fd, Server::format(Server::ERROR, "ERR wrong number of arguments for 'SET' command"));
- }
- $key = $data[0];
- $server->data[$key] = $data[1];
- $server->send($fd, Server::format(Server::STATUS, 'OK'));
- });
- $server->start();
-};
-$pm->childFirst();
-$pm->run();
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/donot_retry_after_failed.phpt b/tests/swoole_redis_coro/donot_retry_after_failed.phpt
deleted file mode 100644
index 3528b9e4010..00000000000
--- a/tests/swoole_redis_coro/donot_retry_after_failed.phpt
+++ /dev/null
@@ -1,43 +0,0 @@
---TEST--
-swoole_redis_coro: don not retry again after connect failed
---SKIPIF--
-
---FILE--
-bind('127.0.0.1');
-$info = $sock->getsockname();
-$port = $info['port'];
-
-$cid = go(function () use ($sock) {
- $sock->listen();
- $sock->accept();
- co::yield();
- $sock->close();
-});
-
-go(function () use ($cid, $port) {
- $redis = new Swoole\Coroutine\Redis();
- $ret = $redis->connect('127.0.0.1', 65535);
- Assert::assert(!$ret);
- Assert::same($redis->errCode, SOCKET_ECONNREFUSED);
- for ($n = MAX_REQUESTS; $n--;) {
- $ret = $redis->get('foo');
- Assert::assert(!$ret);
- Assert::same($redis->errType, SWOOLE_REDIS_ERR_CLOSED);
- }
- $ret = $redis->connect('127.0.0.1', $port);
- Assert::assert($ret);
- Assert::assert($redis->connected);
- Assert::same($redis->errCode, 0, $redis->errCode);
- Assert::same($redis->errMsg, '', $redis->errMsg);
- co::sleep(0.001);
- co::resume($cid);
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/donot_retry_after_server_down.phpt b/tests/swoole_redis_coro/donot_retry_after_server_down.phpt
deleted file mode 100644
index c16cf432f69..00000000000
--- a/tests/swoole_redis_coro/donot_retry_after_server_down.phpt
+++ /dev/null
@@ -1,62 +0,0 @@
---TEST--
-swoole_redis_coro: do not retry after server down
---SKIPIF--
-
---FILE--
-parentFunc = function () use ($pm) {
- go(function () use ($pm) {
- $redis = new Swoole\Coroutine\Redis;
- $ret = $redis->connect('127.0.0.1', $pm->getFreePort());
- Assert::assert($ret);
- $ret = $redis->set('random_val', $random = get_safe_random(128));
- Assert::assert($ret);
- $ret = $redis->get('random_val');
- Assert::same($ret, $random);
- $pm->kill();
- Assert::assert(!$redis->get('random_val'));
- Assert::same($redis->errCode, SOCKET_ECONNRESET);
- for ($n = MAX_REQUESTS; $n--;) {
- Assert::assert(!$redis->set('random_val', get_safe_random(128)));
- Assert::same($redis->errCode, SOCKET_ECONNREFUSED);
- Assert::assert(!$redis->get('random_val'));
- Assert::same($redis->errCode, SOCKET_ECONNREFUSED);
- }
- });
-};
-$pm->childFunc = function () use ($pm) {
- $server = new Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE);
- $server->data = [];
- $server->on('workerStart', function ($server) use ($pm) {
- $pm->wakeup();
- });
- $server->setHandler('GET', function ($fd, $data) use ($server) {
- if (count($data) == 0) {
- return Server::format(Server::ERROR, "ERR wrong number of arguments for 'GET' command");
- }
- $key = $data[0];
- if (empty($server->data[$key])) {
- $server->send($fd, Server::format(Server::NIL));
- } else {
- $server->send($fd, Server::format(Server::STRING, $server->data[$key]));
- }
- });
- $server->setHandler('SET', function ($fd, $data) use ($server) {
- if (count($data) < 2) {
- $server->send($fd, Server::format(Server::ERROR, "ERR wrong number of arguments for 'SET' command"));
- }
- $key = $data[0];
- $server->data[$key] = $data[1];
- $server->send($fd, Server::format(Server::STATUS, 'OK'));
- });
- $server->start();
-};
-$pm->childFirst();
-$pm->run();
-?>
---EXPECT--
diff --git a/tests/swoole_redis_coro/err.phpt b/tests/swoole_redis_coro/err.phpt
deleted file mode 100644
index 6b2ad5c4667..00000000000
--- a/tests/swoole_redis_coro/err.phpt
+++ /dev/null
@@ -1,22 +0,0 @@
---TEST--
-swoole_redis_coro: redis error return
---SKIPIF--
-
---FILE--
- 3]);
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- $res = $redis->set('foo', 'bar');
- Assert::assert($res && $redis->errCode === 0 && $redis->errMsg === '');
- $res = $redis->hIncrBy('foo', 'bar', 123);
- Assert::assert(!$res);
- Assert::same($redis->errType, SWOOLE_REDIS_ERR_OTHER);
- var_dump($redis->errMsg);
- $res = $redis->set('foo', 'baz');
- Assert::assert($res && $redis->errCode === 0 && $redis->errMsg === '');
-});
-?>
---EXPECT--
-string(65) "WRONGTYPE Operation against a key holding the wrong kind of value"
diff --git a/tests/swoole_redis_coro/getDbNum.phpt b/tests/swoole_redis_coro/getDbNum.phpt
deleted file mode 100644
index 581ba0c552c..00000000000
--- a/tests/swoole_redis_coro/getDbNum.phpt
+++ /dev/null
@@ -1,40 +0,0 @@
---TEST--
-swoole_redis_coro: redis select db
---SKIPIF--
-
---FILE--
-getDBNum());
- Assert::assert($redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT));
- // connected but not selected
- Assert::same($redis->getDBNum(), 0);
- // select and success
- Assert::true($redis->select(1));
- Assert::same($redis->getDBNum(), 1);
- // select but failed
- Assert::false($redis->select(-1));
- Assert::same($redis->errCode, SOCKET_EINVAL);
- Assert::false($redis->select(1001));
- Assert::same($redis->errCode, SOCKET_EINVAL);
- Assert::same($redis->getDBNum(), 1);
-
- $redis = new Swoole\Coroutine\Redis(['database' => 1]);
- // connected but not selected
- Assert::false($redis->getDBNum());
- Assert::assert($redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT));
- // connected but not selected
- Assert::same($redis->getDBNum(), 1);
- // set database but failed
- $redis = new Swoole\Coroutine\Redis(['database' => 1001]);
- Assert::false($redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT));
- Assert::false($redis->getDBNum());
- Assert::same($redis->errCode, SOCKET_EINVAL);
- echo "DONE\n";
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/getOptions.phpt b/tests/swoole_redis_coro/getOptions.phpt
deleted file mode 100644
index 7626bd2bc49..00000000000
--- a/tests/swoole_redis_coro/getOptions.phpt
+++ /dev/null
@@ -1,50 +0,0 @@
---TEST--
-swoole_redis_coro: redis client get options
---SKIPIF--
-
---FILE--
- 100,
- 'socket_timeout' => 100,
-]);
-$redis = new Swoole\Coroutine\Redis();
-var_dump($redis->getOptions());
-$redis->setOptions([
- 'connect_timeout' => 0.001,
- 'timeout' => 0.001,
- 'serialize' => true,
- 'reconnect' => 3
-]);
-var_dump($redis->getOptions());
-?>
---EXPECT--
-array(6) {
- ["connect_timeout"]=>
- float(2)
- ["timeout"]=>
- float(100)
- ["serialize"]=>
- bool(false)
- ["reconnect"]=>
- int(1)
- ["password"]=>
- string(0) ""
- ["database"]=>
- int(0)
-}
-array(6) {
- ["connect_timeout"]=>
- float(0.001)
- ["timeout"]=>
- float(0.001)
- ["serialize"]=>
- bool(true)
- ["reconnect"]=>
- int(3)
- ["password"]=>
- string(0) ""
- ["database"]=>
- int(0)
-}
diff --git a/tests/swoole_redis_coro/hgetall.phpt b/tests/swoole_redis_coro/hgetall.phpt
deleted file mode 100644
index 7990aa642dc..00000000000
--- a/tests/swoole_redis_coro/hgetall.phpt
+++ /dev/null
@@ -1,97 +0,0 @@
---TEST--
-swoole_redis_coro: hGetAll hmGet zRange zRevRange zRangeByScore zRevRangeByScore
---SKIPIF--
-
---FILE--
-setOptions(['compatibility_mode' => true]);
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-
- $redis->delete('hkey');
- $redis->hSet('hkey', false, 'val0');
- $redis->hSet('hkey', "field", 'val1');
- $redis->hSet('hkey', 5, 'val5');
-
- $redis->delete('zkey');
- $redis->zAdd('zkey', "field", 'val0');
- $redis->zAdd('zkey', true, 'val1');
- $redis->zAdd('zkey', 5, 'val5');
-
- echo "-----get---\n";
- var_dump($redis->get('novalue'));
- echo "-----zRank---\n";
- var_dump($redis->zRank('novalue', 1));
- echo "-----hGetAll---\n";
- var_dump($redis->hGetAll('hkey'));
- echo "-----hmGet---\n";
- var_dump($redis->hmGet('hkey', [3, 5]));
- echo "-----zRange---\n";
- var_dump($redis->zRange('zkey', 0, 99, true));
- echo "-----zRevRange---\n";
- var_dump($redis->zRevRange('zkey', 0, 99, true));
- echo "-----zRangeByScore---\n";
- var_dump($redis->zRangeByScore('zkey', 0, 99, ['withscores' => true]));
- echo "-----zRevRangeByScore---\n";
- var_dump($redis->zRevRangeByScore('zkey', 99, 0, ['withscores' => true]));
-});
-?>
---EXPECT--
------get---
-bool(false)
------zRank---
-bool(false)
------hGetAll---
-array(3) {
- [""]=>
- string(4) "val0"
- ["field"]=>
- string(4) "val1"
- [5]=>
- string(4) "val5"
-}
------hmGet---
-array(2) {
- [3]=>
- bool(false)
- [5]=>
- string(4) "val5"
-}
------zRange---
-array(3) {
- ["val0"]=>
- float(0)
- ["val1"]=>
- float(1)
- ["val5"]=>
- float(5)
-}
------zRevRange---
-array(3) {
- ["val5"]=>
- float(5)
- ["val1"]=>
- float(1)
- ["val0"]=>
- float(0)
-}
------zRangeByScore---
-array(3) {
- ["val0"]=>
- float(0)
- ["val1"]=>
- float(1)
- ["val5"]=>
- float(5)
-}
------zRevRangeByScore---
-array(3) {
- ["val5"]=>
- float(5)
- ["val1"]=>
- float(1)
- ["val0"]=>
- float(0)
-}
diff --git a/tests/swoole_redis_coro/lock.phpt b/tests/swoole_redis_coro/lock.phpt
deleted file mode 100644
index 6614474f4fa..00000000000
--- a/tests/swoole_redis_coro/lock.phpt
+++ /dev/null
@@ -1,30 +0,0 @@
---TEST--
-swoole_redis_coro: redis lock
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- $redis->delete('lock');
- $ret = $redis->set('lock', 1, ['nx', 'ex' => 1, 'px' => 1000]); // px will be ignored
- Assert::assert($ret);
- $ret = $redis->set('lock', 1, ['nx', 'ex' => 1, 'px' => 1000]); // px will be ignored
- Assert::assert(!$ret);
- $redis->delete('lock');
- $ret = $redis->set('lock', 1, ['nx', 'px' => 100]);
- Assert::assert($ret);
- usleep(50 * 1000);
- $ret = $redis->set('lock', 1, ['nx', 'px' => 100]);
- Assert::assert(!$ret);
- usleep(100 * 1000);
- $ret = $redis->set('lock', 1, ['nx', 'px' => 100]);
- Assert::assert($ret);
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/multi_exec.phpt b/tests/swoole_redis_coro/multi_exec.phpt
deleted file mode 100644
index 0a3ed2f8009..00000000000
--- a/tests/swoole_redis_coro/multi_exec.phpt
+++ /dev/null
@@ -1,30 +0,0 @@
---TEST--
-swoole_redis_coro: redis multi and exec
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT, false);
- Assert::assert($result);
-
- Assert::assert($redis->hmset('u:i:1', ['a' => 'hello', 'b' => 'world']));
- Assert::assert($redis->hmset('u:i:2', ['a' => 'rango', 'b' => 'swoole']));
- Assert::assert($redis->multi());
- $redis->hmget('u:i:1', array('a', 'b'));
- $redis->hmget('u:i:2', array('a', 'b'));
-
- $rs = $redis->exec();
- Assert::assert($rs and is_array($rs));
- Assert::same($rs[0][0], 'hello');
- Assert::same($rs[0][1], 'world');
- Assert::same($rs[1][0], 'rango');
- Assert::same($rs[1][1], 'swoole');
- echo "DONE\n";
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/pool.phpt b/tests/swoole_redis_coro/pool.phpt
deleted file mode 100644
index 98294be2594..00000000000
--- a/tests/swoole_redis_coro/pool.phpt
+++ /dev/null
@@ -1,79 +0,0 @@
---TEST--
-swoole_redis_coro: redis client
---SKIPIF--
-
---FILE--
-parentFunc = function ($pid) use ($pm)
-{
- go(function () use ($pm) {
- echo httpGetBody("http://127.0.0.1:{$pm->getFreePort()}/");
- echo httpGetBody("http://127.0.0.1:{$pm->getFreePort()}/");
- echo httpGetBody("http://127.0.0.1:{$pm->getFreePort()}/");
- $pm->kill();
- });
-};
-
-$count = 0;
-$pool = new SplQueue();
-
-$pm->childFunc = function () use ($pm)
-{
- $http = new Swoole\Http\Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE);
- $http->set(array(
- 'log_file' => '/dev/null'
- ));
- $http->on("WorkerStart", function (Swoole\Server $serv)
- {
- /**
- * @var $pm ProcessManager
- */
- global $pm;
- $pm->wakeup();
- });
-
- $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response)
- {
- global $count, $pool;
- if (count($pool) == 0)
- {
- $redis = new Swoole\Coroutine\Redis();
- $redis->id = $count;
- $res = $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- if ($res == false)
- {
- fail:
- $response->end("ERROR\n");
- return;
- }
- $count++;
- $pool->enqueue($redis);
- }
-
- $redis = $pool->dequeue();
- $ret = $redis->set('key', 'value');
- if ($ret)
- {
- $response->end("OK[$count]\n");
- }
- else
- {
- goto fail;
- }
- $pool->enqueue($redis);
-
- });
-
- $http->start();
-};
-
-$pm->childFirst();
-$pm->run();
-?>
---EXPECT--
-OK[1]
-OK[1]
-OK[1]
diff --git a/tests/swoole_redis_coro/psubscribe_1.phpt b/tests/swoole_redis_coro/psubscribe_1.phpt
deleted file mode 100644
index 1945ac083ab..00000000000
--- a/tests/swoole_redis_coro/psubscribe_1.phpt
+++ /dev/null
@@ -1,37 +0,0 @@
---TEST--
-swoole_redis_coro: redis psubscribe
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- $val = $redis->psubscribe(['test.*']);
- Assert::assert($val);
- $val = $redis->recv();
- Assert::assert($val[0] == 'psubscribe' && $val[1] == 'test.*');
-
- for ($i = 0; $i < MAX_REQUESTS; $i++) {
- $val = $redis->recv();
- Assert::same($val[0] ?? '', 'pmessage');
- }
-
- $redis->close();
-});
-
-go(function () {
- $redis = new Co\redis;
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- co::sleep(0.1);
-
- for ($i = 0; $i < MAX_REQUESTS; $i++) {
- $ret = $redis->publish('test.a', 'hello-' . $i);
- Assert::assert($ret);
- }
-});
-
-?>
---EXPECT--
diff --git a/tests/swoole_redis_coro/psubscribe_2.phpt b/tests/swoole_redis_coro/psubscribe_2.phpt
deleted file mode 100644
index 255a5eef5d7..00000000000
--- a/tests/swoole_redis_coro/psubscribe_2.phpt
+++ /dev/null
@@ -1,41 +0,0 @@
---TEST--
-swoole_redis_coro: redis psubscribe 2
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-
- $redis2 = new Co\Redis;
- $redis2->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-
- for ($i = 0; $i < MAX_REQUESTS; $i++) {
- $channel = 'channel' . floor($i / 10) . $i;
- $val = $redis->psubscribe([$channel . '*']);
- Assert::assert($val);
-
- $val = $redis->recv();
- Assert::same($val[0], 'psubscribe');
- Assert::same($val[1], $channel . '*');
-
- $channel .= 'test';
-
- go(function () use ($channel, $redis2) {
- $ret = $redis2->publish($channel, 'test' . $channel);
- Assert::assert($ret);
- });
-
- $val = $redis->recv();
- Assert::same($val[0] ?? '', 'pmessage');
- }
-
- $redis->close();
- $redis2->close();
-});
-
-?>
---EXPECT--
diff --git a/tests/swoole_redis_coro/psubscribe_eof_1.phpt b/tests/swoole_redis_coro/psubscribe_eof_1.phpt
deleted file mode 100644
index 2f3153fa2d1..00000000000
--- a/tests/swoole_redis_coro/psubscribe_eof_1.phpt
+++ /dev/null
@@ -1,40 +0,0 @@
---TEST--
-swoole_redis_coro: redis psubscribe eof 1
---SKIPIF--
-
---FILE--
-bind('127.0.0.1');
-$info = $sock->getsockname();
-$port = $info['port'];
-go(function () use ($sock) {
- $sock->listen();
- while ($client = $sock->accept(-1)) {
- $client->close();
- }
- echo "DONE\n";
-});
-
-go(function () use ($sock, $port) {
- $redis = new Swoole\Coroutine\Redis();
- $redis->connect('127.0.0.1', $port);
- for ($n = 0; $n < MAX_REQUESTS; $n++) {
- $val = $redis->psubscribe(['test.*']);
- Assert::assert($val);
- $val = $redis->recv();
- Assert::false($val);
- Assert::false($redis->connected);
- Assert::assert(in_array($redis->errType, [SWOOLE_REDIS_ERR_IO, SWOOLE_REDIS_ERR_EOF], true));
- if ($redis->errType === SWOOLE_REDIS_ERR_IO) {
- Assert::same($redis->errCode, SOCKET_ECONNRESET);
- }
- }
- $redis->close();
- $sock->close();
-});
-Swoole\Event::wait();
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/psubscribe_eof_2.phpt b/tests/swoole_redis_coro/psubscribe_eof_2.phpt
deleted file mode 100644
index d6aa4a1b337..00000000000
--- a/tests/swoole_redis_coro/psubscribe_eof_2.phpt
+++ /dev/null
@@ -1,46 +0,0 @@
---TEST--
-swoole_redis_coro: redis psubscribe eof 2
---SKIPIF--
-
---FILE--
-bind('127.0.0.1');
-$info = $sock->getsockname();
-$port = $info['port'];
-go(function () use ($sock) {
- $sock->listen();
-
- while ($client = $sock->accept(-1)) {
- $client->recv();
- $client->send("*3\r\n\$10\r\npsubscribe\r\n\$8\r\nchannel1\r\n:1\r\n");
- co::sleep(0.1);
- $client->close();
- }
-
- echo "DONE\n";
-});
-go(function () use ($sock, $port) {
- $redis = new Swoole\Coroutine\Redis();
- $redis->connect('127.0.0.1', $port);
-
- $val = $redis->psubscribe(['channel1']);
- Assert::assert($val);
-
- $val = $redis->recv();
- Assert::assert($val[0] == 'psubscribe' && $val[1] == 'channel1');
-
- $val = $redis->recv();
- Assert::false($val);
-
- Assert::false($redis->connected);
- Assert::same($redis->errType, SWOOLE_REDIS_ERR_EOF);
-
- $redis->close();
- $sock->close();
-});
-Swoole\Event::wait();
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/punsubscribe.phpt b/tests/swoole_redis_coro/punsubscribe.phpt
deleted file mode 100644
index 6326828cadf..00000000000
--- a/tests/swoole_redis_coro/punsubscribe.phpt
+++ /dev/null
@@ -1,51 +0,0 @@
---TEST--
-swoole_redis_coro: redis punsubscribe
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::assert($ret);
-
- $ret = $redis->psubscribe(['channel1']);
- Assert::assert($ret);
-
- $ret = $redis->recv();
- Assert::same($ret[0], 'psubscribe');
- Assert::same($ret[1], 'channel1');
-
- $ret = $redis->getDefer();
- Assert::assert(!$ret);
-
- $ret = $redis->set('a', '1');
- Assert::assert(!$ret);
-
- $ret = $redis->setDefer(false);
- Assert::assert(!$ret);
-
- $ret = $redis->punsubscribe(['channel1']);
- Assert::assert($ret);
-
- $ret = $redis->recv();
- Assert::same($ret[0], 'punsubscribe');
- Assert::same($ret[1], 'channel1');
-
- $ret = $redis->getDefer();
- Assert::assert(!$ret);
-
- $ret = $redis->set('a', '1');
- Assert::assert($ret);
-
- $ret = $redis->setDefer(false);
- Assert::assert($ret);
-
- $redis->close();
-});
-
-?>
---EXPECTF--
-Warning: Swoole\Coroutine\Redis::setDefer(): you should not use setDefer after subscribe in %s/tests/swoole_redis_coro/punsubscribe.php on line 22
diff --git a/tests/swoole_redis_coro/reconnect.phpt b/tests/swoole_redis_coro/reconnect.phpt
deleted file mode 100644
index 613dd17990a..00000000000
--- a/tests/swoole_redis_coro/reconnect.phpt
+++ /dev/null
@@ -1,17 +0,0 @@
---TEST--
-swoole_redis_coro: redis reconnect
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::assert($res);
- $redis->close();
- $res2 = $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::assert($res2);
-});
-?>
---EXPECT--
diff --git a/tests/swoole_redis_coro/request_without_connected.phpt b/tests/swoole_redis_coro/request_without_connected.phpt
deleted file mode 100644
index f323ff7db2d..00000000000
--- a/tests/swoole_redis_coro/request_without_connected.phpt
+++ /dev/null
@@ -1,16 +0,0 @@
---TEST--
-swoole_redis_coro: redis request without connected
---SKIPIF--
-
---FILE--
-get('foo'));
- echo "DONE\n";
-});
-?>
---EXPECTF--
-Warning: Swoole\Coroutine\Redis::get(): The host is empty in %s/tests/swoole_redis_coro/request_without_connected.php on line 5
-DONE
diff --git a/tests/swoole_redis_coro/select.phpt b/tests/swoole_redis_coro/select.phpt
deleted file mode 100644
index 770c4f28a22..00000000000
--- a/tests/swoole_redis_coro/select.phpt
+++ /dev/null
@@ -1,37 +0,0 @@
---TEST--
-swoole_redis_coro: redis select
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT));
- Assert::assert($redis->select(0));
- Assert::assert($redis->set('foo', $random0 = get_safe_random()));
- Assert::assert($redis->select(1));
- Assert::assert($redis->set('foo', $random1 = get_safe_random()));
- $foo = $redis->get('foo');
- Assert::assert($foo !== $random0);
- Assert::same($foo, $random1);
- Assert::assert($redis->select(0));
- $foo = $redis->get('foo');
- Assert::same($foo, $random0);
- Assert::assert($foo !== $random1);
- Assert::assert($redis->select(1));
-
- // test whether it's OK after automatic reconnected
- $redis_killer = new Swoole\Coroutine\Redis;
- $redis_killer->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- $redis_killer->request(['CLIENT', 'KILL', 'TYPE', 'normal']);
-
- $foo = $redis->get('foo');
- Assert::assert($foo !== $random0);
- Assert::same($foo, $random1);
-
- echo "DONE\n";
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/set.phpt b/tests/swoole_redis_coro/set.phpt
deleted file mode 100644
index 20a8f46ad1e..00000000000
--- a/tests/swoole_redis_coro/set.phpt
+++ /dev/null
@@ -1,43 +0,0 @@
---TEST--
-swoole_redis_coro: set
---SKIPIF--
-
---FILE--
- SWOOLE_LOG_TRACE, 'trace_flags' => SWOOLE_TRACE_ALL]);
-
-go(function () {
- $redis = new Swoole\Coroutine\Redis();
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::assert($redis->set('key1', 'value'));
- Assert::assert($redis->set('key1', 'value', 10));
- Assert::assert($redis->ttl('key1') == 10);
- /**
- * xx+ex
- */
- Assert::assert($redis->set('key1', 'value', ['xx', 'ex' => 30]));
- Assert::assert($redis->ttl('key1') == 30);
- /**
- * delete
- */
- Assert::assert($redis->delete('key1'));
- /**
- * nx+ex
- */
- Assert::assert($redis->set('key1', 'value', ['nx', 'ex' => 20]));
- Assert::assert($redis->ttl('key1') == 20);
-
- /**
- * px
- */
- Assert::assert($redis->set('key1', 'value', ['xx', 'px' => 10000]));
- Assert::assert($redis->ttl('key1') == 10);
- echo "OK\n";
-});
-
-Swoole\Event::wait();
-?>
---EXPECT--
-OK
diff --git a/tests/swoole_redis_coro/setOptions.phpt b/tests/swoole_redis_coro/setOptions.phpt
deleted file mode 100644
index eb5819fc6f9..00000000000
--- a/tests/swoole_redis_coro/setOptions.phpt
+++ /dev/null
@@ -1,39 +0,0 @@
---TEST--
-swoole_redis_coro: redis client set options
---SKIPIF--
-
---FILE--
- -1]);
-go(function () {
- $redis = new Swoole\Coroutine\Redis();
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-
- // read time out
- $redis->setOptions(['timeout' => 0.001]);
- $s = microtime(true);
- $ret = $redis->brpoplpush('test', 'test2', 1);
- $s = microtime(true) - $s;
- time_approximate(0.001, $s, 1);
- Assert::assert(!$ret);
-
- // read ok (after internal auto connect)
- $redis->setOptions(['timeout' => 1]);
- $ret = $redis->set('foo', 'bar');
- Assert::assert($ret);
- Assert::same($redis->errCode, 0);
- Assert::same($redis->errMsg, '');
- $redis->close();
- Assert::assert(!$redis->connected);
-
- // connect timeout
- $redis->setOptions(['connect_timeout' => 0.001]);
- $redis->connect('www.google.com', 80);
- Assert::same($redis->errCode, SOCKET_ETIMEDOUT);
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/stream.phpt b/tests/swoole_redis_coro/stream.phpt
deleted file mode 100644
index 00f7d03520b..00000000000
--- a/tests/swoole_redis_coro/stream.phpt
+++ /dev/null
@@ -1,124 +0,0 @@
---TEST--
-swoole_redis_coro: stream
---SKIPIF--
-
---FILE--
- SWOOLE_LOG_TRACE, 'trace_flags' => SWOOLE_TRACE_ALL]);
-
-Co\run(function() {
- $redis = new Swoole\Coroutine\Redis();
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-
- $ret = $redis->del('mystream');
-
- // xGroupCreate
- $ret = $redis->xGroupCreate('mystream', 'group1', '0-0', true);
- Assert::assert($ret == '1');
-
- // xGroupCreateConsumer
- $ret = $redis->xGroupCreateConsumer('mystream', 'group1', 'consumer1');
- Assert::assert($ret == '1');
- $ret = $redis->xGroupCreateConsumer('mystream', 'group1', 'consumer2');
- Assert::assert($ret == '1');
-
- // xAdd
- $ret = $redis->xAdd('mystream', '0-1', ['field'=>'111'], ['nomkstream'=>true, 'maxlen'=>['~', 5], 'limit'=>5]);
- Assert::assert($ret == '0-1');
- $ret = $redis->xAdd('mystream', '0-2', ['field'=>'222'], ['nomkstream'=>false, 'minid'=>['~', '0-0'], 'limit'=>5]);
- Assert::assert($ret == '0-2');
- $ret = $redis->xAdd('mystream', '0-3', ['field'=>'333'], ['maxlen'=>['=', 5]]);
- Assert::assert($ret == '0-3');
- $ret = $redis->xAdd('mystream', '0-4', ['field'=>'444'], ['maxlen'=>5]);
- Assert::assert($ret, '0-4');
- $ret = $redis->xAdd('mystream', '0-5', ['field'=>'555']);
- Assert::assert($ret, '0-5');
-
- // xLen
- $ret = $redis->xLen('mystream');
- Assert::assert($ret == '5');
-
- // xRead
- $ret = $redis->xRead(['mystream'=>'0-3'], ['count'=>1, 'block'=>100]);
- Assert::assert($ret[0][1][0][0] == '0-4');
-
- // xRange
- $ret = $redis->xRange('mystream', '0-2', '0-3', 1);
- Assert::assert($ret[0][0] == '0-2');
-
- // xRevRange
- $ret = $redis->xRevRange('mystream', '+', '-', 1);
- Assert::assert($ret[0][0] == '0-5');
-
- // xReadGroup
- $ret = $redis->xReadGroup('group1', 'consumer1', ['mystream' => '>'], ['count'=>1, 'block'=>100, 'noack'=>true]);
- Assert::assert($ret[0][1][0][0] == '0-1');
- $ret = $redis->xReadGroup('group1', 'consumer1', ['mystream' => '>'], ['count'=>1, 'block'=>100, 'noack'=>false]);
- Assert::assert($ret[0][1][0][0] == '0-2');
- $ret = $redis->xReadGroup('group1', 'consumer1', ['mystream' => '>'], ['count'=>1]);
- Assert::assert($ret[0][1][0][0] == '0-3');
-
- // xPending
- $ret = $redis->xPending('mystream', 'group1', ['start'=>'-', 'end'=>'+', 'count'=>5]);
- Assert::assert(count($ret) == 2);
- Assert::assert($ret[0][0] == '0-2');
- Assert::assert($ret[1][0] == '0-3');
-
- // xAck
- $ret = $redis->xAck('mystream', 'group1', ['0-2']);
- Assert::assert($ret == '1');
-
- // xClaim
- $ret = $redis->xClaim('mystream', 'group1', 'consumer2', 0, ['0-3']);
- Assert::assert($ret[0][0] == '0-3');
-
- // xInfoConsumers
- $ret = $redis->xInfoConsumers('mystream', 'group1');
- Assert::assert($ret[1][3] == '1');
-
- // xAutoClaim
- $ret = $redis->xAutoClaim('mystream', 'group1', 'consumer1', 0, '0-3');
- Assert::assert($ret[1][0][0] == '0-3');
-
- // xInfoGroups
- $ret = $redis->xInfoGroups('mystream');
- Assert::assert($ret[0][1] == 'group1');
- Assert::assert($ret[0][5] == '1');
-
- // xInfoStream
- $ret = $redis->xInfoStream('mystream');
- Assert::assert($ret[1] == '5');
-
- // xDel
- $ret = $redis->xDel('mystream', '0-1', '0-2');
- Assert::assert($ret == '2');
-
- // xTrim
- $ret = $redis->xTrim('mystream', ['maxlen'=>1]);
- Assert::assert($ret == '2');
- $ret = $redis->xTrim('mystream', ['minid'=>['~', '0'], 'limit'=>1]);
- Assert::assert($ret == '0');
-
- // xGroupSetId
- $ret = $redis->xGroupSetId('mystream', 'group1', '0-1');
- Assert::assert($ret == '1');
-
- // xGroupDelConsumer
- $ret = $redis->xGroupDelConsumer('mystream', 'group1', 'consumer1');
- Assert::assert($ret == '1');
-
- // xGroupDestroy
- $ret = $redis->xGroupDestroy('mystream', 'group1');
- Assert::assert($ret == '1');
-
- $ret = $redis->del('mystream');
-
- echo "OK\n";
-});
-?>
---EXPECT--
-OK
diff --git a/tests/swoole_redis_coro/subscribe_1.phpt b/tests/swoole_redis_coro/subscribe_1.phpt
deleted file mode 100644
index e9b4db226c0..00000000000
--- a/tests/swoole_redis_coro/subscribe_1.phpt
+++ /dev/null
@@ -1,38 +0,0 @@
---TEST--
-swoole_redis_coro: redis subscribe 1
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- $val = $redis->subscribe(['test']);
- Assert::assert($val);
-
- $val = $redis->recv();
- Assert::assert($val[0] == 'subscribe' && $val[1] == 'test');
-
- for ($i = 0; $i < MAX_REQUESTS; $i++) {
- $val = $redis->recv();
- Assert::same($val[0] ?? '', 'message');
- }
-
- $redis->close();
-});
-
-go(function () {
- $redis = new Co\redis;
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- co::sleep(0.1);
-
- for ($i = 0; $i < MAX_REQUESTS; $i++) {
- $ret = $redis->publish('test', 'hello-' . $i);
- Assert::assert($ret);
- }
-});
-
-?>
---EXPECT--
diff --git a/tests/swoole_redis_coro/subscribe_2.phpt b/tests/swoole_redis_coro/subscribe_2.phpt
deleted file mode 100644
index e60c810baae..00000000000
--- a/tests/swoole_redis_coro/subscribe_2.phpt
+++ /dev/null
@@ -1,40 +0,0 @@
---TEST--
-swoole_redis_coro: redis subscribe 2
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-
- $redis2 = new Co\Redis;
- $redis2->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-
- for ($i = 0; $i < MAX_REQUESTS; $i++) {
- $channel = 'channel' . $i;
- $val = $redis->subscribe([$channel]);
- Assert::assert($val);
-
- $val = $redis->recv();
- Assert::assert($val[0] == 'subscribe' && $val[1] == $channel);
-
- go(function () use ($channel, $redis2) {
- $ret = $redis2->publish($channel, 'test' . $channel);
- Assert::assert($ret);
- });
-
- $val = $redis->recv();
- Assert::same($val[0] ?? '', 'message');
- Assert::same($val[1] ?? '', $channel);
- Assert::same($val[2] ?? '', 'test' . $channel);
- }
-
- $redis->close();
- $redis2->close();
-});
-
-?>
---EXPECT--
diff --git a/tests/swoole_redis_coro/subscribe_multi.phpt b/tests/swoole_redis_coro/subscribe_multi.phpt
deleted file mode 100644
index ce269995409..00000000000
--- a/tests/swoole_redis_coro/subscribe_multi.phpt
+++ /dev/null
@@ -1,46 +0,0 @@
---TEST--
-swoole_redis_coro: redis subscribe multi
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-
- $val = $redis->subscribe(['test1', 'test2', 'test3']);
- Assert::assert($val);
-
- for ($i = 0; $i < 3; ++$i)
- {
- $val = $redis->recv();
- Assert::same($val[0], 'subscribe');
- }
-
- for ($i = 0; $i < 3; $i++) {
- $val = $redis->recv();
- Assert::same($val[0] ?? '', 'message');
- }
-
- $redis->close();
-});
-
-go(function () {
- $redis = new Co\redis;
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- co::sleep(0.1);
-
- $ret = $redis->publish('test1', 'hello');
- Assert::assert($ret);
-
- $ret = $redis->publish('test2', 'hello');
- Assert::assert($ret);
-
- $ret = $redis->publish('test3', 'hello');
- Assert::assert($ret);
-});
-
-?>
---EXPECT--
diff --git a/tests/swoole_redis_coro/subscribe_punsubscribe.phpt b/tests/swoole_redis_coro/subscribe_punsubscribe.phpt
deleted file mode 100644
index daaba685cb6..00000000000
--- a/tests/swoole_redis_coro/subscribe_punsubscribe.phpt
+++ /dev/null
@@ -1,54 +0,0 @@
---TEST--
-swoole_redis_coro: redis subscribe and use punsubscribe
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::assert($ret);
-
- $ret = $redis->subscribe(['channel1']);
- Assert::assert($ret);
-
- $ret = $redis->recv();
- Assert::same($ret[0], 'subscribe');
- Assert::same($ret[1], 'channel1');
-
- $ret = $redis->getDefer();
- Assert::assert(!$ret);
-
- $ret = $redis->set('a', '1');
- Assert::assert(!$ret);
-
- $ret = $redis->setDefer(false);
- Assert::assert(!$ret);
-
- $ret = $redis->punsubscribe(['channel1']);
- Assert::assert($ret);
-
- $ret = $redis->recv();
- Assert::same($ret[0], 'punsubscribe');
- Assert::same($ret[1], 'channel1');
- Assert::same($ret[2], 1);
-
- $ret = $redis->getDefer();
- Assert::assert(!$ret);
-
- $ret = $redis->set('a', '1');
- Assert::assert(!$ret);
-
- $ret = $redis->setDefer(false);
- Assert::assert(!$ret);
-
- $redis->close();
-});
-
-?>
---EXPECTF--
-Warning: Swoole\Coroutine\Redis::setDefer(): you should not use setDefer after subscribe in %s/tests/swoole_redis_coro/subscribe_punsubscribe.php on line 22
-
-Warning: Swoole\Coroutine\Redis::setDefer(): you should not use setDefer after subscribe in %s/tests/swoole_redis_coro/subscribe_punsubscribe.php on line 39
diff --git a/tests/swoole_redis_coro/subscribe_reconnect.phpt b/tests/swoole_redis_coro/subscribe_reconnect.phpt
deleted file mode 100644
index da9026bbdaf..00000000000
--- a/tests/swoole_redis_coro/subscribe_reconnect.phpt
+++ /dev/null
@@ -1,35 +0,0 @@
---TEST--
-swoole_redis_coro: redis subscribe reconnect
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::assert($ret);
-
- $ret = $redis->subscribe(['channel1']);
- Assert::assert($ret);
-
- $ret = $redis->recv();
- Assert::same($ret[0], 'subscribe');
- Assert::same($ret[1], 'channel1');
-
- $ret = $redis->set('a', '1');
- Assert::assert(!$ret);
- $redis->close();
-
- $ret = $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::assert($ret);
-
- $ret = $redis->set('a', '1');
- Assert::assert($ret);
-
- $redis->close();
-});
-
-?>
---EXPECT--
diff --git a/tests/swoole_redis_coro/timeout.phpt b/tests/swoole_redis_coro/timeout.phpt
deleted file mode 100644
index d22fd33e1c6..00000000000
--- a/tests/swoole_redis_coro/timeout.phpt
+++ /dev/null
@@ -1,52 +0,0 @@
---TEST--
-swoole_redis_coro: redis client timeout
---SKIPIF--
-
---FILE--
- 0.5]);
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-
- $keyArray = [QUEUE_KEY_1, QUEUE_KEY_2];
-
- $s = microtime(true);
- $res = $redis->blpop($keyArray, 3);
- Assert::assert(!$res);
- Assert::same($redis->errCode, SOCKET_ETIMEDOUT);
- $s = microtime(true) - $s;
- time_approximate(0.5, $s); // would not retry after timeout
-
- $s = microtime(true);
- $res = $redis->brpoplpush(QUEUE_KEY_1, QUEUE_KEY_2, 3);
- Assert::assert(!$res);
- Assert::same($redis->errCode, SOCKET_ETIMEDOUT);
- $s = microtime(true) - $s;
- time_approximate(0.5, $s); // would not retry after timeout
-
- // right way: no timeout
- $redis->setOptions(['timeout' => -1]);
-
- $s = microtime(true);
- $res = $redis->blpop($keyArray, 1);
- Assert::same($res, null);
- Assert::same($redis->errCode, 0);
- $s = microtime(true) - $s;
- time_approximate(1, $s);
-
- $s = microtime(true);
- $res = $redis->brpoplpush(QUEUE_KEY_1, QUEUE_KEY_2, 1);
- Assert::same($res, null);
- Assert::same($redis->errCode, 0);
- $s = microtime(true) - $s;
- time_approximate(1, $s);
-});
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/unconnected.phpt b/tests/swoole_redis_coro/unconnected.phpt
deleted file mode 100644
index 83f3d4579f4..00000000000
--- a/tests/swoole_redis_coro/unconnected.phpt
+++ /dev/null
@@ -1,16 +0,0 @@
---TEST--
-swoole_redis_coro: redis unconnected recv
---SKIPIF--
-
---FILE--
-setDefer(true);
- Assert::false($redis->recv());
- echo "DONE\n";
-});
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/unixsocket.phpt b/tests/swoole_redis_coro/unixsocket.phpt
deleted file mode 100644
index bbc9aa8302d..00000000000
--- a/tests/swoole_redis_coro/unixsocket.phpt
+++ /dev/null
@@ -1,29 +0,0 @@
---TEST--
-swoole_redis_coro: use unixsocket
---SKIPIF--
-
---FILE--
- 100]);
- Assert::assert($redis->connect('unix:/' . REDIS_SERVER_PATH, 0));
- for ($c = MAX_CONCURRENCY_MID; $c--;) {
- for ($n = MAX_REQUESTS; $n--;) {
- $key = md5(get_safe_random(mt_rand(1, 128)));
- $value = md5(get_safe_random(mt_rand(1, 128)));
- Assert::assert($redis->set($key, $value));
- Assert::same($redis->get($key), $value);
- Assert::assert($redis->delete($key));
- }
- }
-});
-Swoole\Event::wait();
-echo "DONE\n";
-?>
---EXPECT--
-DONE
diff --git a/tests/swoole_redis_coro/unsubscribe.phpt b/tests/swoole_redis_coro/unsubscribe.phpt
deleted file mode 100644
index f9541b1ecf9..00000000000
--- a/tests/swoole_redis_coro/unsubscribe.phpt
+++ /dev/null
@@ -1,51 +0,0 @@
---TEST--
-swoole_redis_coro: redis unsubscribe
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::assert($ret);
-
- $ret = $redis->subscribe(['channel1']);
- Assert::assert($ret);
-
- $ret = $redis->recv();
- Assert::same($ret[0], 'subscribe');
- Assert::same($ret[1], 'channel1');
-
- $ret = $redis->getDefer();
- Assert::assert(!$ret);
-
- $ret = $redis->set('a', '1');
- Assert::assert(!$ret);
-
- $ret = $redis->setDefer(false);
- Assert::assert(!$ret);
-
- $ret = $redis->unsubscribe(['channel1']);
- Assert::assert($ret);
-
- $ret = $redis->recv();
- Assert::same($ret[0], 'unsubscribe');
- Assert::same($ret[1], 'channel1');
-
- $ret = $redis->getDefer();
- Assert::assert(!$ret);
-
- $ret = $redis->set('a', '1');
- Assert::assert($ret);
-
- $ret = $redis->setDefer(false);
- Assert::assert($ret);
-
- $redis->close();
-});
-
-?>
---EXPECTF--
-Warning: Swoole\Coroutine\Redis::setDefer(): you should not use setDefer after subscribe in %s/tests/swoole_redis_coro/unsubscribe.php on line 22
diff --git a/tests/swoole_redis_coro/unsubscribe_all.phpt b/tests/swoole_redis_coro/unsubscribe_all.phpt
deleted file mode 100644
index 3ffbffeb04a..00000000000
--- a/tests/swoole_redis_coro/unsubscribe_all.phpt
+++ /dev/null
@@ -1,56 +0,0 @@
---TEST--
-swoole_redis_coro: redis unsubscribe all
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::assert($ret);
-
- $ret = $redis->subscribe(['channel1', 'channel2']);
- Assert::assert($ret);
-
- for ($i = 0; $i < 2; ++$i)
- {
- $ret = $redis->recv();
- Assert::same($ret[0], 'subscribe');
- }
-
- $ret = $redis->getDefer();
- Assert::assert(!$ret);
-
- $ret = $redis->set('a', '1');
- Assert::assert(!$ret);
-
- $ret = $redis->setDefer(false);
- Assert::assert(!$ret);
-
- $ret = $redis->unsubscribe(['channel1', 'channel2']);
- Assert::assert($ret);
-
- for ($i = 0; $i < 2; ++$i)
- {
- $ret = $redis->recv();
- Assert::same($ret[0], 'unsubscribe');
- Assert::same($ret[2], 1 - $i);
- }
-
- $ret = $redis->getDefer();
- Assert::assert(!$ret);
-
- $ret = $redis->set('a', '1');
- Assert::assert($ret);
-
- $ret = $redis->setDefer(false);
- Assert::assert($ret);
-
- $redis->close();
-});
-
-?>
---EXPECTF--
-Warning: Swoole\Coroutine\Redis::setDefer(): you should not use setDefer after subscribe in %s/tests/swoole_redis_coro/unsubscribe_all.php on line 24
diff --git a/tests/swoole_redis_coro/unsubscribe_not_all.phpt b/tests/swoole_redis_coro/unsubscribe_not_all.phpt
deleted file mode 100644
index 69776291c41..00000000000
--- a/tests/swoole_redis_coro/unsubscribe_not_all.phpt
+++ /dev/null
@@ -1,56 +0,0 @@
---TEST--
-swoole_redis_coro: redis unsubscribe not all
---SKIPIF--
-
---FILE--
-connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
- Assert::assert($ret);
-
- $ret = $redis->subscribe(['channel1', 'channel2']);
- Assert::assert($ret);
-
- for ($i = 0; $i < 2; ++$i)
- {
- $ret = $redis->recv();
- Assert::same($ret[0], 'subscribe');
- }
-
- $ret = $redis->getDefer();
- Assert::assert(!$ret);
-
- $ret = $redis->set('a', '1');
- Assert::assert(!$ret);
-
- $ret = $redis->setDefer(false);
- Assert::assert(!$ret);
-
- $ret = $redis->unsubscribe(['channel1']);
- Assert::assert($ret);
-
- $ret = $redis->recv();
- Assert::same($ret[0], 'unsubscribe');
- Assert::same($ret[1], 'channel1');
- Assert::same($ret[2], 1);
-
- $ret = $redis->getDefer();
- Assert::assert(!$ret);
-
- $ret = $redis->set('a', '1');
- Assert::assert(!$ret);
-
- $ret = $redis->setDefer(false);
- Assert::assert(!$ret);
-
- $redis->close();
-});
-
-?>
---EXPECTF--
-Warning: Swoole\Coroutine\Redis::setDefer(): you should not use setDefer after subscribe in %s/tests/swoole_redis_coro/unsubscribe_not_all.php on line 24
-
-Warning: Swoole\Coroutine\Redis::setDefer(): you should not use setDefer after subscribe in %s/tests/swoole_redis_coro/unsubscribe_not_all.php on line 41
diff --git a/tests/swoole_redis_coro/zpop.phpt b/tests/swoole_redis_coro/zpop.phpt
deleted file mode 100644
index 09025992467..00000000000
--- a/tests/swoole_redis_coro/zpop.phpt
+++ /dev/null
@@ -1,75 +0,0 @@
---TEST--
-swoole_redis_coro: zPopMin zPopMax bzPopMin bzPopMax
---SKIPIF--
-
---FILE--
-setOptions(['compatibility_mode' => true]);
- $redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
-
- $redis->delete('zkeyA');
- $redis->zAdd('zkeyA', 1, 'val1');
- $redis->zAdd('zkeyA', 2, 'val2');
- $redis->zAdd('zkeyA', 3, 'val3');
- $redis->zAdd('zkeyA', 4, 'val4');
- $redis->zAdd('zkeyA', 5, 'val5');
-
- $redis->delete('zkeyB');
- $redis->zAdd('zkeyB', 1, 'val1');
- $redis->zAdd('zkeyB', 2, 'val2');
- $redis->zAdd('zkeyB', 3, 'val3');
- $redis->zAdd('zkeyB', 4, 'val4');
- $redis->zAdd('zkeyB', 5, 'val5');
-
- echo "-----zPopMin---\n";
- var_dump($redis->zPopMin('zkeyA'));
- echo "-----zPopMax---\n";
- var_dump($redis->zPopMax('zkeyB'));
- echo "-----bzPopMin---\n";
- var_dump($redis->bzPopMin(['zkeyB','zkeyA'], 2));
- echo "-----bzPopMax---\n";
- var_dump($redis->bzPopMax('zkeyB','zkeyA', 2));
- echo "-----bzPopMin no data---\n";
- var_dump($redis->bzPopMin('zkeyC','zkeyD', 2));
-});
-?>
---EXPECT--
------zPopMin---
-array(2) {
- [0]=>
- string(4) "val1"
- [1]=>
- string(1) "1"
-}
------zPopMax---
-array(2) {
- [0]=>
- string(4) "val5"
- [1]=>
- string(1) "5"
-}
------bzPopMin---
-array(3) {
- [0]=>
- string(5) "zkeyB"
- [1]=>
- string(4) "val1"
- [2]=>
- string(1) "1"
-}
------bzPopMax---
-array(3) {
- [0]=>
- string(5) "zkeyB"
- [1]=>
- string(4) "val4"
- [2]=>
- string(1) "4"
-}
------bzPopMin no data---
-NULL
diff --git a/tests/swoole_runtime/stream_select/base.phpt b/tests/swoole_runtime/stream_select/base.phpt
index 7870b3b26a1..731f7813d86 100644
--- a/tests/swoole_runtime/stream_select/base.phpt
+++ b/tests/swoole_runtime/stream_select/base.phpt
@@ -7,9 +7,8 @@ swoole_runtime/stream_select: base
require __DIR__ . '/../../include/bootstrap.php';
Swoole\Runtime::enableCoroutine();
go(function () {
- Swoole\Runtime::enableCoroutine();
- $fp1 = stream_socket_client("tcp://www.baidu.com:80", $errno, $errstr, 30);
- $fp2 = stream_socket_client("tcp://www.qq.com:80", $errno, $errstr, 30);
+ $fp1 = stream_socket_client("tcp://" . TEST_DOMAIN_1 . ":80", $errno, $errstr, 30);
+ $fp2 = stream_socket_client("tcp://" . TEST_DOMAIN_2 . ":80", $errno, $errstr, 30);
if (!$fp1) {
echo "$errstr ($errno)
\n";
} else {
@@ -28,5 +27,6 @@ go(function () {
fclose($fp1);
}
});
+Swoole\Runtime::enableCoroutine(0);
?>
--EXPECT--
diff --git a/tests/swoole_runtime/stream_select/blocked.phpt b/tests/swoole_runtime/stream_select/blocked.phpt
index a684299be8d..61bd607763b 100644
--- a/tests/swoole_runtime/stream_select/blocked.phpt
+++ b/tests/swoole_runtime/stream_select/blocked.phpt
@@ -6,12 +6,12 @@ swoole_runtime/stream_select: blocked
\n";
} else {
- fwrite($fp1, "GET / HTTP/1.0\r\nHost: www.baidu.com\r\nUser-Agent: curl/7.58.0\r\nAccept: */*\r\n\r\n");
+ fwrite($fp1, "GET / HTTP/1.0\r\nHost: " . TEST_DOMAIN_1 . "\r\nUser-Agent: curl/7.58.0\r\nAccept: */*\r\n\r\n");
$r_array = [$fp1, $fp2];
$w_array = $e_array = null;
$n = stream_select($r_array, $w_array, $e_array, 10);
diff --git a/tests/swoole_server/bug_2308.phpt b/tests/swoole_server/bug_2308.phpt
index 233635d4dc0..253bb68defb 100644
--- a/tests/swoole_server/bug_2308.phpt
+++ b/tests/swoole_server/bug_2308.phpt
@@ -19,10 +19,11 @@ $pm->childFunc = function () use ($pm) {
'worker_num' => MAX_PROCESS_NUM,
'log_file' => '/dev/null',
'enable_coroutine' => false,
+ 'hook_flags' => SWOOLE_HOOK_ALL,
]);
$server->on('start', function () {
Swoole\Coroutine::create(function () {
- $redis = new Swoole\Coroutine\Redis();
+ $redis = new \Redis();
$redis->connect(REDIS_SERVER_HOST, REDIS_SERVER_PORT);
$ret = $redis->set('foo', 'bar');
Assert::assert($ret);
diff --git a/tests/swoole_server/force_reload.phpt b/tests/swoole_server/force_reload.phpt
index ec2eecc4e1f..29e9284c982 100644
--- a/tests/swoole_server/force_reload.phpt
+++ b/tests/swoole_server/force_reload.phpt
@@ -64,7 +64,7 @@ Assert::eq($atomic->get(), WORKER_NUM * 2);
[%s] WARNING Manager::kill_timeout_process() (ERRNO 9101): worker(pid=%d, id=%d) exit timeout, force kill the process
[%s] WARNING Manager::kill_timeout_process() (ERRNO 9101): worker(pid=%d, id=%d) exit timeout, force kill the process
[%s] WARNING Manager::kill_timeout_process() (ERRNO 9101): worker(pid=%d, id=%d) exit timeout, force kill the process
-[%s] WARNING Server::check_worker_exit_status(): worker(pid=%d, id=%d) abnormal exit, status=0, signal=9
-[%s] WARNING Server::check_worker_exit_status(): worker(pid=%d, id=%d) abnormal exit, status=0, signal=9
-[%s] WARNING Server::check_worker_exit_status(): worker(pid=%d, id=%d) abnormal exit, status=0, signal=9
-[%s] WARNING Server::check_worker_exit_status(): worker(pid=%d, id=%d) abnormal exit, status=0, signal=9
+[%s] WARNING Factory::check_worker_exit_status(): worker(pid=%d, id=%d) abnormal exit, status=0, signal=9
+[%s] WARNING Factory::check_worker_exit_status(): worker(pid=%d, id=%d) abnormal exit, status=0, signal=9
+[%s] WARNING Factory::check_worker_exit_status(): worker(pid=%d, id=%d) abnormal exit, status=0, signal=9
+[%s] WARNING Factory::check_worker_exit_status(): worker(pid=%d, id=%d) abnormal exit, status=0, signal=9
diff --git a/tests/swoole_server/force_reload2.phpt b/tests/swoole_server/force_reload2.phpt
index 1144d868c26..0f1576122f6 100644
--- a/tests/swoole_server/force_reload2.phpt
+++ b/tests/swoole_server/force_reload2.phpt
@@ -62,7 +62,7 @@ $pm->run();
%d [%d] stop
%d [%d] start
[%s] WARNING Manager::kill_timeout_process() (ERRNO 9101): worker(pid=%d, id=0) exit timeout, force kill the process
-[%s] WARNING Server::check_worker_exit_status(): worker(pid=%d, id=0) abnormal exit, status=0, signal=9
+[%s] WARNING Factory::check_worker_exit_status(): worker(pid=%d, id=0) abnormal exit, status=0, signal=9
%d [%d] start
%d [%d] stop
%d [%d] stop
diff --git a/tests/swoole_server/heartbeat_with_base.phpt b/tests/swoole_server/heartbeat_with_base.phpt
index c984de02a5c..a067505c6b4 100644
--- a/tests/swoole_server/heartbeat_with_base.phpt
+++ b/tests/swoole_server/heartbeat_with_base.phpt
@@ -8,13 +8,13 @@ skip_if_in_valgrind();
--FILE--
parentFunc = function ($pid) use ($pm)
-{
+$pm->parentFunc = function ($pid) use ($pm) {
$client = new Swoole\Client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);
- if (!$client->connect('127.0.0.1', $pm->getFreePort(), 5, 0))
- {
+ if (!$client->connect('127.0.0.1', $pm->getFreePort(), 5, 0)) {
echo "Over flow. errno=" . $client->errCode;
die("\n");
}
@@ -25,19 +25,17 @@ $pm->parentFunc = function ($pid) use ($pm)
Swoole\Process::kill($pid);
};
-$pm->childFunc = function () use ($pm)
-{
+$pm->childFunc = function () use ($pm) {
$serv = new Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE);
$serv->set(array(
'heartbeat_check_interval' => 1,
'heartbeat_idle_time' => 2,
+ 'worker_num' => 1,
));
- $serv->on("WorkerStart", function (Server $serv) use ($pm)
- {
+ $serv->on("WorkerStart", function (Server $serv) use ($pm) {
$pm->wakeup();
});
- $serv->on('receive', function (Server $serv, $fd, $rid, $data)
- {
+ $serv->on('receive', function (Server $serv, $fd, $rid, $data) {
});
$serv->start();
};
diff --git a/tests/swoole_server/task/kill_01.phpt b/tests/swoole_server/task/kill_01.phpt
index 7c5a83d0d09..e6e96938868 100644
--- a/tests/swoole_server/task/kill_01.phpt
+++ b/tests/swoole_server/task/kill_01.phpt
@@ -14,9 +14,8 @@ const PROC_NAME = 'swoole_unittest_server_task_worker';
$pm = new SwooleTest\ProcessManager;
$pm->parentFunc = function ($pid) use ($pm) {
- for ($i = 0; $i < 5; $i++)
- {
- //杀死进程
+ for ($i = 0; $i < 5; $i++) {
+ // 杀死进程
kill_process_by_name(PROC_NAME);
usleep(10000);
//判断进程是否存在
diff --git a/tests/swoole_thread/async-io.phpt b/tests/swoole_thread/async-io.phpt
new file mode 100644
index 00000000000..045b9376243
--- /dev/null
+++ b/tests/swoole_thread/async-io.phpt
@@ -0,0 +1,52 @@
+--TEST--
+swoole_thread: async-io
+--SKIPIF--
+
+--FILE--
+join();
+ }
+ Assert::eq($atomic->get(), C * N);
+ Assert::eq($atomicLong->get(), C * N * M);
+} else {
+ $id = $args[0];
+ $atomic = $args[1];
+ $atomicLong = $args[2];
+ 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);
+ }
+ });
+ exit(0);
+}
+echo "DONE\n";
+?>
+--EXPECTF--
+DONE
diff --git a/tests/swoole_thread/atomic_ctor.phpt b/tests/swoole_thread/atomic_ctor.phpt
new file mode 100644
index 00000000000..99063beaf87
--- /dev/null
+++ b/tests/swoole_thread/atomic_ctor.phpt
@@ -0,0 +1,45 @@
+--TEST--
+swoole_thread: atomic ctor
+--SKIPIF--
+
+--FILE--
+parentFunc = function () {
+ $lock = new Lock;
+ $lock->lock();
+ $num1 = random_int(1, 1 << 31);
+ $num2 = random_int(1 << 31, PHP_INT_MAX);
+ $atomic1 = new Swoole\Thread\Atomic($num1);
+ $atomic2 = new Swoole\Thread\Atomic\Long($num2);
+ $thread = Thread::exec(__FILE__, $lock, $atomic1, $atomic2, $num1, $num2);
+ $lock->lock();
+ echo "main thread\n";
+ $thread->join();
+};
+
+$tm->childFunc = function ($lock, $atomic1, $atomic2, $num1, $num2) {
+ echo "child thread\n";
+ usleep(200_000);
+ $lock->unlock();
+ Assert::eq($atomic1->get(), $num1);
+ Assert::eq($atomic2->get(), $num2);
+ exit(0);
+};
+
+$tm->run();
+?>
+--EXPECTF--
+child thread
+main thread
+
diff --git a/tests/swoole_thread/co-stream.phpt b/tests/swoole_thread/co-stream.phpt
new file mode 100644
index 00000000000..59f6bbe68c9
--- /dev/null
+++ b/tests/swoole_thread/co-stream.phpt
@@ -0,0 +1,57 @@
+--TEST--
+swoole_thread: co stream
+--SKIPIF--
+
+--FILE--
+initFreePorts();
+
+$tm->parentFunc = function () use ($tm) {
+ Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
+ Co\run(function () use ($tm) {
+ $queue = new Queue();
+ $fp = stream_socket_server('tcp://127.0.0.1:' . $tm->getFreePort(), $errno, $errstr);
+ $queue->push($fp);
+ $thread = new Thread(__FILE__, $queue);
+ var_dump('main thread');
+ $thread->join();
+ });
+};
+
+$tm->childFunc = function ($queue) use ($tm) {
+ var_dump('child thread');
+ $fp = $queue->pop();
+ Co\run(function () use ($fp, $tm) {
+ var_dump('child thread, co 0');
+ Co\go(function () use ($tm) {
+ var_dump('child thread, co 1');
+ $client = stream_socket_client('tcp://127.0.0.1:' . $tm->getFreePort(), $errno, $errstr);
+ Assert::notEmpty($client);
+ $data = fread($client, 8192);
+ Assert::eq($data, "hello world\n");
+ fclose($client);
+ });
+ $conn = stream_socket_accept($fp, -1);
+ fwrite($conn, "hello world\n");
+ fclose($conn);
+ fclose($fp);
+ });
+};
+
+$tm->run();
+?>
+--EXPECT--
+string(11) "main thread"
+string(12) "child thread"
+string(18) "child thread, co 0"
+string(18) "child thread, co 1"
diff --git a/tests/swoole_thread/info.phpt b/tests/swoole_thread/info.phpt
new file mode 100644
index 00000000000..c84d8a8c69e
--- /dev/null
+++ b/tests/swoole_thread/info.phpt
@@ -0,0 +1,33 @@
+--TEST--
+swoole_thread: info
+--SKIPIF--
+
+--FILE--
+parentFunc = function () {
+ $thread = Thread::exec(__FILE__, 'child');
+ $info = Thread::getTsrmInfo();
+ Assert::true($info['is_main_thread']);
+ Assert::eq($info['api_name'], 'POSIX Threads');
+ $thread->join();
+};
+
+$tm->childFunc = function () {
+ $info = Thread::getTsrmInfo();
+ Assert::false($info['is_main_thread']);
+ Assert::eq($info['api_name'], 'POSIX Threads');
+};
+
+$tm->run();
+?>
+--EXPECTF--
+
diff --git a/tests/swoole_thread/lock.phpt b/tests/swoole_thread/lock.phpt
new file mode 100644
index 00000000000..179aa5d9283
--- /dev/null
+++ b/tests/swoole_thread/lock.phpt
@@ -0,0 +1,38 @@
+--TEST--
+swoole_thread: lock
+--SKIPIF--
+
+--FILE--
+parentFunc = function () {
+ $lock = new Lock;
+ $lock->lock();
+ $thread = Thread::exec(__FILE__, $lock);
+ $lock->lock();
+ echo "main thread\n";
+ $thread->join();
+};
+
+$tm->childFunc = function ($lock) {
+ echo "child thread\n";
+ usleep(200_000);
+ $lock->unlock();
+ exit(0);
+};
+
+$tm->run();
+?>
+--EXPECTF--
+child thread
+main thread
+
diff --git a/tests/swoole_thread/pipe.phpt b/tests/swoole_thread/pipe.phpt
new file mode 100644
index 00000000000..8ba07a121fb
--- /dev/null
+++ b/tests/swoole_thread/pipe.phpt
@@ -0,0 +1,39 @@
+--TEST--
+swoole_thread: pipe
+--SKIPIF--
+
+--FILE--
+recv(8192), $rdata);
+ $thread->join();
+ echo "DONE\n";
+ });
+} else {
+ $sockets = $args[0];
+ $rdata = $args[1];
+ // Child threads are not allowed to modify hook flags
+ Assert::false(Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_ALL));
+ Co\run(function () use ($sockets, $rdata, $argv) {
+ usleep(100);
+ shell_exec('sleep 0.01');
+ $sockets[1]->send($rdata);
+ });
+ exit(0);
+}
+?>
+--EXPECTF--
+DONE
diff --git a/tests/swoole_thread/queue.phpt b/tests/swoole_thread/queue.phpt
new file mode 100644
index 00000000000..a33c1da8eec
--- /dev/null
+++ b/tests/swoole_thread/queue.phpt
@@ -0,0 +1,63 @@
+--TEST--
+swoole_thread: queue
+--SKIPIF--
+
+--FILE--
+push($rdata, Queue::NOTIFY_ONE);
+ usleep(random_int(100, 1000));
+ }
+ $n = 4;
+ while ($n--) {
+ $queue->push('', Queue::NOTIFY_ONE);
+ }
+ for ($i = 0; $i < C; $i++) {
+ $threads[$i]->join();
+ $total_child += $map[$i];
+ }
+ Assert::eq($queue->count(), 0);
+ Assert::eq($total_parent, $total_child);
+} else {
+ $i = $args[0];
+ $queue = $args[1];
+ $map = $args[2];
+ $map[$i] = 0;
+ while (1) {
+ $job = $queue->pop(-1);
+ if (!$job) {
+ break;
+ }
+ $map[$i] += strlen($job);
+ Assert::assert(strlen($job), 16);
+ }
+ exit(0);
+}
+?>
+--EXPECTF--
+
diff --git a/tests/swoole_thread/server/base.phpt b/tests/swoole_thread/server/base.phpt
new file mode 100644
index 00000000000..9de0b22c4fc
--- /dev/null
+++ b/tests/swoole_thread/server/base.phpt
@@ -0,0 +1,79 @@
+--TEST--
+swoole_thread/server: base
+--SKIPIF--
+
+--FILE--
+initFreePorts();
+
+$tm->parentFunc = function () use ($tm) {
+ $queue = new Swoole\Thread\Queue();
+ $atomic = new Swoole\Thread\Atomic(1);
+ $thread = Thread::exec(__FILE__, $queue, $atomic);
+ echo $queue->pop(-1);
+ Co\run(function () use ($tm) {
+ $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', $tm->getFreePort(), 2));
+ $cli->send(json_encode(['type' => 'eof']) . "\r\n");
+ Assert::eq($cli->recv(), "EOF\r\n");
+ });
+ $atomic->set(0);
+ echo "done\n";
+ echo $queue->pop(-1);
+};
+
+$tm->childFunc = function ($queue, $atomic) use ($tm) {
+ $serv = new Swoole\Server('127.0.0.1', $tm->getFreePort(), SWOOLE_THREAD);
+ $serv->set(array(
+ 'worker_num' => 2,
+ 'log_level' => SWOOLE_LOG_ERROR,
+ 'open_eof_check' => true,
+ 'package_eof' => "\r\n",
+ 'init_arguments' => function () use ($queue, $atomic) {
+ return [$queue, $atomic];
+ }
+ ));
+ $serv->on("WorkerStart", function (Swoole\Server $serv, $workerId) use ($queue, $atomic) {
+ if ($workerId == 0) {
+ $queue->push("begin\n", Thread\Queue::NOTIFY_ALL);
+ \Swoole\Timer::tick(200, function ($timerId) use ($atomic, $serv) {
+ if ($atomic->get() == 0) {
+ $serv->shutdown();
+ \Swoole\Timer::clear($timerId);
+ }
+ });
+ }
+ });
+ $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 () use ($queue, $atomic) {
+ $queue->push("shutdown\n", Thread\Queue::NOTIFY_ALL);
+ });
+ $serv->start();
+};
+
+$tm->run();
+?>
+--EXPECT--
+begin
+done
+shutdown
diff --git a/tests/swoole_thread/server/send_large_packet.phpt b/tests/swoole_thread/server/send_large_packet.phpt
new file mode 100644
index 00000000000..889ade98496
--- /dev/null
+++ b/tests/swoole_thread/server/send_large_packet.phpt
@@ -0,0 +1,101 @@
+--TEST--
+swoole_thread/server: send large packet
+--SKIPIF--
+
+--FILE--
+initFreePorts();
+
+$tm->parentFunc = function () use ($tm) {
+ $queue = new Swoole\Thread\Queue();
+ $atomic = new Swoole\Thread\Atomic(1);
+ $thread = Thread::exec(__FILE__, $queue, $atomic);
+ echo $queue->pop(-1);
+
+ $c = MAX_CONCURRENCY_LOW;
+ $n = MAX_REQUESTS_LOW;
+
+ for ($i = 0; $i < $c; $i++) {
+ go(function () use ($tm, $i, $n, $atomic) {
+ $cli = new Co\Client(SWOOLE_SOCK_TCP);
+ $cli->set([
+ 'open_length_check' => true,
+ 'package_max_length' => 4 * 1024 * 1024,
+ 'package_length_type' => 'N',
+ 'package_length_offset' => 0,
+ 'package_body_offset' => 4,
+ ]);
+ if ($cli->connect('127.0.0.1', $tm->getFreePort(), 2) == false) {
+ echo "ERROR\n";
+ return;
+ }
+ for ($i = 0; $i < $n; $i++) {
+ $sid = strval(rand(10000000, 99999999));
+ $send_data = str_repeat('A', 1000) . $sid;
+ $cli->send(pack('N', strlen($send_data)) . $send_data);
+ $data = $cli->recv();
+ Assert::same(strlen($data), SIZE);
+ Assert::same($sid, substr($data, -8, 8));
+ }
+ });
+ }
+ Swoole\Event::wait();
+ $atomic->set(0);
+ echo "done\n";
+ echo $queue->pop(-1);
+};
+
+$tm->childFunc = function ($queue, $atomic) use ($tm) {
+ $serv = new Swoole\Server('127.0.0.1', $tm->getFreePort(), SWOOLE_THREAD);
+ $serv->set(array(
+ 'worker_num' => 2,
+ 'log_level' => SWOOLE_LOG_ERROR,
+ 'open_length_check' => true,
+ 'package_max_length' => 4 * 1024 * 1024,
+ 'package_length_type' => 'N',
+ 'package_length_offset' => 0,
+ 'package_body_offset' => 4,
+ 'init_arguments' => function () use ($queue, $atomic) {
+ return [$queue, $atomic];
+ }
+ ));
+ $serv->on("WorkerStart", function (Swoole\Server $serv, $workerId) use ($queue, $atomic) {
+ if ($workerId == 0) {
+ $queue->push("begin\n", Thread\Queue::NOTIFY_ALL);
+ \Swoole\Timer::tick(200, function ($timerId) use ($atomic, $serv) {
+ if ($atomic->get() == 0) {
+ $serv->shutdown();
+ \Swoole\Timer::clear($timerId);
+ }
+ });
+ }
+ });
+ $serv->on("WorkerStop", function (Swoole\Server $serv, $workerId) use ($queue, $atomic) {
+ });
+ $serv->on('receive', function (Swoole\Server $serv, $fd, $rid, $data) use ($queue, $atomic) {
+ $send_data = str_repeat('A', SIZE - 12) . substr($data, -8, 8);
+ $serv->send($fd, pack('N', strlen($send_data)) . $send_data);
+ });
+ $serv->on('shutdown', function () use ($queue, $atomic) {
+ $queue->push("shutdown\n", Thread\Queue::NOTIFY_ALL);
+ });
+ $serv->start();
+};
+
+$tm->run();
+?>
+--EXPECT--
+begin
+done
+shutdown
diff --git a/tests/swoole_thread/signal.phpt b/tests/swoole_thread/signal.phpt
new file mode 100644
index 00000000000..8a68b60080c
--- /dev/null
+++ b/tests/swoole_thread/signal.phpt
@@ -0,0 +1,56 @@
+--TEST--
+swoole_thread: signal
+--SKIPIF--
+
+--FILE--
+send('exit');
+ }
+ Co\go(function () use ($parent_pipe, $thread) {
+ // 从管道中读取子线程退出的信息
+ echo $parent_pipe->recv(8192), PHP_EOL;
+ // 回收子线程
+ $thread->join();
+ });
+ });
+} else {
+ $sockets = $args[0];
+ $child_pipe = $sockets[0];
+ Co\run(function () use ($child_pipe) {
+ // 收到父线程的指令,开始退出
+ echo $child_pipe->recv(8192), PHP_EOL;
+ // 通知父线程已退出
+ $child_pipe->send('child exit');
+ });
+ exit(0);
+}
+?>
+--EXPECTF--
+timer
+signal term
+exit
+child exit
diff --git a/tests/swoole_thread/stream.phpt b/tests/swoole_thread/stream.phpt
new file mode 100644
index 00000000000..3052ce1ba00
--- /dev/null
+++ b/tests/swoole_thread/stream.phpt
@@ -0,0 +1,52 @@
+--TEST--
+swoole_thread: stream
+--SKIPIF--
+
+--FILE--
+initFreePorts();
+
+$tm->parentFunc = function () use ($tm) {
+ $queue = new Queue();
+ $fp = stream_socket_server('tcp://127.0.0.1:' . $tm->getFreePort(), $errno, $errstr);
+ $queue->push($fp);
+ $thread = new Thread(__FILE__, $queue, 0);
+ var_dump('main thread');
+ $thread->join();
+};
+
+$tm->childFunc = function ($queue, $id) use ($tm) {
+ if ($id === 0) {
+ var_dump('child thread 0');
+ $fp = $queue->pop();
+ $thread = new Thread(__FILE__, $queue, 1);
+ $conn = stream_socket_accept($fp, -1);
+ fwrite($conn, "hello world\n");
+ fclose($conn);
+ fclose($fp);
+ $thread->join();
+ } else {
+ var_dump('child thread 1');
+ $client = stream_socket_client('tcp://127.0.0.1:' . $tm->getFreePort(), $errno, $errstr);
+ Assert::notEmpty($client);
+ $data = fread($client, 8192);
+ Assert::eq($data, "hello world\n");
+ fclose($client);
+ }
+};
+
+$tm->run();
+?>
+--EXPECT--
+string(11) "main thread"
+string(14) "child thread 0"
+string(14) "child thread 1"
diff --git a/tests/swoole_thread/stream_arg.phpt b/tests/swoole_thread/stream_arg.phpt
new file mode 100644
index 00000000000..871049bd624
--- /dev/null
+++ b/tests/swoole_thread/stream_arg.phpt
@@ -0,0 +1,49 @@
+--TEST--
+swoole_thread: stream as a thread argument
+--SKIPIF--
+
+--FILE--
+initFreePorts();
+
+$tm->parentFunc = function () use ($tm) {
+ $fp = stream_socket_server('tcp://127.0.0.1:' . $tm->getFreePort(), $errno, $errstr);
+ $thread = new Thread(__FILE__, $fp, 0);
+ var_dump('main thread');
+ $thread->join();
+};
+
+$tm->childFunc = function ($fp, $id) use ($tm) {
+ if ($id === 0) {
+ var_dump('child thread 0');
+ $thread = new Thread(__FILE__, $fp, 1);
+ $conn = stream_socket_accept($fp, -1);
+ fwrite($conn, "hello world\n");
+ fclose($conn);
+ fclose($fp);
+ $thread->join();
+ } else {
+ var_dump('child thread 1');
+ $client = stream_socket_client('tcp://127.0.0.1:' . $tm->getFreePort(), $errno, $errstr);
+ Assert::notEmpty($client);
+ $data = fread($client, 8192);
+ Assert::eq($data, "hello world\n");
+ fclose($client);
+ }
+};
+
+$tm->run();
+?>
+--EXPECT--
+string(11) "main thread"
+string(14) "child thread 0"
+string(14) "child thread 1"
diff --git a/tests/swoole_timer/enable_coroutine2.phpt b/tests/swoole_timer/enable_coroutine2.phpt
index 44ad8d319e2..18e0d107342 100644
--- a/tests/swoole_timer/enable_coroutine2.phpt
+++ b/tests/swoole_timer/enable_coroutine2.phpt
@@ -5,20 +5,23 @@ swoole_timer: enable_coroutine setting
--FILE--
false
]);
Swoole\Timer::after(1, function () {
$uid = Co::getuid();
echo "#{$uid}\n";
- Swoole\Timer::set([
- 'enable_coroutine' => true
- ]);
- Swoole\Timer::after(1, function () {
- $uid = Co::getuid();
- echo "#{$uid}\n";
- });
});
+Swoole\Event::wait();
+
+swoole_async_set([
+ 'enable_coroutine' => true
+]);
+Swoole\Timer::after(1, function () {
+ $uid = Co::getuid();
+ echo "#{$uid}\n";
+});
+Swoole\Event::wait();
?>
--EXPECT--
#-1
diff --git a/tests/swoole_timer/function_alias.phpt b/tests/swoole_timer/function_alias.phpt
index 61cf74fab80..870f6eca27d 100644
--- a/tests/swoole_timer/function_alias.phpt
+++ b/tests/swoole_timer/function_alias.phpt
@@ -7,7 +7,6 @@ swoole_timer: function alias
require __DIR__ . '/../include/bootstrap.php';
var_dump(
- function_exists('swoole_timer_set') &&
function_exists('swoole_timer_after') &&
function_exists('swoole_timer_tick') &&
function_exists('swoole_timer_exists') &&
diff --git a/thirdparty/boost/asm/combined.S b/thirdparty/boost/asm/combined.S
index 4fdba6b03bc..3aeb528fd97 100644
--- a/thirdparty/boost/asm/combined.S
+++ b/thirdparty/boost/asm/combined.S
@@ -8,6 +8,9 @@
#elif defined(__arm64__)
#include "make_arm64_aapcs_elf_gas.S"
#include "jump_arm64_aapcs_elf_gas.S"
+ #elif defined(__loongarch64)
+ #include "make_loongarch64_sysv_elf_gas.S"
+ #include "jump_loongarch64_sysv_elf_gas.S"
#else
#error "No arch's"
#endif
diff --git a/thirdparty/boost/asm/jump_arm64_aapcs_elf_gas.S b/thirdparty/boost/asm/jump_arm64_aapcs_elf_gas.S
index 4780fb86fd2..47282c18e96 100644
--- a/thirdparty/boost/asm/jump_arm64_aapcs_elf_gas.S
+++ b/thirdparty/boost/asm/jump_arm64_aapcs_elf_gas.S
@@ -1,5 +1,5 @@
/*
- Copyright Edward Nevill 2015
+ Copyright Edward Nevill + Oliver Kowalke 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
@@ -51,7 +51,7 @@
* *
*******************************************************/
-.cpu generic+fp+simd
+.file "jump_arm64_aapcs_elf_gas.S"
.text
.align 2
.global swoole_jump_fcontext
@@ -60,23 +60,12 @@ swoole_jump_fcontext:
# prepare stack for GP + FPU
sub sp, sp, #0xb0
-# Because gcc may save integer registers in fp registers across a
-# function call we cannot skip saving the fp registers.
-#
-# Do not reinstate this test unless you fully understand what you
-# are doing.
-#
-# # test if fpu env should be preserved
-# cmp w3, #0
-# b.eq 1f
-
# save d8 - d15
stp d8, d9, [sp, #0x00]
stp d10, d11, [sp, #0x10]
stp d12, d13, [sp, #0x20]
stp d14, d15, [sp, #0x30]
-1:
# save x19-x30
stp x19, x20, [sp, #0x40]
stp x21, x22, [sp, #0x50]
@@ -88,17 +77,11 @@ swoole_jump_fcontext:
# save LR as PC
str x30, [sp, #0xa0]
- # store RSP (pointing to context-data) in first argument (x0).
- # STR cannot have sp as a target register
+ # store RSP (pointing to context-data) in X0
mov x4, sp
- str x4, [x0]
-
- # restore RSP (pointing to context-data) from A2 (x1)
- mov sp, x1
-# # test if fpu env should be preserved
-# cmp w3, #0
-# b.eq 2f
+ # restore RSP (pointing to context-data) from X1
+ mov sp, x0
# load d8 - d15
ldp d8, d9, [sp, #0x00]
@@ -106,7 +89,6 @@ swoole_jump_fcontext:
ldp d12, d13, [sp, #0x20]
ldp d14, d15, [sp, #0x30]
-2:
# load x19-x30
ldp x19, x20, [sp, #0x40]
ldp x21, x22, [sp, #0x50]
@@ -115,9 +97,10 @@ swoole_jump_fcontext:
ldp x27, x28, [sp, #0x80]
ldp x29, x30, [sp, #0x90]
- # use third arg as return value after jump
- # and as first arg in context function
- mov x0, x2
+ # return transfer_t from jump
+ # pass transfer_t as first arg in context function
+ # X0 == FCTX, X1 == DATA
+ mov x0, x4
# load pc
ldr x4, [sp, #0xa0]
@@ -127,7 +110,5 @@ swoole_jump_fcontext:
ret x4
.size swoole_jump_fcontext,.-swoole_jump_fcontext
-#ifndef __NetBSD__
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
-#endif
diff --git a/thirdparty/boost/asm/jump_arm64_aapcs_macho_gas.S b/thirdparty/boost/asm/jump_arm64_aapcs_macho_gas.S
index 2cac1274264..dc544e026e4 100644
--- a/thirdparty/boost/asm/jump_arm64_aapcs_macho_gas.S
+++ b/thirdparty/boost/asm/jump_arm64_aapcs_macho_gas.S
@@ -1,3 +1,9 @@
+/*
+ Copyright Edward Nevill + Oliver Kowalke 2015
+ Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt)
+*/
/*******************************************************
* *
* ------------------------------------------------- *
@@ -52,20 +58,12 @@ _swoole_jump_fcontext:
; prepare stack for GP + FPU
sub sp, sp, #0xb0
-#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
- ; test if fpu env should be preserved
- cmp w3, #0
- b.eq 1f
-
; save d8 - d15
stp d8, d9, [sp, #0x00]
stp d10, d11, [sp, #0x10]
stp d12, d13, [sp, #0x20]
stp d14, d15, [sp, #0x30]
-1:
-#endif
-
; save x19-x30
stp x19, x20, [sp, #0x40]
stp x21, x22, [sp, #0x50]
@@ -77,18 +75,11 @@ _swoole_jump_fcontext:
; save LR as PC
str lr, [sp, #0xa0]
- ; store RSP (pointing to context-data) in first argument (x0).
- ; STR cannot have sp as a target register
+ ; store RSP (pointing to context-data) in X0
mov x4, sp
- str x4, [x0]
- ; restore RSP (pointing to context-data) from A2 (x1)
- mov sp, x1
-
-#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
- ; test if fpu env should be preserved
- cmp w3, #0
- b.eq 2f
+ ; restore RSP (pointing to context-data) from X1
+ mov sp, x0
; load d8 - d15
ldp d8, d9, [sp, #0x00]
@@ -96,9 +87,6 @@ _swoole_jump_fcontext:
ldp d12, d13, [sp, #0x20]
ldp d14, d15, [sp, #0x30]
-2:
-#endif
-
; load x19-x30
ldp x19, x20, [sp, #0x40]
ldp x21, x22, [sp, #0x50]
@@ -107,9 +95,10 @@ _swoole_jump_fcontext:
ldp x27, x28, [sp, #0x80]
ldp fp, lr, [sp, #0x90]
- ; use third arg as return value after jump
- ; and as first arg in context function
- mov x0, x2
+ ; return transfer_t from jump
+ ; pass transfer_t as first arg in context function
+ ; X0 == FCTX, X1 == DATA
+ mov x0, x4
; load pc
ldr x4, [sp, #0xa0]
diff --git a/thirdparty/boost/asm/jump_loongarch64_sysv_elf_gas.S b/thirdparty/boost/asm/jump_loongarch64_sysv_elf_gas.S
new file mode 100644
index 00000000000..89a08821ca6
--- /dev/null
+++ b/thirdparty/boost/asm/jump_loongarch64_sysv_elf_gas.S
@@ -0,0 +1,121 @@
+/*******************************************************
+ * *
+ * ------------------------------------------------- *
+ * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
+ * ------------------------------------------------- *
+ * | 0 | 8 | 16 | 24 | *
+ * ------------------------------------------------- *
+ * | FS0 | FS1 | FS2 | FS3 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
+ * ------------------------------------------------- *
+ * | 32 | 40 | 48 | 56 | *
+ * ------------------------------------------------- *
+ * | FS4 | FS5 | FS6 | FS7 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
+ * ------------------------------------------------- *
+ * | 64 | 72 | 80 | 88 | *
+ * ------------------------------------------------- *
+ * | S0 | S1 | S2 | S3 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
+ * ------------------------------------------------- *
+ * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
+ * ------------------------------------------------- *
+ * | S4 | S5 | S6 | S7 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
+ * ------------------------------------------------- *
+ * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
+ * ------------------------------------------------- *
+ * | S8 | FP | RA | PC | *
+ * ------------------------------------------------- *
+ * *
+ * *****************************************************/
+
+.file "jump_loongarch64_sysv_elf_gas.S"
+.text
+.globl swoole_jump_fcontext
+.align 2
+.type swoole_jump_fcontext,@function
+swoole_jump_fcontext:
+ # reserve space on stack
+ addi.d $sp, $sp, -160
+
+ # save fs0 - fs7
+ fst.d $fs0, $sp, 0
+ fst.d $fs1, $sp, 8
+ fst.d $fs2, $sp, 16
+ fst.d $fs3, $sp, 24
+ fst.d $fs4, $sp, 32
+ fst.d $fs5, $sp, 40
+ fst.d $fs6, $sp, 48
+ fst.d $fs7, $sp, 56
+
+ # save s0 - s8, fp, ra
+ st.d $s0, $sp, 64
+ st.d $s1, $sp, 72
+ st.d $s2, $sp, 80
+ st.d $s3, $sp, 88
+ st.d $s4, $sp, 96
+ st.d $s5, $sp, 104
+ st.d $s6, $sp, 112
+ st.d $s7, $sp, 120
+ st.d $s8, $sp, 128
+ st.d $fp, $sp, 136
+ st.d $ra, $sp, 144
+
+ # save RA as PC
+ st.d $ra, $sp, 152
+
+ # store SP (pointing to context-data) in A2
+ move $a2, $sp
+
+ # restore SP (pointing to context-data) from A0
+ move $sp, $a0
+
+ # load fs0 - fs7
+ fld.d $fs0, $sp, 0
+ fld.d $fs1, $sp, 8
+ fld.d $fs2, $sp, 16
+ fld.d $fs3, $sp, 24
+ fld.d $fs4, $sp, 32
+ fld.d $fs5, $sp, 40
+ fld.d $fs6, $sp, 48
+ fld.d $fs7, $sp, 56
+
+ #load s0 - s7
+ ld.d $s0, $sp, 64
+ ld.d $s1, $sp, 72
+ ld.d $s2, $sp, 80
+ ld.d $s3, $sp, 88
+ ld.d $s4, $sp, 96
+ ld.d $s5, $sp, 104
+ ld.d $s6, $sp, 112
+ ld.d $s7, $sp, 120
+ ld.d $s8, $sp, 128
+ ld.d $fp, $sp, 136
+ ld.d $ra, $sp, 144
+
+ # return transfer_t from jump
+ # pass transfer_t as first arg in context function
+ # a0 == FCTX, a1 == DATA
+ move $a0, $a2
+
+ # load PC
+ ld.d $a2, $sp, 152
+
+ # restore stack
+ addi.d $sp, $sp, 160
+
+ # jump to context
+ jr $a2
+.size swoole_jump_fcontext, .-swoole_jump_fcontext
+
+/* Mark that we don't need executable stack. */
+.section .note.GNU-stack,"",%progbits
diff --git a/thirdparty/boost/asm/jump_mips64_n64_elf_gas.S b/thirdparty/boost/asm/jump_mips64_n64_elf_gas.S
index 2c21bdaa97c..edff6ec0501 100644
--- a/thirdparty/boost/asm/jump_mips64_n64_elf_gas.S
+++ b/thirdparty/boost/asm/jump_mips64_n64_elf_gas.S
@@ -5,10 +5,6 @@
http://www.boost.org/LICENSE_1_0.txt)
*/
-/*
- "backported" version of original jump_mips64_n64_elf_gas.S
-*/
-
/*******************************************************
* *
* ------------------------------------------------- *
@@ -49,6 +45,7 @@
* *
* *****************************************************/
+.file "jump_mips64_n64_elf_gas.S"
.text
.globl swoole_jump_fcontext
.align 3
@@ -71,9 +68,6 @@ swoole_jump_fcontext:
sd $ra, 152($sp) # save RA as PC
#if defined(__mips_hard_float)
- # test if fpu env should be preserved
- beqz $a3, 1f
-
s.d $f24, 0($sp) # save F24
s.d $f25, 8($sp) # save F25
s.d $f26, 16($sp) # save F26
@@ -82,20 +76,15 @@ swoole_jump_fcontext:
s.d $f29, 40($sp) # save F29
s.d $f30, 48($sp) # save F30
s.d $f31, 56($sp) # save F31
-1:
#endif
- # store SP (pointing to context-data) in A0
- sd $sp, ($a0)
+ # store SP (pointing to old context-data) in v0 as return
+ move $v0, $sp
- # restore SP (pointing to context-data) from A1
- move $sp, $a1
+ # get SP (pointing to new context-data) from a0 param
+ move $sp, $a0
#if defined(__mips_hard_float)
- # test if fpu env should be preserved
- beqz $a3, 2f
-
-
l.d $f24, 0($sp) # restore F24
l.d $f25, 8($sp) # restore F25
l.d $f26, 16($sp) # restore F26
@@ -104,7 +93,6 @@ swoole_jump_fcontext:
l.d $f29, 40($sp) # restore F29
l.d $f30, 48($sp) # restore F30
l.d $f31, 56($sp) # restore F31
-2:
#endif
ld $s0, 64($sp) # restore S0
@@ -124,10 +112,8 @@ swoole_jump_fcontext:
# adjust stack
daddiu $sp, $sp, 160
- # use third arg as return value after jump
- move $v0, $a2
- # use third arg as first arg in context function
- move $a0, $a2
+ move $a0, $v0 # move old sp from v0 to a0 as param
+ move $v1, $a1 # move *data from a1 to v1 as return
# jump to context
jr $t9
@@ -136,4 +122,3 @@ swoole_jump_fcontext:
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-
diff --git a/thirdparty/boost/asm/jump_ppc64_sysv_elf_gas.S b/thirdparty/boost/asm/jump_ppc64_sysv_elf_gas.S
index 5cc97550b61..a90ffbe1681 100644
--- a/thirdparty/boost/asm/jump_ppc64_sysv_elf_gas.S
+++ b/thirdparty/boost/asm/jump_ppc64_sysv_elf_gas.S
@@ -12,82 +12,61 @@
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
- * | F14 | F15 | F16 | F17 | *
+ * | TOC | R14 | R15 | R16 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
- * | F18 | F19 | F20 | F21 | *
+ * | R17 | R18 | R19 | R20 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
- * | F22 | F23 | F24 | F25 | *
+ * | R21 | R22 | R23 | R24 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
- * | F26 | F27 | F28 | F29 | *
+ * | R25 | R26 | R27 | R28 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
- * | F30 | F31 | fpscr | TOC | *
+ * | R29 | R30 | R31 | hidden | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
- * | R14 | R15 | R16 | R17 | *
+ * | CR | LR | PC | back-chain| *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
* ------------------------------------------------- *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
- * | R18 | R19 | R20 | R21 | *
+ * | cr saved | lr saved | compiler | linker | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
* ------------------------------------------------- *
* | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
* ------------------------------------------------- *
- * | R22 | R23 | R24 | R25 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | *
- * ------------------------------------------------- *
- * | 256 | 260 | 264 | 268 | 272 | 276 | 280 | 284 | *
- * ------------------------------------------------- *
- * | R26 | R27 | R28 | R29 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | *
- * ------------------------------------------------- *
- * | 288 | 292 | 296 | 300 | 304 | 308 | 312 | 316 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | R30 | R31 | CR | LR | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 80 | 81 | | *
- * ------------------------------------------------- *
- * | 320 | 324 | | *
- * ------------------------------------------------- *
- * | PC | | *
+ * | TOC saved | FCTX | DATA | | *
* ------------------------------------------------- *
* *
*******************************************************/
+.file "jump_ppc64_sysv_elf_gas.S"
.globl swoole_jump_fcontext
#if _CALL_ELF == 2
.text
@@ -118,143 +97,118 @@ swoole_jump_fcontext:
# endif
#endif
# reserve space on stack
- subi %r1, %r1, 328
+ subi %r1, %r1, 184
#if _CALL_ELF != 2
- std %r2, 152(%r1) # save TOC
+ std %r2, 0(%r1) # save TOC
+#endif
+ std %r14, 8(%r1) # save R14
+ std %r15, 16(%r1) # save R15
+ std %r16, 24(%r1) # save R16
+ std %r17, 32(%r1) # save R17
+ std %r18, 40(%r1) # save R18
+ std %r19, 48(%r1) # save R19
+ std %r20, 56(%r1) # save R20
+ std %r21, 64(%r1) # save R21
+ std %r22, 72(%r1) # save R22
+ std %r23, 80(%r1) # save R23
+ std %r24, 88(%r1) # save R24
+ std %r25, 96(%r1) # save R25
+ std %r26, 104(%r1) # save R26
+ std %r27, 112(%r1) # save R27
+ std %r28, 120(%r1) # save R28
+ std %r29, 128(%r1) # save R29
+ std %r30, 136(%r1) # save R30
+ std %r31, 144(%r1) # save R31
+#if _CALL_ELF != 2
+ std %r3, 152(%r1) # save hidden
#endif
- std %r14, 160(%r1) # save R14
- std %r15, 168(%r1) # save R15
- std %r16, 176(%r1) # save R16
- std %r17, 184(%r1) # save R17
- std %r18, 192(%r1) # save R18
- std %r19, 200(%r1) # save R19
- std %r20, 208(%r1) # save R20
- std %r21, 216(%r1) # save R21
- std %r22, 224(%r1) # save R22
- std %r23, 232(%r1) # save R23
- std %r24, 240(%r1) # save R24
- std %r25, 248(%r1) # save R25
- std %r26, 256(%r1) # save R26
- std %r27, 264(%r1) # save R27
- std %r28, 272(%r1) # save R28
- std %r29, 280(%r1) # save R29
- std %r30, 288(%r1) # save R30
- std %r31, 296(%r1) # save R31
# save CR
mfcr %r0
- std %r0, 304(%r1)
+ std %r0, 160(%r1)
# save LR
mflr %r0
- std %r0, 312(%r1)
+ std %r0, 168(%r1)
# save LR as PC
- std %r0, 320(%r1)
-
- # test if fpu env should be preserved
- cmpwi cr7, %r6, 0
- beq cr7, 1f
-
- stfd %f14, 0(%r1) # save F14
- stfd %f15, 8(%r1) # save F15
- stfd %f16, 16(%r1) # save F16
- stfd %f17, 24(%r1) # save F17
- stfd %f18, 32(%r1) # save F18
- stfd %f19, 40(%r1) # save F19
- stfd %f20, 48(%r1) # save F20
- stfd %f21, 56(%r1) # save F21
- stfd %f22, 64(%r1) # save F22
- stfd %f23, 72(%r1) # save F23
- stfd %f24, 80(%r1) # save F24
- stfd %f25, 88(%r1) # save F25
- stfd %f26, 96(%r1) # save F26
- stfd %f27, 104(%r1) # save F27
- stfd %f28, 112(%r1) # save F28
- stfd %f29, 120(%r1) # save F29
- stfd %f30, 128(%r1) # save F30
- stfd %f31, 136(%r1) # save F31
- mffs %f0 # load FPSCR
- stfd %f0, 144(%r1) # save FPSCR
+ std %r0, 176(%r1)
-1:
- # store RSP (pointing to context-data) in R3
- std %r1, 0(%r3)
+ # store RSP (pointing to context-data) in R6
+ mr %r6, %r1
+#if _CALL_ELF == 2
+ # restore RSP (pointing to context-data) from R3
+ mr %r1, %r3
+#else
# restore RSP (pointing to context-data) from R4
mr %r1, %r4
- # test if fpu env should be preserved
- cmpwi cr7, %r6, 0
- beq cr7, 2f
-
- lfd %f14, 0(%r1) # restore F14
- lfd %f15, 8(%r1) # restore F15
- lfd %f16, 16(%r1) # restore F16
- lfd %f17, 24(%r1) # restore F17
- lfd %f18, 32(%r1) # restore F18
- lfd %f19, 40(%r1) # restore F19
- lfd %f20, 48(%r1) # restore F20
- lfd %f21, 56(%r1) # restore F21
- lfd %f22, 64(%r1) # restore F22
- lfd %f23, 72(%r1) # restore F23
- lfd %f24, 80(%r1) # restore F24
- lfd %f25, 88(%r1) # restore F25
- lfd %f26, 96(%r1) # restore F26
- lfd %f27, 104(%r1) # restore F27
- lfd %f28, 112(%r1) # restore F28
- lfd %f29, 120(%r1) # restore F29
- lfd %f30, 128(%r1) # restore F30
- lfd %f31, 136(%r1) # restore F31
- lfd %f0, 144(%r1) # load FPSCR
- mtfsf 0xff, %f0 # restore FPSCR
-
-2:
+ ld %r2, 0(%r1) # restore TOC
+#endif
+ ld %r14, 8(%r1) # restore R14
+ ld %r15, 16(%r1) # restore R15
+ ld %r16, 24(%r1) # restore R16
+ ld %r17, 32(%r1) # restore R17
+ ld %r18, 40(%r1) # restore R18
+ ld %r19, 48(%r1) # restore R19
+ ld %r20, 56(%r1) # restore R20
+ ld %r21, 64(%r1) # restore R21
+ ld %r22, 72(%r1) # restore R22
+ ld %r23, 80(%r1) # restore R23
+ ld %r24, 88(%r1) # restore R24
+ ld %r25, 96(%r1) # restore R25
+ ld %r26, 104(%r1) # restore R26
+ ld %r27, 112(%r1) # restore R27
+ ld %r28, 120(%r1) # restore R28
+ ld %r29, 128(%r1) # restore R29
+ ld %r30, 136(%r1) # restore R30
+ ld %r31, 144(%r1) # restore R31
#if _CALL_ELF != 2
- ld %r2, 152(%r1) # restore TOC
+ ld %r3, 152(%r1) # restore hidden
#endif
- ld %r14, 160(%r1) # restore R14
- ld %r15, 168(%r1) # restore R15
- ld %r16, 176(%r1) # restore R16
- ld %r17, 184(%r1) # restore R17
- ld %r18, 192(%r1) # restore R18
- ld %r19, 200(%r1) # restore R19
- ld %r20, 208(%r1) # restore R20
- ld %r21, 216(%r1) # restore R21
- ld %r22, 224(%r1) # restore R22
- ld %r23, 232(%r1) # restore R23
- ld %r24, 240(%r1) # restore R24
- ld %r25, 248(%r1) # restore R25
- ld %r26, 256(%r1) # restore R26
- ld %r27, 264(%r1) # restore R27
- ld %r28, 272(%r1) # restore R28
- ld %r29, 280(%r1) # restore R29
- ld %r30, 288(%r1) # restore R30
- ld %r31, 296(%r1) # restore R31
# restore CR
- ld %r0, 304(%r1)
+ ld %r0, 160(%r1)
mtcr %r0
# restore LR
- ld %r0, 312(%r1)
+ ld %r0, 168(%r1)
mtlr %r0
# load PC
- ld %r12, 320(%r1)
+ ld %r12, 176(%r1)
# restore CTR
mtctr %r12
# adjust stack
- addi %r1, %r1, 328
+ addi %r1, %r1, 184
- # use third arg as return value after jump
- # use third arg as first arg in context function
- mr %r3, %r5
+#if _CALL_ELF == 2
+ # copy transfer_t into transfer_fn arg registers
+ mr %r3, %r6
+ # arg pointer already in %r4
# jump to context
bctr
-#if _CALL_ELF == 2
.size swoole_jump_fcontext, .-swoole_jump_fcontext
#else
+ # zero in r3 indicates first jump to context-function
+ cmpdi %r3, 0
+ beq use_entry_arg
+
+ # return transfer_t
+ std %r6, 0(%r3)
+ std %r5, 8(%r3)
+
+ # jump to context
+ bctr
+
+use_entry_arg:
+ # copy transfer_t into transfer_fn arg registers
+ mr %r3, %r6
+ mr %r4, %r5
+
+ # jump to context
+ bctr
# ifdef _CALL_LINUX
.size .swoole_jump_fcontext, .-.L.swoole_jump_fcontext
# else
@@ -263,7 +217,5 @@ swoole_jump_fcontext:
#endif
-#ifndef __NetBSD__
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-#endif
diff --git a/thirdparty/boost/asm/jump_ppc64_sysv_macho_gas.S b/thirdparty/boost/asm/jump_ppc64_sysv_macho_gas.S
index d8d9aa4f513..abea7940628 100644
--- a/thirdparty/boost/asm/jump_ppc64_sysv_macho_gas.S
+++ b/thirdparty/boost/asm/jump_ppc64_sysv_macho_gas.S
@@ -12,215 +12,153 @@
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
- * | F14 | F15 | F16 | F17 | *
+ * | R13 | R14 | R15 | R16 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
- * | F18 | F19 | F20 | F21 | *
+ * | R17 | R18 | R19 | R20 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
- * | F22 | F23 | F24 | F25 | *
+ * | R21 | R22 | R23 | R24 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
- * | F26 | F27 | F28 | F29 | *
+ * | R25 | R26 | R27 | R28 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
- * | F30 | F31 | fpscr | R13 | *
+ * | R29 | R30 | R31 | hidden | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
- * | R14 | R15 | R16 | R17 | *
+ * | CR | LR | PC | back-chain| *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
* ------------------------------------------------- *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
- * | R18 | R19 | R20 | R21 | *
+ * | cr saved | lr saved | compiler | linker | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
* ------------------------------------------------- *
* | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
* ------------------------------------------------- *
- * | R22 | R23 | R24 | R25 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | *
- * ------------------------------------------------- *
- * | 256 | 260 | 264 | 268 | 272 | 276 | 280 | 284 | *
- * ------------------------------------------------- *
- * | R26 | R27 | R28 | R29 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | *
- * ------------------------------------------------- *
- * | 288 | 292 | 296 | 300 | 304 | 308 | 312 | 316 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | R30 | R31 | CR | LR | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 80 | 81 | | *
- * ------------------------------------------------- *
- * | 320 | 324 | | *
- * ------------------------------------------------- *
- * | PC | | *
+ * | FCTX | DATA | | | *
* ------------------------------------------------- *
* *
*******************************************************/
.text
.align 2
-.globl swoole_jump_fcontext
+.globl _swoole_jump_fcontext
_swoole_jump_fcontext:
; reserve space on stack
- subi r1, r1, 328
-
- std r13, 152(r1) ; save R13
- std r14, 160(r1) ; save R14
- std r15, 168(r1) ; save R15
- std r16, 176(r1) ; save R16
- std r17, 184(r1) ; save R17
- std r18, 192(r1) ; save R18
- std r19, 200(r1) ; save R19
- std r20, 208(r1) ; save R20
- std r21, 216(r1) ; save R21
- std r22, 224(r1) ; save R22
- std r23, 232(r1) ; save R23
- std r24, 240(r1) ; save R24
- std r25, 248(r1) ; save R25
- std r26, 256(r1) ; save R26
- std r27, 264(r1) ; save R27
- std r28, 272(r1) ; save R28
- std r29, 280(r1) ; save R29
- std r30, 288(r1) ; save R30
- std r31, 296(r1) ; save R31
+ subi r1, r1, 184
+
+ std r14, 8(r1) ; save R14
+ std r15, 16(r1) ; save R15
+ std r16, 24(r1) ; save R16
+ std r17, 32(r1) ; save R17
+ std r18, 40(r1) ; save R18
+ std r19, 48(r1) ; save R19
+ std r20, 56(r1) ; save R20
+ std r21, 64(r1) ; save R21
+ std r22, 72(r1) ; save R22
+ std r23, 80(r1) ; save R23
+ std r24, 88(r1) ; save R24
+ std r25, 96(r1) ; save R25
+ std r26, 104(r1) ; save R26
+ std r27, 112(r1) ; save R27
+ std r28, 120(r1) ; save R28
+ std r29, 128(r1) ; save R29
+ std r30, 136(r1) ; save R30
+ std r31, 144(r1) ; save R31
+ std r3, 152(r1) ; save hidden
; save CR
mfcr r0
- std r0, 304(r1)
+ std r0, 160(r1)
; save LR
mflr r0
- std r0, 312(r1)
+ std r0, 168(r1)
; save LR as PC
- std r0, 320(r1)
-
- ; test if fpu env should be preserved
- cmpwi cr7, r6, 0
- beq cr7, l1
-
- stfd f14, 0(r1) ; save F14
- stfd f15, 8(r1) ; save F15
- stfd f16, 16(r1) ; save F16
- stfd f17, 24(r1) ; save F17
- stfd f18, 32(r1) ; save F18
- stfd f19, 40(r1) ; save F19
- stfd f20, 48(r1) ; save F20
- stfd f21, 56(r1) ; save F21
- stfd f22, 64(r1) ; save F22
- stfd f23, 72(r1) ; save F23
- stfd f24, 80(r1) ; save F24
- stfd f25, 88(r1) ; save F25
- stfd f26, 96(r1) ; save F26
- stfd f27, 104(r1) ; save F27
- stfd f28, 112(r1) ; save F28
- stfd f29, 120(r1) ; save F29
- stfd f30, 128(r1) ; save F30
- stfd f31, 136(r1) ; save F31
- mffs f0 ; load FPSCR
- stfd f0, 144(r1) ; save FPSCR
-
-l1:
- ; store RSP (pointing to context-data) in R3
- stw r1, 0(r3)
+ std r0, 176(r1)
+
+ ; store RSP (pointing to context-data) in R6
+ mr r6, r1
; restore RSP (pointing to context-data) from R4
mr r1, r4
- ; test if fpu env should be preserved
- cmpwi cr7, r6, 0
- beq cr7, l2
-
- lfd f14, 0(r1) ; restore F14
- lfd f15, 8(r1) ; restore F15
- lfd f16, 16(r1) ; restore F16
- lfd f17, 24(r1) ; restore F17
- lfd f18, 32(r1) ; restore F18
- lfd f19, 40(r1) ; restore F19
- lfd f20, 48(r1) ; restore F20
- lfd f21, 56(r1) ; restore F21
- lfd f22, 64(r1) ; restore F22
- lfd f23, 72(r1) ; restore F23
- lfd f24, 80(r1) ; restore F24
- lfd f25, 88(r1) ; restore F25
- lfd f26, 96(r1) ; restore F26
- lfd f27, 104(r1) ; restore F27
- lfd f28, 112(r1) ; restore F28
- lfd f29, 120(r1) ; restore F29
- lfd f30, 128(r1) ; restore F30
- lfd f31, 136(r1) ; restore F31
- lfd f0, 144(r1) ; load FPSCR
- mtfsf 0xff, f0 ; restore FPSCR
-
-2:
- ld r13, 152(r1) ; restore R13
- ld r14, 160(r1) ; restore R14
- ld r15, 168(r1) ; restore R15
- ld r16, 176(r1) ; restore R16
- ld r17, 184(r1) ; restore R17
- ld r18, 192(r1) ; restore R18
- ld r19, 200(r1) ; restore R19
- ld r20, 208(r1) ; restore R20
- ld r21, 216(r1) ; restore R21
- ld r22, 224(r1) ; restore R22
- ld r23, 232(r1) ; restore R23
- ld r24, 240(r1) ; restore R24
- ld r25, 248(r1) ; restore R25
- ld r26, 256(r1) ; restore R26
- ld r27, 264(r1) ; restore R27
- ld r28, 272(r1) ; restore R28
- ld r29, 280(r1) ; restore R29
- ld r30, 288(r1) ; restore R30
- ld r31, 296(r1) ; restore R31
+ ld r14, 8(r1) ; restore R14
+ ld r15, 16(r1) ; restore R15
+ ld r16, 24(r1) ; restore R16
+ ld r17, 32(r1) ; restore R17
+ ld r18, 40(r1) ; restore R18
+ ld r19, 48(r1) ; restore R19
+ ld r20, 56(r1) ; restore R20
+ ld r21, 64(r1) ; restore R21
+ ld r22, 72(r1) ; restore R22
+ ld r23, 80(r1) ; restore R23
+ ld r24, 88(r1) ; restore R24
+ ld r25, 96(r1) ; restore R25
+ ld r26, 104(r1) ; restore R26
+ ld r27, 112(r1) ; restore R27
+ ld r28, 120(r1) ; restore R28
+ ld r29, 128(r1) ; restore R29
+ ld r30, 136(r1) ; restore R30
+ ld r31, 144(r1) ; restore R31
+ ld r3, 152(r1) ; restore hidden
; restore CR
- ld r0, 304(r1)
+ ld r0, 160(r1)
mtcr r0
; restore LR
- ld r0, 312(r1)
+ ld r0, 168(r1)
mtlr r0
; load PC
- ld r0, 320(r1)
+ ld r12, 176(r1)
; restore CTR
- mtctr r0
+ mtctr r12
; adjust stack
- addi r1, r1, 328
+ addi r1, r1, 184
+
+ ; zero in r3 indicates first jump to context-function
+ cmpdi r3, 0
+ beq use_entry_arg
+
+ ; return transfer_t
+ std r6, 0(r3)
+ std r5, 8(r3)
+
+ ; jump to context
+ bctr
- ; use third arg as return value after jump
- ; use third arg as first arg in context function
- mr r3, r5
+use_entry_arg:
+ ; copy transfer_t into transfer_fn arg registers
+ mr r3, r6
+ mr r4, r5
; jump to context
bctr
diff --git a/thirdparty/boost/asm/jump_ppc64_sysv_xcoff_gas.S b/thirdparty/boost/asm/jump_ppc64_sysv_xcoff_gas.S
index e00720b0a5e..a125f681b5e 100644
--- a/thirdparty/boost/asm/jump_ppc64_sysv_xcoff_gas.S
+++ b/thirdparty/boost/asm/jump_ppc64_sysv_xcoff_gas.S
@@ -1,134 +1,173 @@
-.align 2
-.globl .swoole_jump_fcontext
+
+/*
+ Copyright Oliver Kowalke 2009.
+ Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt)
+*/
+
+/*******************************************************
+ * *
+ * ------------------------------------------------- *
+ * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
+ * ------------------------------------------------- *
+ * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
+ * ------------------------------------------------- *
+ * | TOC | R14 | R15 | R16 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
+ * ------------------------------------------------- *
+ * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
+ * ------------------------------------------------- *
+ * | R17 | R18 | R19 | R20 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
+ * ------------------------------------------------- *
+ * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
+ * ------------------------------------------------- *
+ * | R21 | R22 | R23 | R24 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
+ * ------------------------------------------------- *
+ * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
+ * ------------------------------------------------- *
+ * | R25 | R26 | R27 | R28 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
+ * ------------------------------------------------- *
+ * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
+ * ------------------------------------------------- *
+ * | R29 | R30 | R31 | hidden | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
+ * ------------------------------------------------- *
+ * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
+ * ------------------------------------------------- *
+ * | CR | LR | PC | back-chain| *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
+ * ------------------------------------------------- *
+ * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
+ * ------------------------------------------------- *
+ * | cr saved | lr saved | compiler | linker | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
+ * ------------------------------------------------- *
+ * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
+ * ------------------------------------------------- *
+ * | TOC saved | FCTX | DATA | | *
+ * ------------------------------------------------- *
+ * *
+ *******************************************************/
+
+ .file "jump_ppc64_sysv_xcoff_gas.S"
+ .toc
+ .csect .text[PR], 5
+ .align 2
+ .globl swoole_jump_fcontext[DS]
+ .globl .swoole_jump_fcontext
+ .csect swoole_jump_fcontext[DS], 3
+swoole_jump_fcontext:
+ .llong .swoole_jump_fcontext[PR], TOC[tc0], 0
+ .csect .text[PR], 5
.swoole_jump_fcontext:
# reserve space on stack
- subi 1, 1, 328
-
- std 13, 152(1) # save R13
- std 14, 160(1) # save R14
- std 15, 168(1) # save R15
- std 16, 176(1) # save R16
- std 17, 184(1) # save R17
- std 18, 192(1) # save R18
- std 19, 200(1) # save R19
- std 20, 208(1) # save R20
- std 21, 216(1) # save R21
- std 22, 224(1) # save R22
- std 23, 232(1) # save R23
- std 24, 240(1) # save R24
- std 25, 248(1) # save R25
- std 26, 256(1) # save R26
- std 27, 264(1) # save R27
- std 28, 272(1) # save R28
- std 29, 280(1) # save R29
- std 30, 288(1) # save R30
- std 31, 296(1) # save R31
+ subi 1, 1, 184
+
+ std 2, 0(1) # save TOC
+ std 14, 8(1) # save R14
+ std 15, 16(1) # save R15
+ std 16, 24(1) # save R16
+ std 17, 32(1) # save R17
+ std 18, 40(1) # save R18
+ std 19, 48(1) # save R19
+ std 20, 56(1) # save R20
+ std 21, 64(1) # save R21
+ std 22, 72(1) # save R22
+ std 23, 80(1) # save R23
+ std 24, 88(1) # save R24
+ std 25, 96(1) # save R25
+ std 26, 104(1) # save R26
+ std 27, 112(1) # save R27
+ std 28, 120(1) # save R28
+ std 29, 128(1) # save R29
+ std 30, 136(1) # save R30
+ std 31, 144(1) # save R31
+ std 3, 152(1) # save hidden
# save CR
mfcr 0
- std 0, 304(1)
+ std 0, 160(1)
# save LR
mflr 0
- std 0, 312(1)
+ std 0, 168(1)
# save LR as PC
- std 0, 320(1)
-
- # test if fpu env should be preserved
- cmpwi 7, 6, 0
- beq 7, label1
-
- stfd 14, 0(1) # save F14
- stfd 15, 8(1) # save F15
- stfd 16, 16(1) # save F16
- stfd 17, 24(1) # save F17
- stfd 18, 32(1) # save F18
- stfd 19, 40(1) # save F19
- stfd 20, 48(1) # save F20
- stfd 21, 56(1) # save F21
- stfd 22, 64(1) # save F22
- stfd 23, 72(1) # save F23
- stfd 24, 80(1) # save F24
- stfd 25, 88(1) # save F25
- stfd 26, 96(1) # save F26
- stfd 27, 104(1) # save F27
- stfd 28, 112(1) # save F28
- stfd 29, 120(1) # save F29
- stfd 30, 128(1) # save F30
- stfd 31, 136(1) # save F31
- mffs 0 # load FPSCR
- stfd 0, 144(1) # save FPSCR
-
-label1:
- # store RSP (pointing to context-data) in R3
- stw 1, 0(3)
+ std 0, 176(1)
+
+ # store RSP (pointing to context-data) in R6
+ mr 6, 1
# restore RSP (pointing to context-data) from R4
mr 1, 4
- # test if fpu env should be preserved
- cmpwi 7, 6, 0
- beq 7, label2
-
- lfd 14, 0(1) # restore F14
- lfd 15, 8(1) # restore F15
- lfd 16, 16(1) # restore F16
- lfd 17, 24(1) # restore F17
- lfd 18, 32(1) # restore F18
- lfd 19, 40(1) # restore F19
- lfd 20, 48(1) # restore F20
- lfd 21, 56(1) # restore F21
- lfd 22, 64(1) # restore F22
- lfd 23, 72(1) # restore F23
- lfd 24, 80(1) # restore F24
- lfd 25, 88(1) # restore F25
- lfd 26, 96(1) # restore F26
- lfd 27, 104(1) # restore F27
- lfd 28, 112(1) # restore F28
- lfd 29, 120(1) # restore F29
- lfd 30, 128(1) # restore F30
- lfd 31, 136(1) # restore F31
- lfd 0, 144(1) # load FPSCR
- mtfsf 0xff, 0 # restore FPSCR
-
-label2:
- ld 13, 152(1) # restore R13
- ld 14, 160(1) # restore R14
- ld 15, 168(1) # restore R15
- ld 16, 176(1) # restore R16
- ld 17, 184(1) # restore R17
- ld 18, 192(1) # restore R18
- ld 19, 200(1) # restore R19
- ld 20, 208(1) # restore R20
- ld 21, 216(1) # restore R21
- ld 22, 224(1) # restore R22
- ld 23, 232(1) # restore R23
- ld 24, 240(1) # restore R24
- ld 25, 248(1) # restore R25
- ld 26, 256(1) # restore R26
- ld 27, 264(1) # restore R27
- ld 28, 272(1) # restore R28
- ld 29, 280(1) # restore R29
- ld 30, 288(1) # restore R30
- ld 31, 296(1) # restore R31
+ ld 2, 0(1) # restore TOC
+ ld 14, 8(1) # restore R14
+ ld 15, 16(1) # restore R15
+ ld 16, 24(1) # restore R16
+ ld 17, 32(1) # restore R17
+ ld 18, 40(1) # restore R18
+ ld 19, 48(1) # restore R19
+ ld 20, 56(1) # restore R20
+ ld 21, 64(1) # restore R21
+ ld 22, 72(1) # restore R22
+ ld 23, 80(1) # restore R23
+ ld 24, 88(1) # restore R24
+ ld 25, 96(1) # restore R25
+ ld 26, 104(1) # restore R26
+ ld 27, 112(1) # restore R27
+ ld 28, 120(1) # restore R28
+ ld 29, 128(1) # restore R29
+ ld 30, 136(1) # restore R30
+ ld 31, 144(1) # restore R31
+ ld 3, 152(1) # restore hidden
# restore CR
- ld 0, 304(1)
+ ld 0, 160(1)
mtcr 0
# restore LR
- ld 0, 312(1)
+ ld 0, 168(1)
mtlr 0
# load PC
- ld 0, 320(1)
+ ld 0, 176(1)
# restore CTR
mtctr 0
# adjust stack
- addi 1, 1, 328
+ addi 1, 1, 184
+
+ # zero in r3 indicates first jump to context-function
+ cmpdi 3, 0
+ beq use_entry_arg
+
+ # return transfer_t
+ std 6, 0(3)
+ std 5, 8(3)
+
+ # jump to context
+ bctr
- # use third arg as return value after jump
- # use third arg as first arg in context function
- mr 3, 5
+use_entry_arg:
+ # copy transfer_t into transfer_fn arg registers
+ mr 3, 6
+ mr 4, 5
# jump to context
bctr
diff --git a/thirdparty/boost/asm/jump_riscv64_sysv_elf_gas.S b/thirdparty/boost/asm/jump_riscv64_sysv_elf_gas.S
index 23f66d60b2a..a2f9a2f3bb3 100644
--- a/thirdparty/boost/asm/jump_riscv64_sysv_elf_gas.S
+++ b/thirdparty/boost/asm/jump_riscv64_sysv_elf_gas.S
@@ -66,8 +66,6 @@ swoole_jump_fcontext:
# prepare stack for GP + FPU
addi sp, sp, -0xd0
- beqz a3, .L1
-
# save fs0 - fs11
fsd fs0, 0x00(sp)
fsd fs1, 0x08(sp)
@@ -81,7 +79,6 @@ swoole_jump_fcontext:
fsd fs9, 0x48(sp)
fsd fs10, 0x50(sp)
fsd fs11, 0x58(sp)
-.L1:
# save s0-s11, ra
sd s0, 0x60(sp)
@@ -101,13 +98,12 @@ swoole_jump_fcontext:
# save RA as PC
sd ra, 0xc8(sp)
- # store SP (pointing to context-data) in A0
- sd sp, (a0)
+ # store SP (pointing to context-data) in A2
+ mv a2, sp
- # restore SP (pointing to context-data) from A1
- mv sp, a1
+ # restore SP (pointing to context-data) from A0
+ mv sp, a0
- beqz a3, .L2
# load fs0 - fs11
fld fs0, 0x00(sp)
fld fs1, 0x08(sp)
@@ -121,7 +117,6 @@ swoole_jump_fcontext:
fld fs9, 0x48(sp)
fld fs10, 0x50(sp)
fld fs11, 0x58(sp)
-.L2:
# load s0-s11,ra
ld s0, 0x60(sp)
@@ -138,7 +133,9 @@ swoole_jump_fcontext:
ld s11, 0xb8(sp)
ld ra, 0xc0(sp)
- # use A2 as return value
+ # return transfer_t from jump
+ # pass transfer_t as first arg in context function
+ # a0 == FCTX, a1 == DATA
mv a0, a2
# load pc
diff --git a/thirdparty/boost/asm/jump_x86_64_sysv_elf_gas.S b/thirdparty/boost/asm/jump_x86_64_sysv_elf_gas.S
index 64193d5a5fd..7b80132b67e 100644
--- a/thirdparty/boost/asm/jump_x86_64_sysv_elf_gas.S
+++ b/thirdparty/boost/asm/jump_x86_64_sysv_elf_gas.S
@@ -12,95 +12,131 @@
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
- * | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | *
+ * | fc_mxcsr|fc_x87_cw| guard | R12 | R13 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
- * | R15 | RBX | RBP | RIP | *
+ * | R14 | R15 | RBX | RBP | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
- * | 16 | 17 | | *
+ * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ---------------------------------------------------------------------------------- *
* | 0x40 | 0x44 | | *
* ---------------------------------------------------------------------------------- *
- * | EXIT | | *
+ * | RIP | | *
* ---------------------------------------------------------------------------------- *
* *
****************************************************************************************/
-#ifdef __CET__
-#include
-#else
-#define _CET_ENDBR
-#endif
+# if defined __CET__
+# include
+# define SWOOLE_SHSTK_ENABLED (__CET__ & 0x2)
+# define SWOOLE_CONTEXT_SHADOW_STACK (SWOOLE_SHSTK_ENABLED && SHADOW_STACK_SYSCALL)
+# else
+# define _CET_ENDBR
+# endif
+.file "jump_x86_64_sysv_elf_gas.S"
.text
.globl swoole_jump_fcontext
.type swoole_jump_fcontext,@function
.align 16
swoole_jump_fcontext:
_CET_ENDBR
- pushq %rbp /* save RBP */
- pushq %rbx /* save RBX */
- pushq %r15 /* save R15 */
- pushq %r14 /* save R14 */
- pushq %r13 /* save R13 */
- pushq %r12 /* save R12 */
-
- /* prepare stack for FPU */
- leaq -0x8(%rsp), %rsp
+ leaq -0x40(%rsp), %rsp /* prepare stack */
- /* test for flag preserve_fpu */
- cmp $0, %rcx
- je 1f
+#if !defined(SWOOLE_USE_TSX)
+ stmxcsr (%rsp) /* save MMX control- and status-word */
+ fnstcw 0x4(%rsp) /* save x87 control-word */
+#endif
- /* save MMX control- and status-word */
- stmxcsr (%rsp)
- /* save x87 control-word */
- fnstcw 0x4(%rsp)
+#if defined(SWOOLE_CONTEXT_TLS_STACK_PROTECTOR)
+ movq %fs:0x28, %rcx /* read stack guard from TLS record */
+ movq %rcx, 0x8(%rsp) /* save stack guard */
+#endif
-1:
- /* store RSP (pointing to context-data) in RDI */
- movq %rsp, (%rdi)
+ movq %r12, 0x10(%rsp) /* save R12 */
+ movq %r13, 0x18(%rsp) /* save R13 */
+ movq %r14, 0x20(%rsp) /* save R14 */
+ movq %r15, 0x28(%rsp) /* save R15 */
+ movq %rbx, 0x30(%rsp) /* save RBX */
+ movq %rbp, 0x38(%rsp) /* save RBP */
- /* restore RSP (pointing to context-data) from RSI */
- movq %rsi, %rsp
+#if SWOOLE_CONTEXT_SHADOW_STACK
+ /* grow the stack to reserve space for shadow stack pointer(SSP) */
+ leaq -0x8(%rsp), %rsp
+ /* read the current SSP and store it */
+ rdsspq %rcx
+ movq %rcx, (%rsp)
+#endif
- /* test for flag preserve_fpu */
- cmp $0, %rcx
- je 2f
+ /* store RSP (pointing to context-data) in RAX */
+ movq %rsp, %rax
- /* restore MMX control- and status-word */
- ldmxcsr (%rsp)
- /* restore x87 control-word */
- fldcw 0x4(%rsp)
+ /* restore RSP (pointing to context-data) from RDI */
+ movq %rdi, %rsp
-2:
- /* prepare stack for FPU */
+#if SWOOLE_CONTEXT_SHADOW_STACK
+ /* first 8 bytes are SSP */
+ movq (%rsp), %rcx
leaq 0x8(%rsp), %rsp
- popq %r12 /* restrore R12 */
- popq %r13 /* restrore R13 */
- popq %r14 /* restrore R14 */
- popq %r15 /* restrore R15 */
- popq %rbx /* restrore RBX */
- popq %rbp /* restrore RBP */
+ /* Restore target(new) shadow stack */
+ rstorssp -8(%rcx)
+ /* restore token for previous shadow stack is pushed */
+ /* on previous shadow stack after saveprevssp */
+ saveprevssp
+
+ /* when return, swoole_jump_fcontext jump to restored return address */
+ /* (r8) instead of RET. This miss of RET implies us to unwind */
+ /* shadow stack accordingly. Otherwise mismatch occur */
+ movq $1, %rcx
+ incsspq %rcx
+#endif
+
+ movq 0x40(%rsp), %r8 /* restore return-address */
- /* restore return-address */
- popq %r8
+#if !defined(SWOOLE_USE_TSX)
+ ldmxcsr (%rsp) /* restore MMX control- and status-word */
+ fldcw 0x4(%rsp) /* restore x87 control-word */
+#endif
+
+#if defined(SWOOLE_CONTEXT_TLS_STACK_PROTECTOR)
+ movq 0x8(%rsp), %rdx /* load stack guard */
+ movq %rdx, %fs:0x28 /* restore stack guard to TLS record */
+#endif
+
+ movq 0x10(%rsp), %r12 /* restore R12 */
+ movq 0x18(%rsp), %r13 /* restore R13 */
+ movq 0x20(%rsp), %r14 /* restore R14 */
+ movq 0x28(%rsp), %r15 /* restore R15 */
+ movq 0x30(%rsp), %rbx /* restore RBX */
+ movq 0x38(%rsp), %rbp /* restore RBP */
+
+ leaq 0x48(%rsp), %rsp /* prepare stack */
- /* use third arg as return-value after jump */
- movq %rdx, %rax
- /* use third arg as first arg in context function */
- movq %rdx, %rdi
+ /* return transfer_t from jump */
+#if !defined(_ILP32)
+ /* RAX == fctx, RDX == data */
+ movq %rsi, %rdx
+#else
+ /* RAX == data:fctx */
+ salq $32, %rsi
+ orq %rsi, %rax
+#endif
+ /* pass transfer_t as first arg in context function */
+#if !defined(_ILP32)
+ /* RDI == fctx, RSI == data */
+#else
+ /* RDI == data:fctx */
+#endif
+ movq %rax, %rdi
/* indirect jump to context */
jmp *%r8
.size swoole_jump_fcontext,.-swoole_jump_fcontext
-#ifndef __NetBSD__
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-#endif
diff --git a/thirdparty/boost/asm/jump_x86_64_sysv_macho_gas.S b/thirdparty/boost/asm/jump_x86_64_sysv_macho_gas.S
index 1515a6e7f9f..0bf18bd763f 100644
--- a/thirdparty/boost/asm/jump_x86_64_sysv_macho_gas.S
+++ b/thirdparty/boost/asm/jump_x86_64_sysv_macho_gas.S
@@ -21,13 +21,6 @@
* ---------------------------------------------------------------------------------- *
* | R15 | RBX | RBP | RIP | *
* ---------------------------------------------------------------------------------- *
- * ---------------------------------------------------------------------------------- *
- * | 16 | 17 | | *
- * ---------------------------------------------------------------------------------- *
- * | 0x40 | 0x44 | | *
- * ---------------------------------------------------------------------------------- *
- * | EXIT | | *
- * ---------------------------------------------------------------------------------- *
* *
****************************************************************************************/
@@ -35,59 +28,48 @@
.globl _swoole_jump_fcontext
.align 8
_swoole_jump_fcontext:
- pushq %rbp /* save RBP */
- pushq %rbx /* save RBX */
- pushq %r15 /* save R15 */
- pushq %r14 /* save R14 */
- pushq %r13 /* save R13 */
- pushq %r12 /* save R12 */
-
- /* prepare stack for FPU */
- leaq -0x8(%rsp), %rsp
-
- /* test for flag preserve_fpu */
- cmp $0, %rcx
- je 1f
+ leaq -0x38(%rsp), %rsp /* prepare stack */
- /* save MMX control- and status-word */
- stmxcsr (%rsp)
- /* save x87 control-word */
- fnstcw 0x4(%rsp)
+#if !defined(SWOOLE_USE_TSX)
+ stmxcsr (%rsp) /* save MMX control- and status-word */
+ fnstcw 0x4(%rsp) /* save x87 control-word */
+#endif
-1:
- /* store RSP (pointing to context-data) in RDI */
- movq %rsp, (%rdi)
+ movq %r12, 0x8(%rsp) /* save R12 */
+ movq %r13, 0x10(%rsp) /* save R13 */
+ movq %r14, 0x18(%rsp) /* save R14 */
+ movq %r15, 0x20(%rsp) /* save R15 */
+ movq %rbx, 0x28(%rsp) /* save RBX */
+ movq %rbp, 0x30(%rsp) /* save RBP */
- /* restore RSP (pointing to context-data) from RSI */
- movq %rsi, %rsp
+ /* store RSP (pointing to context-data) in RAX */
+ movq %rsp, %rax
- /* test for flag preserve_fpu */
- cmp $0, %rcx
- je 2f
+ /* restore RSP (pointing to context-data) from RDI */
+ movq %rdi, %rsp
- /* restore MMX control- and status-word */
- ldmxcsr (%rsp)
- /* restore x87 control-word */
- fldcw 0x4(%rsp)
+ movq 0x38(%rsp), %r8 /* restore return-address */
-2:
- /* prepare stack for FPU */
- leaq 0x8(%rsp), %rsp
+#if !defined(SWOOLE_USE_TSX)
+ ldmxcsr (%rsp) /* restore MMX control- and status-word */
+ fldcw 0x4(%rsp) /* restore x87 control-word */
+#endif
- popq %r12 /* restrore R12 */
- popq %r13 /* restrore R13 */
- popq %r14 /* restrore R14 */
- popq %r15 /* restrore R15 */
- popq %rbx /* restrore RBX */
- popq %rbp /* restrore RBP */
+ movq 0x8(%rsp), %r12 /* restore R12 */
+ movq 0x10(%rsp), %r13 /* restore R13 */
+ movq 0x18(%rsp), %r14 /* restore R14 */
+ movq 0x20(%rsp), %r15 /* restore R15 */
+ movq 0x28(%rsp), %rbx /* restore RBX */
+ movq 0x30(%rsp), %rbp /* restore RBP */
- /* restore return-address */
- popq %r8
+ leaq 0x40(%rsp), %rsp /* prepare stack */
- /* use third arg as return-value after jump */
- movq %rdx, %rax
- /* use third arg as first arg in context function */
- movq %rdx, %rdi
+ /* return transfer_t from jump */
+ /* RAX == fctx, RDX == data */
+ movq %rsi, %rdx
+ /* pass transfer_t as first arg in context function */
+ /* RDI == fctx, RSI == data */
+ movq %rax, %rdi
/* indirect jump to context */
jmp *%r8
diff --git a/thirdparty/boost/asm/make_arm64_aapcs_elf_gas.S b/thirdparty/boost/asm/make_arm64_aapcs_elf_gas.S
index 1fc23f4e369..fd98d15984d 100644
--- a/thirdparty/boost/asm/make_arm64_aapcs_elf_gas.S
+++ b/thirdparty/boost/asm/make_arm64_aapcs_elf_gas.S
@@ -1,5 +1,5 @@
/*
- Copyright Edward Nevill 2015
+ Copyright Edward Nevill + Oliver Kowalke 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
@@ -51,7 +51,7 @@
* *
*******************************************************/
-.cpu generic+fp+simd
+.file "make_arm64_aapcs_elf_gas.S"
.text
.align 2
.global swoole_make_fcontext
@@ -81,7 +81,5 @@ finish:
bl _exit
.size swoole_make_fcontext,.-swoole_make_fcontext
-#ifndef __NetBSD__
# Mark that we don't need executable stack.
.section .note.GNU-stack,"",%progbits
-#endif
diff --git a/thirdparty/boost/asm/make_arm64_aapcs_macho_gas.S b/thirdparty/boost/asm/make_arm64_aapcs_macho_gas.S
index 556cc15e519..7977c0ee9bd 100644
--- a/thirdparty/boost/asm/make_arm64_aapcs_macho_gas.S
+++ b/thirdparty/boost/asm/make_arm64_aapcs_macho_gas.S
@@ -1,3 +1,9 @@
+/*
+ Copyright Edward Nevill + Oliver Kowalke 2015
+ Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt)
+*/
/*******************************************************
* *
* ------------------------------------------------- *
@@ -45,7 +51,6 @@
* *
*******************************************************/
-
.text
.globl _swoole_make_fcontext
.balign 16
@@ -61,9 +66,6 @@ _swoole_make_fcontext:
; store address as a PC to jump in
str x2, [x0, #0xa0]
- ; compute abs address of label finish
- ; 0x0c = 3 instructions * size (4) before label 'finish'
-
adr x1, finish
; save address of finish as return-address for context-function
diff --git a/thirdparty/boost/asm/make_loongarch64_sysv_elf_gas.S b/thirdparty/boost/asm/make_loongarch64_sysv_elf_gas.S
new file mode 100644
index 00000000000..5359e0235e1
--- /dev/null
+++ b/thirdparty/boost/asm/make_loongarch64_sysv_elf_gas.S
@@ -0,0 +1,72 @@
+/*******************************************************
+ * *
+ * ------------------------------------------------- *
+ * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
+ * ------------------------------------------------- *
+ * | 0 | 8 | 16 | 24 | *
+ * ------------------------------------------------- *
+ * | FS0 | FS1 | FS2 | FS3 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
+ * ------------------------------------------------- *
+ * | 32 | 40 | 48 | 56 | *
+ * ------------------------------------------------- *
+ * | FS4 | FS5 | FS6 | FS7 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
+ * ------------------------------------------------- *
+ * | 64 | 72 | 80 | 88 | *
+ * ------------------------------------------------- *
+ * | S0 | S1 | S2 | S3 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
+ * ------------------------------------------------- *
+ * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
+ * ------------------------------------------------- *
+ * | S4 | S5 | S6 | S7 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
+ * ------------------------------------------------- *
+ * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
+ * ------------------------------------------------- *
+ * | S8 | FP | RA | PC | *
+ * ------------------------------------------------- *
+ * *
+ * *****************************************************/
+
+.file "make_loongarch64_sysv_elf_gas.S"
+.text
+.globl swoole_make_fcontext
+.align 2
+.type swoole_make_fcontext,@function
+swoole_make_fcontext:
+ # shift address in A0 to lower 16 byte boundary
+ bstrins.d $a0, $zero, 3, 0
+
+ # reserve space for context-data on context-stack
+ addi.d $a0, $a0, -160
+
+ # third arg of swoole_make_fcontext() == address of context-function
+ st.d $a2, $a0, 152
+
+ # save address of finish as return-address for context-function
+ # will be entered after context-function returns
+ la.local $a4, finish
+ st.d $a4, $a0, 144
+
+ # return pointer to context-data
+ jr $ra
+
+finish:
+ # exit code is zero
+ li.d $a0, 0
+ # call _exit(0)
+ b %plt(_exit)
+
+.size swoole_make_fcontext, .-swoole_make_fcontext
+/* Mark that we don't need executable stack. */
+.section .note.GNU-stack,"",%progbits
diff --git a/thirdparty/boost/asm/make_mips64_n64_elf_gas.S b/thirdparty/boost/asm/make_mips64_n64_elf_gas.S
index 888ddc26ca3..d3d46313b6b 100644
--- a/thirdparty/boost/asm/make_mips64_n64_elf_gas.S
+++ b/thirdparty/boost/asm/make_mips64_n64_elf_gas.S
@@ -45,6 +45,7 @@
* *
* *****************************************************/
+.file "make_mips64_n64_elf_gas.S"
.text
.globl swoole_make_fcontext
.align 3
diff --git a/thirdparty/boost/asm/make_ppc64_sysv_elf_gas.S b/thirdparty/boost/asm/make_ppc64_sysv_elf_gas.S
index 71af0db1a52..59354f8dde5 100644
--- a/thirdparty/boost/asm/make_ppc64_sysv_elf_gas.S
+++ b/thirdparty/boost/asm/make_ppc64_sysv_elf_gas.S
@@ -12,82 +12,61 @@
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
- * | F14 | F15 | F16 | F17 | *
+ * | TOC | R14 | R15 | R16 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
- * | F18 | F19 | F20 | F21 | *
+ * | R17 | R18 | R19 | R20 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
- * | F22 | F23 | F24 | F25 | *
+ * | R21 | R22 | R23 | R24 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
- * | F26 | F27 | F28 | F29 | *
+ * | R25 | R26 | R27 | R28 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
- * | F30 | F31 | fpscr | TOC | *
+ * | R29 | R30 | R31 | hidden | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
- * | R14 | R15 | R16 | R17 | *
+ * | CR | LR | PC | back-chain| *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
* ------------------------------------------------- *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
- * | R18 | R19 | R20 | R21 | *
+ * | cr saved | lr saved | compiler | linker | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
* ------------------------------------------------- *
* | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
* ------------------------------------------------- *
- * | R22 | R23 | R24 | R25 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | *
- * ------------------------------------------------- *
- * | 256 | 260 | 264 | 268 | 272 | 276 | 280 | 284 | *
- * ------------------------------------------------- *
- * | R26 | R27 | R28 | R29 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | *
- * ------------------------------------------------- *
- * | 288 | 292 | 296 | 300 | 304 | 308 | 312 | 316 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | R30 | R31 | CR | LR | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 80 | 81 | | *
- * ------------------------------------------------- *
- * | 320 | 324 | | *
- * ------------------------------------------------- *
- * | PC | | *
+ * | TOC saved | FCTX | DATA | | *
* ------------------------------------------------- *
* *
*******************************************************/
+.file "make_ppc64_sysv_elf_gas.S"
.globl swoole_make_fcontext
#if _CALL_ELF == 2
.text
@@ -126,20 +105,29 @@ swoole_make_fcontext:
# reserve space for context-data on context-stack
# including 64 byte of linkage + parameter area (R1 % 16 == 0)
- subi %r3, %r3, 392
+ subi %r3, %r3, 248
# third arg of swoole_make_fcontext() == address of context-function
# entry point (ELFv2) or descriptor (ELFv1)
#if _CALL_ELF == 2
# save address of context-function entry point
- std %r5, 320(%r3)
+ std %r5, 176(%r3)
#else
# save address of context-function entry point
ld %r4, 0(%r5)
- std %r4, 320(%r3)
+ std %r4, 176(%r3)
# save TOC of context-function
ld %r4, 8(%r5)
- std %r4, 152(%r3)
+ std %r4, 0(%r3)
+#endif
+
+ # set back-chain to zero
+ li %r0, 0
+ std %r0, 184(%r3)
+
+#if _CALL_ELF != 2
+ # zero in r3 indicates first jump to context-function
+ std %r0, 152(%r3)
#endif
# load LR
@@ -155,7 +143,7 @@ swoole_make_fcontext:
mtlr %r0
# save address of finish as return-address for context-function
# will be entered after context-function returns
- std %r4, 312(%r3)
+ std %r4, 168(%r3)
# restore return address from R6
mtlr %r6
@@ -185,7 +173,5 @@ finish:
# endif
#endif
-#ifndef __NetBSD__
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-#endif
diff --git a/thirdparty/boost/asm/make_ppc64_sysv_macho_gas.S b/thirdparty/boost/asm/make_ppc64_sysv_macho_gas.S
index d656cab6554..717f3bb2cf2 100644
--- a/thirdparty/boost/asm/make_ppc64_sysv_macho_gas.S
+++ b/thirdparty/boost/asm/make_ppc64_sysv_macho_gas.S
@@ -12,78 +12,56 @@
* ------------------------------------------------- *
* | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
* ------------------------------------------------- *
- * | F14 | F15 | F16 | F17 | *
+ * | R13 | R14 | R15 | R16 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ------------------------------------------------- *
* | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
* ------------------------------------------------- *
- * | F18 | F19 | F20 | F21 | *
+ * | R17 | R18 | R19 | R20 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ------------------------------------------------- *
* | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
* ------------------------------------------------- *
- * | F22 | F23 | F24 | F25 | *
+ * | R21 | R22 | R23 | R24 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
* ------------------------------------------------- *
* | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
* ------------------------------------------------- *
- * | F26 | F27 | F28 | F29 | *
+ * | R25 | R26 | R27 | R28 | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
* ------------------------------------------------- *
* | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
* ------------------------------------------------- *
- * | F30 | F31 | fpscr | R13 | *
+ * | R29 | R30 | R31 | hidden | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
* ------------------------------------------------- *
* | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
* ------------------------------------------------- *
- * | R14 | R15 | R16 | R17 | *
+ * | CR | LR | PC | back-chain| *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
* ------------------------------------------------- *
* | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
* ------------------------------------------------- *
- * | R18 | R19 | R20 | R21 | *
+ * | cr saved | lr saved | compiler | linker | *
* ------------------------------------------------- *
* ------------------------------------------------- *
* | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
* ------------------------------------------------- *
* | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
* ------------------------------------------------- *
- * | R22 | R23 | R24 | R25 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | *
- * ------------------------------------------------- *
- * | 256 | 260 | 264 | 268 | 272 | 276 | 280 | 284 | *
- * ------------------------------------------------- *
- * | R26 | R27 | R28 | R29 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | *
- * ------------------------------------------------- *
- * | 288 | 292 | 296 | 300 | 304 | 308 | 312 | 316 | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | R30 | R31 | CR | LR | *
- * ------------------------------------------------- *
- * ------------------------------------------------- *
- * | 80 | 81 | | *
- * ------------------------------------------------- *
- * | 320 | 324 | | *
- * ------------------------------------------------- *
- * | PC | | *
+ * | FCTX | DATA | | | *
* ------------------------------------------------- *
* *
*******************************************************/
@@ -100,10 +78,19 @@ _swoole_make_fcontext:
; reserve space for context-data on context-stack
; including 64 byte of linkage + parameter area (R1 16 == 0)
- subi r3, r3, 392
+ subi r3, r3, 240
; third arg of swoole_make_fcontext() == address of context-function
- stw r5, 320(r3)
+ stw r5, 176(r3)
+
+ ; set back-chain to zero
+ li r0, 0
+ std r0, 184(r3)
+
+ ; compute address of returned transfer_t
+ addi r0, r3, 224
+ mr r4, r0
+ std r4, 152(r3)
; load LR
mflr r0
@@ -118,7 +105,7 @@ l1:
mtlr r0
; save address of finish as return-address for context-function
; will be entered after context-function returns
- std r4, 312(r3)
+ std r4, 168(r3)
; restore return address from R6
mtlr r6
diff --git a/thirdparty/boost/asm/make_ppc64_sysv_xcoff_gas.S b/thirdparty/boost/asm/make_ppc64_sysv_xcoff_gas.S
index b9dfb189767..58fd12eb916 100644
--- a/thirdparty/boost/asm/make_ppc64_sysv_xcoff_gas.S
+++ b/thirdparty/boost/asm/make_ppc64_sysv_xcoff_gas.S
@@ -1,22 +1,106 @@
- .globl swoole_make_fcontext[DS]
- .globl .swoole_make_fcontext[PR]
- .align 2
- .csect .swoole_make_fcontext[PR], 3
- .globl _swoole_make_fcontext
-#._swoole_make_fcontext:
+/*
+ Copyright Oliver Kowalke 2009.
+ Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt)
+*/
+
+/*******************************************************
+ * *
+ * ------------------------------------------------- *
+ * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | *
+ * ------------------------------------------------- *
+ * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | *
+ * ------------------------------------------------- *
+ * | TOC | R14 | R15 | R16 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
+ * ------------------------------------------------- *
+ * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | *
+ * ------------------------------------------------- *
+ * | R17 | R18 | R19 | R20 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
+ * ------------------------------------------------- *
+ * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | *
+ * ------------------------------------------------- *
+ * | R21 | R22 | R23 | R24 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | *
+ * ------------------------------------------------- *
+ * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | *
+ * ------------------------------------------------- *
+ * | R25 | R26 | R27 | R28 | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | *
+ * ------------------------------------------------- *
+ * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | *
+ * ------------------------------------------------- *
+ * | R29 | R30 | R31 | hidden | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | *
+ * ------------------------------------------------- *
+ * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | *
+ * ------------------------------------------------- *
+ * | CR | LR | PC | back-chain| *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | *
+ * ------------------------------------------------- *
+ * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | *
+ * ------------------------------------------------- *
+ * | cr saved | lr saved | compiler | linker | *
+ * ------------------------------------------------- *
+ * ------------------------------------------------- *
+ * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | *
+ * ------------------------------------------------- *
+ * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | *
+ * ------------------------------------------------- *
+ * | TOC saved | FCTX | DATA | | *
+ * ------------------------------------------------- *
+ * *
+ *******************************************************/
+
+ .file "make_ppc64_sysv_xcoff_gas.S"
+ .toc
+ .csect .text[PR], 5
+ .align 2
+ .globl swoole_make_fcontext[DS]
+ .globl .swoole_make_fcontext
+ .csect swoole_make_fcontext[DS], 3
+swoole_make_fcontext:
+ .llong .swoole_make_fcontext[PR], TOC[tc0], 0
+ .csect .text[PR], 5
+.swoole_make_fcontext:
# save return address into R6
mflr 6
# first arg of swoole_make_fcontext() == top address of context-function
# shift address in R3 to lower 16 byte boundary
- clrrwi 3, 3, 4
+ clrrdi 3, 3, 4
# reserve space for context-data on context-stack
# including 64 byte of linkage + parameter area (R1 % 16 == 0)
- subi 3, 3, 392
+ subi 3, 3, 248
+
+ # third arg of swoole_make_fcontext() == address of context-function descriptor
+ ld 4, 0(5)
+ std 4, 176(3)
+ # save TOC of context-function
+ ld 4, 8(5)
+ std 4, 0(3)
+
+ # set back-chain to zero
+ li 0, 0
+ std 0, 184(3)
- # third arg of swoole_make_fcontext() == address of context-function
- stw 5, 320(3)
+ # zero in r3 indicates first jump to context-function
+ std 0, 152(3)
# load LR
mflr 0
@@ -31,7 +115,7 @@
mtlr 0
# save address of finish as return-address for context-function
# will be entered after context-function returns
- stw 4, 312(3)
+ std 4, 168(3)
# restore return address from R6
mtlr 6
@@ -42,9 +126,9 @@
# save return address into R0
mflr 0
# save return address on stack, set up stack frame
- stw 0, 8(1)
+ std 0, 8(1)
# allocate stack space, R1 % 16 == 0
- stwu 1, -32(1)
+ stdu 1, -32(1)
# exit code is zero
li 3, 0
diff --git a/thirdparty/boost/asm/make_x86_64_sysv_elf_gas.S b/thirdparty/boost/asm/make_x86_64_sysv_elf_gas.S
index 34ce3b26f4e..00674735f38 100644
--- a/thirdparty/boost/asm/make_x86_64_sysv_elf_gas.S
+++ b/thirdparty/boost/asm/make_x86_64_sysv_elf_gas.S
@@ -12,36 +12,44 @@
* ---------------------------------------------------------------------------------- *
* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | *
* ---------------------------------------------------------------------------------- *
- * | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | *
+ * | fc_mxcsr|fc_x87_cw| guard | R12 | R13 | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | *
* ---------------------------------------------------------------------------------- *
* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | *
* ---------------------------------------------------------------------------------- *
- * | R15 | RBX | RBP | RIP | *
+ * | R14 | R15 | RBX | RBP | *
* ---------------------------------------------------------------------------------- *
* ---------------------------------------------------------------------------------- *
- * | 16 | 17 | | *
+ * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | *
* ---------------------------------------------------------------------------------- *
* | 0x40 | 0x44 | | *
* ---------------------------------------------------------------------------------- *
- * | EXIT | | *
+ * | RIP | | *
* ---------------------------------------------------------------------------------- *
* *
****************************************************************************************/
-#ifdef __CET__
-#include
-#else
-#define _CET_ENDBR
-#endif
+# if defined __CET__
+# include
+# define SWOOLE_SHSTK_ENABLED (__CET__ & 0x2)
+# define SWOOLE_CONTEXT_SHADOW_STACK (SWOOLE_SHSTK_ENABLED && SHADOW_STACK_SYSCALL)
+# else
+# define _CET_ENDBR
+# endif
+.file "make_x86_64_sysv_elf_gas.S"
.text
.globl swoole_make_fcontext
.type swoole_make_fcontext,@function
.align 16
swoole_make_fcontext:
_CET_ENDBR
+#if SWOOLE_CONTEXT_SHADOW_STACK
+ /* the new shadow stack pointer (SSP) */
+ movq -0x8(%rdi), %r9
+#endif
+
/* first arg of swoole_make_fcontext() == top of context-stack */
movq %rdi, %rax
@@ -49,26 +57,83 @@ swoole_make_fcontext:
andq $-16, %rax
/* reserve space for context-data on context-stack */
- /* size for fc_mxcsr .. RIP + return-address for context-function */
/* on context-function entry: (RSP -0x8) % 16 == 0 */
leaq -0x48(%rax), %rax
/* third arg of swoole_make_fcontext() == address of context-function */
- movq %rdx, 0x38(%rax)
+ /* stored in RBX */
+ movq %rdx, 0x30(%rax)
/* save MMX control- and status-word */
stmxcsr (%rax)
/* save x87 control-word */
fnstcw 0x4(%rax)
+#if defined(SWOOLE_CONTEXT_TLS_STACK_PROTECTOR)
+ /* save stack guard */
+ movq %fs:0x28, %rcx /* read stack guard from TLS record */
+ movq %rcx, 0x8(%rsp) /* save stack guard */
+#endif
+
+ /* compute abs address of label trampoline */
+ leaq trampoline(%rip), %rcx
+ /* save address of trampoline as return-address for context-function */
+ /* will be entered after calling jump_fcontext() first time */
+ movq %rcx, 0x40(%rax)
+
/* compute abs address of label finish */
leaq finish(%rip), %rcx
/* save address of finish as return-address for context-function */
/* will be entered after context-function returns */
- movq %rcx, 0x40(%rax)
+ movq %rcx, 0x38(%rax)
+
+#if SWOOLE_CONTEXT_SHADOW_STACK
+ /* Populate the shadow stack and normal stack */
+ /* get original SSP */
+ rdsspq %r8
+ /* restore new shadow stack */
+ rstorssp -0x8(%r9)
+ /* save the restore token on the original shadow stack */
+ saveprevssp
+ /* push the address of "jmp trampoline" to the new shadow stack */
+ /* as well as the stack */
+ call 1f
+ jmp trampoline
+1:
+ /* save address of "jmp trampoline" as return-address */
+ /* for context-function */
+ pop 0x38(%rax)
+ /* Get the new SSP. */
+ rdsspq %r9
+ /* restore original shadow stack */
+ rstorssp -0x8(%r8)
+ /* save the restore token on the new shadow stack. */
+ saveprevssp
+
+ /* reserve space for the new SSP */
+ leaq -0x8(%rax), %rax
+ /* save the new SSP to this fcontext */
+ movq %r9, (%rax)
+#endif
ret /* return pointer to context-data */
+trampoline:
+ _CET_ENDBR
+ /* store return address on stack */
+ /* fix stack alignment */
+#if SWOOLE_CONTEXT_SHADOW_STACK
+ /* save address of "jmp *%rbp" as return-address */
+ /* on stack and shadow stack */
+ call 2f
+ jmp *%rbp
+2:
+#else
+ push %rbp
+#endif
+ /* jump to context-function */
+ jmp *%rbx
+
finish:
_CET_ENDBR
/* exit code is zero */
@@ -78,7 +143,5 @@ finish:
hlt
.size swoole_make_fcontext,.-swoole_make_fcontext
-#ifndef __NetBSD__
/* Mark that we don't need executable stack. */
.section .note.GNU-stack,"",%progbits
-#endif
diff --git a/thirdparty/boost/asm/make_x86_64_sysv_macho_gas.S b/thirdparty/boost/asm/make_x86_64_sysv_macho_gas.S
index 79995c8833b..46f8bd15cc4 100644
--- a/thirdparty/boost/asm/make_x86_64_sysv_macho_gas.S
+++ b/thirdparty/boost/asm/make_x86_64_sysv_macho_gas.S
@@ -21,13 +21,6 @@
* ---------------------------------------------------------------------------------- *
* | R15 | RBX | RBP | RIP | *
* ---------------------------------------------------------------------------------- *
- * ---------------------------------------------------------------------------------- *
- * | 16 | 17 | | *
- * ---------------------------------------------------------------------------------- *
- * | 0x40 | 0x44 | | *
- * ---------------------------------------------------------------------------------- *
- * | EXIT | | *
- * ---------------------------------------------------------------------------------- *
* *
****************************************************************************************/
@@ -39,30 +32,42 @@ _swoole_make_fcontext:
movq %rdi, %rax
/* shift address in RAX to lower 16 byte boundary */
- movabs $-16, %r8
- andq %r8, %rax
+ andq $-16, %rax
/* reserve space for context-data on context-stack */
- /* size for fc_mxcsr .. RIP + return-address for context-function */
/* on context-function entry: (RSP -0x8) % 16 == 0 */
- leaq -0x48(%rax), %rax
+ leaq -0x40(%rax), %rax
/* third arg of swoole_make_fcontext() == address of context-function */
- movq %rdx, 0x38(%rax)
+ /* stored in RBX */
+ movq %rdx, 0x28(%rax)
/* save MMX control- and status-word */
stmxcsr (%rax)
/* save x87 control-word */
fnstcw 0x4(%rax)
+ /* compute abs address of label trampoline */
+ leaq trampoline(%rip), %rcx
+ /* save address of trampoline as return-address for context-function */
+ /* will be entered after calling jump_fcontext() first time */
+ movq %rcx, 0x38(%rax)
+
/* compute abs address of label finish */
leaq finish(%rip), %rcx
/* save address of finish as return-address for context-function */
/* will be entered after context-function returns */
- movq %rcx, 0x40(%rax)
+ movq %rcx, 0x30(%rax)
ret /* return pointer to context-data */
+trampoline:
+ /* store return address on stack */
+ /* fix stack alignment */
+ push %rbp
+ /* jump to context-function */
+ jmp *%rbx
+
finish:
/* exit code is zero */
xorq %rdi, %rdi
diff --git a/thirdparty/php/standard/proc_open.cc b/thirdparty/php/standard/proc_open.cc
index ccdafefaa30..b3e50ec9d89 100644
--- a/thirdparty/php/standard/proc_open.cc
+++ b/thirdparty/php/standard/proc_open.cc
@@ -1,13 +1,11 @@
/*
- +----------------------------------------------------------------------+
- | PHP Version 7 |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
+ | https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
@@ -24,25 +22,50 @@ using swoole::Coroutine;
using swoole::PHPCoroutine;
using swoole::coroutine::Socket;
-#if HAVE_SYS_STAT_H
-#include
+#ifdef HAVE_SYS_WAIT_H
+#include
#endif
-#if HAVE_FCNTL_H
+
+#ifdef HAVE_FCNTL_H
#include
#endif
+#ifdef HAVE_PTY_H
+#include
+#elif defined(__FreeBSD__)
+/* FreeBSD defines `openpty` in */
+#include
+#elif defined(__NetBSD__) || defined(__DragonFly__)
+/* On recent NetBSD/DragonFlyBSD releases the emalloc, estrdup ... calls had been introduced in libutil */
+#if defined(__NetBSD__)
+#include
+#else
+#include
+#endif
+extern int openpty(int *, int *, char *, struct termios *, struct winsize *);
+#elif defined(__sun)
+#include
+#else
+/* Mac OS X (and some BSDs) define `openpty` in */
+#include
+#endif
+
static int le_proc_open;
static const char *le_proc_name = "process/coroutine";
-/* {{{ _php_array_to_envp */
-static proc_co_env_t _php_array_to_envp(zval *environment) {
+/* {{{ _php_array_to_envp
+ * Process the `environment` argument to `proc_open`
+ * Convert into data structures which can be passed to underlying OS APIs like `exec` on POSIX or
+ * `CreateProcessW` on Win32 */
+static sw_php_process_env _php_array_to_envp(zval *environment) {
zval *element;
- proc_co_env_t env;
- zend_string *key, *str;
+ sw_php_process_env env;
+#ifndef PHP_WIN32
char **ep;
+#endif
char *p;
- size_t cnt, sizeenv = 0;
- HashTable *env_hash;
+ size_t sizeenv = 0;
+ HashTable *env_hash; /* temporary PHP array used as helper */
memset(&env, 0, sizeof(env));
@@ -50,10 +73,12 @@ static proc_co_env_t _php_array_to_envp(zval *environment) {
return env;
}
- cnt = zend_hash_num_elements(Z_ARRVAL_P(environment));
+ uint32_t cnt = zend_hash_num_elements(Z_ARRVAL_P(environment));
if (cnt < 1) {
+#ifndef PHP_WIN32
env.envarray = (char **) ecalloc(1, sizeof(char *));
+#endif
env.envp = (char *) ecalloc(4, 1);
return env;
}
@@ -61,12 +86,15 @@ static proc_co_env_t _php_array_to_envp(zval *environment) {
ALLOC_HASHTABLE(env_hash);
zend_hash_init(env_hash, cnt, NULL, NULL, 0);
+ void *_key, *_str;
+ zend_string *key, *str;
/* first, we have to get the size of all the elements in the hash */
- ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(environment), key, element) {
+ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(environment), _key, element) {
+ key = (zend_string *) _key;
str = zval_get_string(element);
if (ZSTR_LEN(str) == 0) {
- zend_string_release(str);
+ zend_string_release_ex(str, 0);
continue;
}
@@ -81,15 +109,18 @@ static proc_co_env_t _php_array_to_envp(zval *environment) {
}
ZEND_HASH_FOREACH_END();
+#ifndef PHP_WIN32
ep = env.envarray = (char **) ecalloc(cnt + 1, sizeof(char *));
+#endif
p = env.envp = (char *) ecalloc(sizeenv + 4, 1);
- void *v1, *v2;
- ZEND_HASH_FOREACH_STR_KEY_PTR(env_hash, v1, v2) {
- key = (zend_string *) v1;
- str = (zend_string *) v2;
+ ZEND_HASH_FOREACH_STR_KEY_PTR(env_hash, _key, _str) {
+ key = (zend_string *) _key;
+ str = (zend_string *) _str;
+#ifndef PHP_WIN32
*ep = p;
++ep;
+#endif
if (key) {
memcpy(p, ZSTR_VAL(key), ZSTR_LEN(key));
@@ -100,11 +131,11 @@ static proc_co_env_t _php_array_to_envp(zval *environment) {
memcpy(p, ZSTR_VAL(str), ZSTR_LEN(str));
p += ZSTR_LEN(str);
*p++ = '\0';
- zend_string_release(str);
+ zend_string_release_ex(str, 0);
}
ZEND_HASH_FOREACH_END();
- assert((uint32_t)(p - env.envp) <= sizeenv);
+ assert((uint32_t) (p - env.envp) <= sizeenv);
zend_hash_destroy(env_hash);
FREE_HASHTABLE(env_hash);
@@ -113,28 +144,28 @@ static proc_co_env_t _php_array_to_envp(zval *environment) {
}
/* }}} */
-/* {{{ _php_free_envp */
-static void _php_free_envp(proc_co_env_t env, int is_persistent) {
+/* {{{ _php_free_envp
+ * Free the structures allocated by `_php_array_to_envp` */
+static void _php_free_envp(sw_php_process_env env) {
if (env.envarray) {
- pefree(env.envarray, is_persistent);
+ efree(env.envarray);
}
if (env.envp) {
- pefree(env.envp, is_persistent);
+ efree(env.envp);
}
}
/* }}} */
static void proc_co_rsrc_dtor(zend_resource *rsrc) {
- proc_co_t *proc = (proc_co_t *) rsrc->ptr;
- int i;
+ sw_php_process_handle *proc = (sw_php_process_handle *) rsrc->ptr;
int wstatus = 0;
/* Close all handles to avoid a deadlock */
- for (i = 0; i < proc->npipes; i++) {
- if (proc->pipes[i] != 0) {
+ for (int i = 0; i < proc->npipes; i++) {
+ if (proc->pipes[i] != NULL) {
GC_DELREF(proc->pipes[i]);
zend_list_close(proc->pipes[i]);
- proc->pipes[i] = 0;
+ proc->pipes[i] = NULL;
}
}
@@ -147,74 +178,82 @@ static void proc_co_rsrc_dtor(zend_resource *rsrc) {
*proc->wstatus = wstatus;
}
- _php_free_envp(proc->env, proc->is_persistent);
+ _php_free_envp(proc->env);
efree(proc->pipes);
- efree(proc->command);
+ zend_string_release_ex(proc->command, false);
efree(proc);
}
+/* }}} */
+/* {{{ PHP_MINIT_FUNCTION(proc_open) */
void swoole_proc_open_init(int module_number) {
le_proc_open = zend_register_list_destructors_ex(proc_co_rsrc_dtor, NULL, le_proc_name, module_number);
}
+/* }}} */
-/* {{{ proto bool proc_terminate(resource process [, int signal])
- kill a process opened by proc_open */
+/* {{{ Kill a process opened by `proc_open` */
PHP_FUNCTION(swoole_proc_terminate) {
zval *zproc;
- proc_co_t *proc;
+ sw_php_process_handle *proc;
zend_long sig_no = SIGTERM;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_RESOURCE(zproc)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(sig_no)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
+ ZEND_PARSE_PARAMETERS_END();
- if ((proc = (proc_co_t *) zend_fetch_resource(Z_RES_P(zproc), le_proc_name, le_proc_open)) == NULL) {
- RETURN_FALSE;
+ proc = (sw_php_process_handle *) zend_fetch_resource(Z_RES_P(zproc), le_proc_name, le_proc_open);
+ if (proc == NULL) {
+ RETURN_THROWS();
}
+#ifdef PHP_WIN32
+ RETURN_BOOL(TerminateProcess(proc->childHandle, 255));
+#else
RETURN_BOOL(kill(proc->child, sig_no) == 0);
+#endif
}
/* }}} */
+/* {{{ Close a process opened by `proc_open` */
PHP_FUNCTION(swoole_proc_close) {
zval *zproc;
- proc_co_t *proc;
int wstatus = 0;
+ sw_php_process_handle *proc;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_RESOURCE(zproc)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
+ ZEND_PARSE_PARAMETERS_END();
- if ((proc = (proc_co_t *) zend_fetch_resource(Z_RES_P(zproc), le_proc_name, le_proc_open)) == NULL) {
- RETURN_FALSE;
+ if ((proc = (sw_php_process_handle *) zend_fetch_resource(Z_RES_P(zproc), le_proc_name, le_proc_open)) == NULL) {
+ RETURN_THROWS();
}
-
proc->wstatus = &wstatus;
zend_list_close(Z_RES_P(zproc));
RETURN_LONG(wstatus);
}
+/* }}} */
+/* {{{ Get information about a process opened by `proc_open` */
PHP_FUNCTION(swoole_proc_get_status) {
zval *zproc;
- proc_co_t *proc;
+ sw_php_process_handle *proc;
int wstatus;
pid_t wait_pid;
- int running = 1, signaled = 0, stopped = 0;
+ bool running = 1, signaled = 0, stopped = 0;
int exitcode = -1, termsig = 0, stopsig = 0;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_RESOURCE(zproc)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
+ ZEND_PARSE_PARAMETERS_END();
- if ((proc = (proc_co_t *) zend_fetch_resource(Z_RES_P(zproc), le_proc_name, le_proc_open)) == NULL) {
- RETURN_FALSE;
+ if ((proc = (sw_php_process_handle *) zend_fetch_resource(Z_RES_P(zproc), le_proc_name, le_proc_open)) == NULL) {
+ RETURN_THROWS();
}
array_init(return_value);
-
- add_assoc_string(return_value, "command", proc->command);
+ add_assoc_str(return_value, "command", zend_string_copy(proc->command));
add_assoc_long(return_value, "pid", (zend_long) proc->child);
errno = 0;
@@ -228,7 +267,6 @@ PHP_FUNCTION(swoole_proc_get_status) {
if (WIFSIGNALED(wstatus)) {
running = 0;
signaled = 1;
-
termsig = WTERMSIG(wstatus);
}
if (WIFSTOPPED(wstatus)) {
@@ -236,6 +274,8 @@ PHP_FUNCTION(swoole_proc_get_status) {
stopsig = WSTOPSIG(wstatus);
}
} else if (wait_pid == -1) {
+ /* The only error which could occur here is ECHILD, which means that the PID we were
+ * looking for either does not exist or is not a child of this process */
running = 0;
}
@@ -250,18 +290,50 @@ PHP_FUNCTION(swoole_proc_get_status) {
}
/* }}} */
-#define DESC_PIPE 1
-#define DESC_FILE 2
-#define DESC_REDIRECT 3
-#define DESC_PARENT_MODE_WRITE 8
-
-struct php_proc_open_descriptor_item {
- int index; /* desired fd number in child process */
- int parentend, childend; /* fds for pipes in parent/child */
- int mode; /* mode for proc_open code */
- int mode_flags; /* mode flags for opening fds */
-};
-/* }}} */
+#ifdef PHP_WIN32
+
+/* We use this to allow child processes to inherit handles
+ * One static instance can be shared and used for all calls to `proc_open`, since the values are
+ * never changed */
+SECURITY_ATTRIBUTES php_proc_open_security = {
+ .nLength = sizeof(SECURITY_ATTRIBUTES), .lpSecurityDescriptor = NULL, .bInheritHandle = TRUE};
+
+#define pipe(pair) (CreatePipe(&pair[0], &pair[1], &php_proc_open_security, 0) ? 0 : -1)
+
+#define COMSPEC_NT "cmd.exe"
+
+static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig) {
+ HANDLE copy, self = GetCurrentProcess();
+
+ if (!DuplicateHandle(
+ self, src, self, ©, 0, inherit, DUPLICATE_SAME_ACCESS | (closeorig ? DUPLICATE_CLOSE_SOURCE : 0)))
+ return NULL;
+ return copy;
+}
+
+static inline HANDLE dup_fd_as_handle(int fd) {
+ return dup_handle((HANDLE) _get_osfhandle(fd), TRUE, FALSE);
+}
+
+#define close_descriptor(fd) CloseHandle(fd)
+#else /* !PHP_WIN32 */
+#define close_descriptor(fd) close(fd)
+#endif
+
+/* Determines the type of a descriptor item. */
+typedef enum _descriptor_type { DESCRIPTOR_TYPE_STD, DESCRIPTOR_TYPE_PIPE, DESCRIPTOR_TYPE_SOCKET } descriptor_type;
+
+/* One instance of this struct is created for each item in `$descriptorspec` argument to `proc_open`
+ * They are used within `proc_open` and freed before it returns */
+typedef struct _descriptorspec_item {
+ int index; /* desired FD # in child process */
+ descriptor_type type;
+ php_file_descriptor_t childend; /* FD # opened for use in child
+ * (will be copied to `index` in child) */
+ php_file_descriptor_t parentend; /* FD # opened for use in parent
+ * (for pipes only; will be 0 otherwise) */
+ int mode_flags; /* mode for opening FDs: r/o, r/w, binary (on Win32), etc */
+} descriptorspec_item;
static zend_string *get_valid_arg_string(zval *zv, int elem_num) {
zend_string *str = zval_get_string(zv);
@@ -269,8 +341,14 @@ static zend_string *get_valid_arg_string(zval *zv, int elem_num) {
return NULL;
}
+ if (elem_num == 1 && ZSTR_LEN(str) == 0) {
+ zend_value_error("First element must contain a non-empty program name");
+ zend_string_release(str);
+ return NULL;
+ }
+
if (strlen(ZSTR_VAL(str)) != ZSTR_LEN(str)) {
- php_error_docref(NULL, E_WARNING, "Command array element %d contains a null byte", elem_num);
+ zend_value_error("Command array element %d contains a null byte", elem_num);
zend_string_release(str);
return NULL;
}
@@ -278,76 +356,627 @@ static zend_string *get_valid_arg_string(zval *zv, int elem_num) {
return str;
}
-/* {{{ proto resource proc_open(string|array command, array descriptorspec, array &pipes [, string cwd [, array env [,
- array other_options]]]) Run a process with more control over it's file descriptors */
+#ifdef PHP_WIN32
+static void append_backslashes(smart_str *str, size_t num_bs) {
+ for (size_t i = 0; i < num_bs; i++) {
+ smart_str_appendc(str, '\\');
+ }
+}
+
+/* See https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments */
+static void append_win_escaped_arg(smart_str *str, zend_string *arg) {
+ size_t num_bs = 0;
+
+ smart_str_appendc(str, '"');
+ for (size_t i = 0; i < ZSTR_LEN(arg); ++i) {
+ char c = ZSTR_VAL(arg)[i];
+ if (c == '\\') {
+ num_bs++;
+ continue;
+ }
+
+ if (c == '"') {
+ /* Backslashes before " need to be doubled. */
+ num_bs = num_bs * 2 + 1;
+ }
+ append_backslashes(str, num_bs);
+ smart_str_appendc(str, c);
+ num_bs = 0;
+ }
+ append_backslashes(str, num_bs * 2);
+ smart_str_appendc(str, '"');
+}
+
+static zend_string *create_win_command_from_args(HashTable *args) {
+ smart_str str = {0};
+ zval *arg_zv;
+ bool is_prog_name = 1;
+ int elem_num = 0;
+
+ ZEND_HASH_FOREACH_VAL(args, arg_zv) {
+ zend_string *arg_str = get_valid_arg_string(arg_zv, ++elem_num);
+ if (!arg_str) {
+ smart_str_free(&str);
+ return NULL;
+ }
+
+ if (!is_prog_name) {
+ smart_str_appendc(&str, ' ');
+ }
+
+ append_win_escaped_arg(&str, arg_str);
+
+ is_prog_name = 0;
+ zend_string_release(arg_str);
+ }
+ ZEND_HASH_FOREACH_END();
+ smart_str_0(&str);
+ return str.s;
+}
+
+/* Get a boolean option from the `other_options` array which can be passed to `proc_open`.
+ * (Currently, all options apply on Windows only.) */
+static bool get_option(zval *other_options, char *opt_name, size_t opt_name_len) {
+ HashTable *opt_ary = Z_ARRVAL_P(other_options);
+ zval *item = zend_hash_str_find_deref(opt_ary, opt_name, opt_name_len);
+ return item != NULL && (Z_TYPE_P(item) == IS_TRUE || ((Z_TYPE_P(item) == IS_LONG) && Z_LVAL_P(item)));
+}
+
+/* Initialize STARTUPINFOW struct, used on Windows when spawning a process.
+ * Ref: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfow */
+static void init_startup_info(STARTUPINFOW *si, descriptorspec_item *descriptors, int ndesc) {
+ memset(si, 0, sizeof(STARTUPINFOW));
+ si->cb = sizeof(STARTUPINFOW);
+ si->dwFlags = STARTF_USESTDHANDLES;
+
+ si->hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ si->hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ si->hStdError = GetStdHandle(STD_ERROR_HANDLE);
+
+ /* redirect stdin/stdout/stderr if requested */
+ for (int i = 0; i < ndesc; i++) {
+ switch (descriptors[i].index) {
+ case 0:
+ si->hStdInput = descriptors[i].childend;
+ break;
+ case 1:
+ si->hStdOutput = descriptors[i].childend;
+ break;
+ case 2:
+ si->hStdError = descriptors[i].childend;
+ break;
+ }
+ }
+}
+
+static void init_process_info(PROCESS_INFORMATION *pi) {
+ memset(&pi, 0, sizeof(pi));
+}
+
+static zend_result convert_command_to_use_shell(wchar_t **cmdw, size_t cmdw_len) {
+ size_t len = sizeof(COMSPEC_NT) + sizeof(" /s /c ") + cmdw_len + 3;
+ wchar_t *cmdw_shell = (wchar_t *) malloc(len * sizeof(wchar_t));
+
+ if (cmdw_shell == NULL) {
+ php_error_docref(NULL, E_WARNING, "Command conversion failed");
+ return FAILURE;
+ }
+
+ if (_snwprintf(cmdw_shell, len, L"%hs /s /c \"%s\"", COMSPEC_NT, *cmdw) == -1) {
+ free(cmdw_shell);
+ php_error_docref(NULL, E_WARNING, "Command conversion failed");
+ return FAILURE;
+ }
+
+ free(*cmdw);
+ *cmdw = cmdw_shell;
+
+ return SUCCESS;
+}
+#endif
+
+/* Convert command parameter array passed as first argument to `proc_open` into command string */
+static zend_string *get_command_from_array(HashTable *array, char ***argv, int num_elems) {
+ zval *arg_zv;
+ zend_string *command = NULL;
+ int i = 0;
+
+ *argv = (char **) safe_emalloc(sizeof(char *), num_elems + 1, 0);
+
+ ZEND_HASH_FOREACH_VAL(array, arg_zv) {
+ zend_string *arg_str = get_valid_arg_string(arg_zv, i + 1);
+ if (!arg_str) {
+ /* Terminate with NULL so exit_fail code knows how many entries to free */
+ (*argv)[i] = NULL;
+ if (command != NULL) {
+ zend_string_release_ex(command, false);
+ }
+ return NULL;
+ }
+
+ if (i == 0) {
+ command = zend_string_copy(arg_str);
+ }
+
+ (*argv)[i++] = (char *) estrdup(ZSTR_VAL(arg_str));
+ zend_string_release(arg_str);
+ }
+ ZEND_HASH_FOREACH_END();
+
+ (*argv)[i] = NULL;
+ return command;
+}
+
+static descriptorspec_item *alloc_descriptor_array(HashTable *descriptorspec) {
+ uint32_t ndescriptors = zend_hash_num_elements(descriptorspec);
+ return (descriptorspec_item *) ecalloc(sizeof(descriptorspec_item), ndescriptors);
+}
+
+static zend_string *get_string_parameter(zval *array, int index, char *param_name) {
+ zval *array_item;
+ if ((array_item = zend_hash_index_find(Z_ARRVAL_P(array), index)) == NULL) {
+ zend_value_error("Missing %s", param_name);
+ return NULL;
+ }
+ return zval_try_get_string(array_item);
+}
+
+static zend_result set_proc_descriptor_to_blackhole(descriptorspec_item *desc) {
+#ifdef PHP_WIN32
+ desc->childend = CreateFileA(
+ "nul", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ if (desc->childend == NULL) {
+ php_error_docref(NULL, E_WARNING, "Failed to open nul");
+ return FAILURE;
+ }
+#else
+ desc->childend = open("/dev/null", O_RDWR);
+ if (desc->childend < 0) {
+ php_error_docref(NULL, E_WARNING, "Failed to open /dev/null: %s", strerror(errno));
+ return FAILURE;
+ }
+#endif
+ return SUCCESS;
+}
+
+static zend_result set_proc_descriptor_to_pty(descriptorspec_item *desc, int *master_fd, int *slave_fd) {
+#ifdef HAVE_OPENPTY
+ /* All FDs set to PTY in the child process will go to the slave end of the same PTY.
+ * Likewise, all the corresponding entries in `$pipes` in the parent will all go to the master
+ * end of the same PTY.
+ * If this is the first descriptorspec set to 'pty', find an available PTY and get master and
+ * slave FDs. */
+ if (*master_fd == -1) {
+ if (openpty(master_fd, slave_fd, NULL, NULL, NULL)) {
+ php_error_docref(NULL, E_WARNING, "Could not open PTY (pseudoterminal): %s", strerror(errno));
+ return FAILURE;
+ }
+ }
+
+ desc->type = DESCRIPTOR_TYPE_PIPE;
+ desc->childend = dup(*slave_fd);
+ desc->parentend = dup(*master_fd);
+ desc->mode_flags = O_RDWR;
+ return SUCCESS;
+#else
+ php_error_docref(NULL, E_WARNING, "PTY (pseudoterminal) not supported on this system");
+ return FAILURE;
+#endif
+}
+
+/* Mark the descriptor close-on-exec, so it won't be inherited by children */
+static php_file_descriptor_t make_descriptor_cloexec(php_file_descriptor_t fd) {
+#ifdef PHP_WIN32
+ return dup_handle(fd, FALSE, TRUE);
+#else
+#if defined(F_SETFD) && defined(FD_CLOEXEC)
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+ return fd;
+#endif
+}
+
+static zend_result set_proc_descriptor_to_pipe(descriptorspec_item *desc, zend_string *zmode) {
+ php_file_descriptor_t newpipe[2];
+
+ if (pipe(newpipe) != 0) {
+ php_error_docref(NULL, E_WARNING, "Unable to create pipe %s", strerror(errno));
+ return FAILURE;
+ }
+
+ desc->type = DESCRIPTOR_TYPE_PIPE;
+
+ if (strncmp(ZSTR_VAL(zmode), "w", 1) != 0) {
+ desc->parentend = newpipe[1];
+ desc->childend = newpipe[0];
+ desc->mode_flags = O_WRONLY;
+ } else {
+ desc->parentend = newpipe[0];
+ desc->childend = newpipe[1];
+ desc->mode_flags = O_RDONLY;
+ }
+
+ desc->parentend = make_descriptor_cloexec(desc->parentend);
+
+#ifdef PHP_WIN32
+ if (ZSTR_LEN(zmode) >= 2 && ZSTR_VAL(zmode)[1] == 'b') desc->mode_flags |= O_BINARY;
+#endif
+
+ return SUCCESS;
+}
+
+#ifdef PHP_WIN32
+#define create_socketpair(socks) socketpair_win32(AF_INET, SOCK_STREAM, 0, (socks), 0)
+#else
+#define create_socketpair(socks) socketpair(AF_UNIX, SOCK_STREAM, 0, (socks))
+#endif
+
+static zend_result set_proc_descriptor_to_socket(descriptorspec_item *desc) {
+ php_socket_t sock[2];
+
+ if (create_socketpair(sock)) {
+ zend_string *err = php_socket_error_str(php_socket_errno());
+ php_error_docref(NULL, E_WARNING, "Unable to create socket pair: %s", ZSTR_VAL(err));
+ zend_string_release(err);
+ return FAILURE;
+ }
+
+ desc->type = DESCRIPTOR_TYPE_SOCKET;
+ desc->parentend = make_descriptor_cloexec((php_file_descriptor_t) sock[0]);
+
+ /* Pass sock[1] to child because it will never use overlapped IO on Windows. */
+ desc->childend = (php_file_descriptor_t) sock[1];
+
+ return SUCCESS;
+}
+
+static zend_result set_proc_descriptor_to_file(descriptorspec_item *desc,
+ zend_string *file_path,
+ zend_string *file_mode) {
+ php_socket_t fd;
+
+ /* try a wrapper */
+ php_stream *stream =
+ php_stream_open_wrapper(ZSTR_VAL(file_path), ZSTR_VAL(file_mode), REPORT_ERRORS | STREAM_WILL_CAST, NULL);
+ if (stream == NULL) {
+ return FAILURE;
+ }
+
+ /* force into an fd */
+ if (php_stream_cast(stream, PHP_STREAM_CAST_RELEASE | PHP_STREAM_AS_FD, (void **) &fd, REPORT_ERRORS) == FAILURE) {
+ return FAILURE;
+ }
+
+#ifdef PHP_WIN32
+ desc->childend = dup_fd_as_handle((int) fd);
+ _close((int) fd);
+
+ /* Simulate the append mode by fseeking to the end of the file
+ * This introduces a potential race condition, but it is the best we can do */
+ if (strchr(ZSTR_VAL(file_mode), 'a')) {
+ SetFilePointer(desc->childend, 0, NULL, FILE_END);
+ }
+#else
+ desc->childend = fd;
+#endif
+ return SUCCESS;
+}
+
+static zend_result dup_proc_descriptor(php_file_descriptor_t from, php_file_descriptor_t *to, zend_ulong nindex) {
+#ifdef PHP_WIN32
+ *to = dup_handle(from, TRUE, FALSE);
+ if (*to == NULL) {
+ php_error_docref(NULL, E_WARNING, "Failed to dup() for descriptor " ZEND_LONG_FMT, nindex);
+ return FAILURE;
+ }
+#else
+ *to = dup(from);
+ if (*to < 0) {
+ php_error_docref(
+ NULL, E_WARNING, "Failed to dup() for descriptor " ZEND_LONG_FMT ": %s", nindex, strerror(errno));
+ return FAILURE;
+ }
+#endif
+ return SUCCESS;
+}
+
+static zend_result redirect_proc_descriptor(
+ descriptorspec_item *desc, int target, descriptorspec_item *descriptors, int ndesc, int nindex) {
+ php_file_descriptor_t redirect_to = PHP_INVALID_FD;
+
+ for (int i = 0; i < ndesc; i++) {
+ if (descriptors[i].index == target) {
+ redirect_to = descriptors[i].childend;
+ break;
+ }
+ }
+
+ if (redirect_to == PHP_INVALID_FD) { /* Didn't find the index we wanted */
+ if (target < 0 || target > 2) {
+ php_error_docref(NULL, E_WARNING, "Redirection target %d not found", target);
+ return FAILURE;
+ }
+
+ /* Support referring to a stdin/stdout/stderr pipe adopted from the parent,
+ * which happens whenever an explicit override is not provided. */
+#ifndef PHP_WIN32
+ redirect_to = target;
+#else
+ switch (target) {
+ case 0:
+ redirect_to = GetStdHandle(STD_INPUT_HANDLE);
+ break;
+ case 1:
+ redirect_to = GetStdHandle(STD_OUTPUT_HANDLE);
+ break;
+ case 2:
+ redirect_to = GetStdHandle(STD_ERROR_HANDLE);
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE()
+ }
+#endif
+ }
+
+ return dup_proc_descriptor(redirect_to, &desc->childend, nindex);
+}
+
+/* Process one item from `$descriptorspec` argument to `proc_open` */
+static zend_result set_proc_descriptor_from_array(
+ zval *descitem, descriptorspec_item *descriptors, int ndesc, int nindex, int *pty_master_fd, int *pty_slave_fd) {
+ zend_string *ztype = get_string_parameter(descitem, 0, "handle qualifier");
+ if (!ztype) {
+ return FAILURE;
+ }
+
+ zend_string *zmode = NULL, *zfile = NULL;
+ zend_result retval = FAILURE;
+
+#if 0
+ if (zend_string_equals_literal(ztype, "pipe")) {
+ /* Set descriptor to pipe */
+ zmode = get_string_parameter(descitem, 1, "mode parameter for 'pipe'");
+ if (zmode == NULL) {
+ goto finish;
+ }
+ retval = set_proc_descriptor_to_pipe(&descriptors[ndesc], zmode);
+ } else
+#endif
+ if (zend_string_equals_literal(ztype, "socket") || zend_string_equals_literal(ztype, "pipe")) {
+ /* Set descriptor to socketpair */
+ retval = set_proc_descriptor_to_socket(&descriptors[ndesc]);
+ } else if (zend_string_equals(ztype, ZSTR_KNOWN(ZEND_STR_FILE))) {
+ /* Set descriptor to file */
+ if ((zfile = get_string_parameter(descitem, 1, "file name parameter for 'file'")) == NULL) {
+ goto finish;
+ }
+ if ((zmode = get_string_parameter(descitem, 2, "mode parameter for 'file'")) == NULL) {
+ goto finish;
+ }
+ retval = set_proc_descriptor_to_file(&descriptors[ndesc], zfile, zmode);
+ } else if (zend_string_equals_literal(ztype, "redirect")) {
+ /* Redirect descriptor to whatever another descriptor is set to */
+ zval *ztarget = zend_hash_index_find_deref(Z_ARRVAL_P(descitem), 1);
+ if (!ztarget) {
+ zend_value_error("Missing redirection target");
+ goto finish;
+ }
+ if (Z_TYPE_P(ztarget) != IS_LONG) {
+ zend_value_error("Redirection target must be of type int, %s given", zend_zval_type_name(ztarget));
+ goto finish;
+ }
+
+ retval = redirect_proc_descriptor(&descriptors[ndesc], (int) Z_LVAL_P(ztarget), descriptors, ndesc, nindex);
+ } else if (zend_string_equals(ztype, ZSTR_KNOWN(ZEND_STR_NULL_LOWERCASE))) {
+ /* Set descriptor to blackhole (discard all data written) */
+ retval = set_proc_descriptor_to_blackhole(&descriptors[ndesc]);
+ } else if (zend_string_equals_literal(ztype, "pty")) {
+ /* Set descriptor to slave end of PTY */
+ retval = set_proc_descriptor_to_pty(&descriptors[ndesc], pty_master_fd, pty_slave_fd);
+ } else {
+ php_error_docref(NULL, E_WARNING, "%s is not a valid descriptor spec/mode", ZSTR_VAL(ztype));
+ goto finish;
+ }
+
+finish:
+ if (zmode) zend_string_release(zmode);
+ if (zfile) zend_string_release(zfile);
+ zend_string_release(ztype);
+ return retval;
+}
+
+static zend_result set_proc_descriptor_from_resource(zval *resource, descriptorspec_item *desc, int nindex) {
+ /* Should be a stream - try and dup the descriptor */
+ php_stream *stream = (php_stream *) zend_fetch_resource(Z_RES_P(resource), "stream", php_file_le_stream());
+ if (stream == NULL) {
+ return FAILURE;
+ }
+
+ php_socket_t fd;
+ zend_result status = (zend_result) php_stream_cast(stream, PHP_STREAM_AS_FD, (void **) &fd, REPORT_ERRORS);
+ if (status == FAILURE) {
+ return FAILURE;
+ }
+
+#ifdef PHP_WIN32
+ php_file_descriptor_t fd_t = (php_file_descriptor_t) _get_osfhandle(fd);
+#else
+ php_file_descriptor_t fd_t = fd;
+#endif
+ return dup_proc_descriptor(fd_t, &desc->childend, nindex);
+}
+
+#ifndef PHP_WIN32
+#if defined(USE_POSIX_SPAWN)
+static zend_result close_parentends_of_pipes(posix_spawn_file_actions_t *actions,
+ descriptorspec_item *descriptors,
+ int ndesc) {
+ int r;
+ for (int i = 0; i < ndesc; i++) {
+ if (descriptors[i].type != DESCRIPTOR_TYPE_STD) {
+ r = posix_spawn_file_actions_addclose(actions, descriptors[i].parentend);
+ if (r != 0) {
+ php_error_docref(
+ NULL, E_WARNING, "Cannot close file descriptor %d: %s", descriptors[i].parentend, strerror(r));
+ return FAILURE;
+ }
+ }
+ if (descriptors[i].childend != descriptors[i].index) {
+ r = posix_spawn_file_actions_adddup2(actions, descriptors[i].childend, descriptors[i].index);
+ if (r != 0) {
+ php_error_docref(NULL,
+ E_WARNING,
+ "Unable to copy file descriptor %d (for pipe) into "
+ "file descriptor %d: %s",
+ descriptors[i].childend,
+ descriptors[i].index,
+ strerror(r));
+ return FAILURE;
+ }
+ r = posix_spawn_file_actions_addclose(actions, descriptors[i].childend);
+ if (r != 0) {
+ php_error_docref(
+ NULL, E_WARNING, "Cannot close file descriptor %d: %s", descriptors[i].childend, strerror(r));
+ return FAILURE;
+ }
+ }
+ }
+
+ return SUCCESS;
+}
+#else
+static zend_result close_parentends_of_pipes(descriptorspec_item *descriptors, int ndesc) {
+ /* We are running in child process
+ * Close the 'parent end' of pipes which were opened before forking/spawning
+ * Also, dup() the child end of all pipes as necessary so they will use the FD
+ * number which the user requested */
+ for (int i = 0; i < ndesc; i++) {
+ if (descriptors[i].type != DESCRIPTOR_TYPE_STD) {
+ close(descriptors[i].parentend);
+ }
+ if (descriptors[i].childend != descriptors[i].index) {
+ if (dup2(descriptors[i].childend, descriptors[i].index) < 0) {
+ php_error_docref(NULL,
+ E_WARNING,
+ "Unable to copy file descriptor %d (for pipe) into "
+ "file descriptor %d: %s",
+ descriptors[i].childend,
+ descriptors[i].index,
+ strerror(errno));
+ return FAILURE;
+ }
+ close(descriptors[i].childend);
+ }
+ }
+
+ return SUCCESS;
+}
+#endif
+#endif
+
+static void close_all_descriptors(descriptorspec_item *descriptors, int ndesc) {
+ for (int i = 0; i < ndesc; i++) {
+ close_descriptor(descriptors[i].childend);
+ if (descriptors[i].parentend) close_descriptor(descriptors[i].parentend);
+ }
+}
+
+static void efree_argv(char **argv) {
+ if (argv) {
+ char **arg = argv;
+ while (*arg != NULL) {
+ efree(*arg);
+ arg++;
+ }
+ efree(argv);
+ }
+}
+
+/* {{{ Execute a command, with specified files used for input/output */
PHP_FUNCTION(swoole_proc_open) {
- zval *command_zv;
- char *command = NULL, *cwd = NULL;
- size_t cwd_len = 0;
- zval *descriptorspec;
- zval *pipes;
- zval *environment = NULL;
- zval *other_options = NULL;
- proc_co_env_t env;
+ zend_string *command_str;
+ HashTable *command_ht;
+ HashTable *descriptorspec; /* Mandatory argument */
+ zval *pipes; /* Mandatory argument */
+ char *cwd = NULL; /* Optional argument */
+ size_t cwd_len = 0; /* Optional argument */
+ zval *environment = NULL, *other_options = NULL; /* Optional arguments */
+
+ sw_php_process_env env;
int ndesc = 0;
int i;
zval *descitem = NULL;
zend_string *str_index;
zend_ulong nindex;
- struct php_proc_open_descriptor_item *descriptors = NULL;
- int ndescriptors_array;
-
+ descriptorspec_item *descriptors = NULL;
+#ifdef PHP_WIN32
+ PROCESS_INFORMATION pi;
+ HANDLE childHandle;
+ STARTUPINFOW si;
+ BOOL newprocok;
+ DWORD dwCreateFlags = 0;
+ UINT old_error_mode;
+ char cur_cwd[MAXPATHLEN];
+ wchar_t *cmdw = NULL, *cwdw = NULL, *envpw = NULL;
+ size_t cmdw_len;
+ bool suppress_errors = 0;
+ bool bypass_shell = 0;
+ bool blocking_pipes = 0;
+ bool create_process_group = 0;
+ bool create_new_console = 0;
+#else
char **argv = NULL;
-
- pid_t child;
- proc_co_t *proc;
- int is_persistent = 0; /* TODO: ensure that persistent procs will work */
+#endif
+ int pty_master_fd = -1, pty_slave_fd = -1;
+ php_process_id_t child;
+ sw_php_process_handle *proc;
ZEND_PARSE_PARAMETERS_START(3, 6)
- Z_PARAM_ZVAL(command_zv)
- Z_PARAM_ARRAY(descriptorspec)
+ Z_PARAM_ARRAY_HT_OR_STR(command_ht, command_str)
+ Z_PARAM_ARRAY_HT(descriptorspec)
Z_PARAM_ZVAL(pipes)
Z_PARAM_OPTIONAL
- Z_PARAM_STRING_EX(cwd, cwd_len, 1, 0)
- Z_PARAM_ARRAY_EX(environment, 1, 0)
- Z_PARAM_ARRAY_EX(other_options, 1, 0)
- ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
+ Z_PARAM_STRING_OR_NULL(cwd, cwd_len)
+ Z_PARAM_ARRAY_OR_NULL(environment)
+ Z_PARAM_ARRAY_OR_NULL(other_options)
+ ZEND_PARSE_PARAMETERS_END();
memset(&env, 0, sizeof(env));
- if (Z_TYPE_P(command_zv) == IS_ARRAY) {
- zval *arg_zv;
- uint32_t num_elems = zend_hash_num_elements(Z_ARRVAL_P(command_zv));
+ if (command_ht) {
+ uint32_t num_elems = zend_hash_num_elements(command_ht);
if (num_elems == 0) {
- php_error_docref(NULL, E_WARNING, "Command array must have at least one element");
- RETURN_FALSE;
+ zend_argument_value_error(1, "must have at least one element");
+ RETURN_THROWS();
}
- argv = (char **) safe_emalloc(sizeof(char *), num_elems + 1, 0);
- i = 0;
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(command_zv), arg_zv) {
- zend_string *arg_str = get_valid_arg_string(arg_zv, i + 1);
- if (!arg_str) {
- argv[i] = NULL;
- goto exit_fail;
- }
-
- if (i == 0) {
- command = pestrdup(ZSTR_VAL(arg_str), is_persistent);
- }
+#ifdef PHP_WIN32
+ /* Automatically bypass shell if command is given as an array */
+ bypass_shell = 1;
+ command_str = create_win_command_from_args(command_ht);
+#else
+ command_str = get_command_from_array(command_ht, &argv, num_elems);
+#endif
- argv[i++] = estrdup(ZSTR_VAL(arg_str));
- zend_string_release(arg_str);
+ if (!command_str) {
+#ifndef PHP_WIN32
+ efree_argv(argv);
+#endif
+ RETURN_FALSE;
}
- ZEND_HASH_FOREACH_END();
- argv[i] = NULL;
-
- /* As the array is non-empty, we should have found a command. */
- ZEND_ASSERT(command);
} else {
- convert_to_string(command_zv);
- command = pestrdup(Z_STRVAL_P(command_zv), is_persistent);
+ zend_string_addref(command_str);
+ }
+
+#ifdef PHP_WIN32
+ if (other_options) {
+ suppress_errors = get_option(other_options, "suppress_errors", strlen("suppress_errors"));
+ /* TODO: Deprecate in favor of array command? */
+ bypass_shell = bypass_shell || get_option(other_options, "bypass_shell", strlen("bypass_shell"));
+ blocking_pipes = get_option(other_options, "blocking_pipes", strlen("blocking_pipes"));
+ create_process_group = get_option(other_options, "create_process_group", strlen("create_process_group"));
+ create_new_console = get_option(other_options, "create_new_console", strlen("create_new_console"));
}
+#endif
php_swoole_check_reactor();
if (php_swoole_signal_isset_handler(SIGCHLD)) {
@@ -355,251 +984,157 @@ PHP_FUNCTION(swoole_proc_open) {
RETURN_FALSE;
}
- Coroutine::get_current_safe();
+ swoole::Coroutine::get_current_safe();
if (environment) {
env = _php_array_to_envp(environment);
- } else {
- memset(&env, 0, sizeof(env));
}
- ndescriptors_array = zend_hash_num_elements(Z_ARRVAL_P(descriptorspec));
-
- descriptors = (struct php_proc_open_descriptor_item *) safe_emalloc(
- sizeof(struct php_proc_open_descriptor_item), ndescriptors_array, 0);
-
- memset(descriptors, 0, sizeof(struct php_proc_open_descriptor_item) * ndescriptors_array);
-
- /* walk the descriptor spec and set up files/pipes */
- ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(descriptorspec), nindex, str_index, descitem) {
- zval *ztype;
+ descriptors = alloc_descriptor_array(descriptorspec);
+ /* Walk the descriptor spec and set up files/pipes */
+ ZEND_HASH_FOREACH_KEY_VAL(descriptorspec, nindex, str_index, descitem) {
if (str_index) {
- php_swoole_fatal_error(E_WARNING, "descriptor spec must be an integer indexed array");
+ zend_argument_value_error(2, "must be an integer indexed array");
goto exit_fail;
}
descriptors[ndesc].index = (int) nindex;
+ ZVAL_DEREF(descitem);
if (Z_TYPE_P(descitem) == IS_RESOURCE) {
- /* should be a stream - try and dup the descriptor */
- php_stream *stream;
- php_socket_t fd;
-
- php_stream_from_zval(stream, descitem);
-
- if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_FD, (void **) &fd, REPORT_ERRORS)) {
+ if (set_proc_descriptor_from_resource(descitem, &descriptors[ndesc], ndesc) == FAILURE) {
goto exit_fail;
}
-
- descriptors[ndesc].childend = dup(fd);
- if (descriptors[ndesc].childend < 0) {
- php_swoole_fatal_error(E_WARNING,
- "unable to dup File-Handle for descriptor " ZEND_ULONG_FMT " - %s",
- nindex,
- strerror(errno));
+ } else if (Z_TYPE_P(descitem) == IS_ARRAY) {
+ if (set_proc_descriptor_from_array(
+ descitem, descriptors, ndesc, (int) nindex, &pty_master_fd, &pty_slave_fd) == FAILURE) {
goto exit_fail;
}
+ } else {
+ php_swoole_fatal_error(E_WARNING, "Descriptor item must be either an array or a File-Handle");
+ goto exit_fail;
+ }
+ ndesc++;
+ }
+ ZEND_HASH_FOREACH_END();
+
+#ifdef PHP_WIN32
+ if (cwd == NULL) {
+ char *getcwd_result = VCWD_GETCWD(cur_cwd, MAXPATHLEN);
+ if (!getcwd_result) {
+ php_error_docref(NULL, E_WARNING, "Cannot get current directory");
+ goto exit_fail;
+ }
+ cwd = cur_cwd;
+ }
+ cwdw = php_win32_cp_any_to_w(cwd);
+ if (!cwdw) {
+ php_error_docref(NULL, E_WARNING, "CWD conversion failed");
+ goto exit_fail;
+ }
- descriptors[ndesc].mode = DESC_FILE;
+ init_startup_info(&si, descriptors, ndesc);
+ init_process_info(&pi);
- } else if (Z_TYPE_P(descitem) != IS_ARRAY) {
- php_swoole_fatal_error(E_WARNING, "Descriptor item must be either an array or a File-Handle");
+ if (suppress_errors) {
+ old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+ }
+
+ dwCreateFlags = NORMAL_PRIORITY_CLASS;
+ if (strcmp(sapi_module.name, "cli") != 0) {
+ dwCreateFlags |= CREATE_NO_WINDOW;
+ }
+ if (create_process_group) {
+ dwCreateFlags |= CREATE_NEW_PROCESS_GROUP;
+ }
+ if (create_new_console) {
+ dwCreateFlags |= CREATE_NEW_CONSOLE;
+ }
+ envpw = php_win32_cp_env_any_to_w(env.envp);
+ if (envpw) {
+ dwCreateFlags |= CREATE_UNICODE_ENVIRONMENT;
+ } else {
+ if (env.envp) {
+ php_error_docref(NULL, E_WARNING, "ENV conversion failed");
goto exit_fail;
- } else {
- if ((ztype = zend_hash_index_find(Z_ARRVAL_P(descitem), 0)) != NULL) {
- convert_to_string_ex(ztype);
- } else {
- php_swoole_fatal_error(E_WARNING, "Missing handle qualifier in array");
- goto exit_fail;
- }
+ }
+ }
- if (strcmp(Z_STRVAL_P(ztype), "pipe") == 0) {
- php_file_descriptor_t newpipe[2];
- zval *zmode;
-
- if ((zmode = zend_hash_index_find(Z_ARRVAL_P(descitem), 1)) != NULL) {
- convert_to_string_ex(zmode);
- } else {
- php_swoole_fatal_error(E_WARNING, "Missing mode parameter for 'pipe'");
- goto exit_fail;
- }
-
- descriptors[ndesc].mode = DESC_PIPE;
-
- if (0 != socketpair(AF_UNIX, SOCK_STREAM, 0, newpipe)) {
- php_swoole_fatal_error(E_WARNING, "unable to create pipe %s", strerror(errno));
- goto exit_fail;
- }
-
- if (strncmp(Z_STRVAL_P(zmode), "w", 1) != 0) {
- descriptors[ndesc].parentend = newpipe[1];
- descriptors[ndesc].childend = newpipe[0];
- descriptors[ndesc].mode |= DESC_PARENT_MODE_WRITE;
- } else {
- descriptors[ndesc].parentend = newpipe[0];
- descriptors[ndesc].childend = newpipe[1];
- }
- descriptors[ndesc].mode_flags = descriptors[ndesc].mode & DESC_PARENT_MODE_WRITE ? O_WRONLY : O_RDONLY;
-
- } else if (strcmp(Z_STRVAL_P(ztype), "file") == 0) {
- zval *zfile, *zmode;
- php_socket_t fd;
- php_stream *stream;
-
- descriptors[ndesc].mode = DESC_FILE;
-
- if ((zfile = zend_hash_index_find(Z_ARRVAL_P(descitem), 1)) != NULL) {
- if (!try_convert_to_string(zfile)) {
- goto exit_fail;
- }
- } else {
- php_swoole_fatal_error(E_WARNING, "Missing file name parameter for 'file'");
- goto exit_fail;
- }
-
- if ((zmode = zend_hash_index_find(Z_ARRVAL_P(descitem), 2)) != NULL) {
- if (!try_convert_to_string(zmode)) {
- goto exit_fail;
- }
- } else {
- php_swoole_fatal_error(E_WARNING, "Missing mode parameter for 'file'");
- goto exit_fail;
- }
-
- /* try a wrapper */
- stream = php_stream_open_wrapper(
- Z_STRVAL_P(zfile), Z_STRVAL_P(zmode), REPORT_ERRORS | STREAM_WILL_CAST, NULL);
-
- /* force into an fd */
- if (stream == NULL ||
- FAILURE == php_stream_cast(
- stream, PHP_STREAM_CAST_RELEASE | PHP_STREAM_AS_FD, (void **) &fd, REPORT_ERRORS)) {
- goto exit_fail;
- }
-
- descriptors[ndesc].childend = fd;
- } else if (strcmp(Z_STRVAL_P(ztype), "redirect") == 0) {
- zval *ztarget = zend_hash_index_find_deref(Z_ARRVAL_P(descitem), 1);
- struct php_proc_open_descriptor_item *target = NULL;
- php_file_descriptor_t childend;
-
- if (!ztarget) {
- php_error_docref(NULL, E_WARNING, "Missing redirection target");
- goto exit_fail;
- }
- if (Z_TYPE_P(ztarget) != IS_LONG) {
- php_error_docref(NULL, E_WARNING, "Redirection target must be an integer");
- goto exit_fail;
- }
-
- for (i = 0; i < ndesc; i++) {
- if (descriptors[i].index == Z_LVAL_P(ztarget)) {
- target = &descriptors[i];
- break;
- }
- }
- if (target) {
- childend = target->childend;
- } else {
- if (Z_LVAL_P(ztarget) < 0 || Z_LVAL_P(ztarget) > 2) {
- php_error_docref(
- NULL, E_WARNING, "Redirection target " ZEND_LONG_FMT " not found", Z_LVAL_P(ztarget));
- goto exit_fail;
- }
-
- /* Support referring to a stdin/stdout/stderr pipe adopted from the parent,
- * which happens whenever an explicit override is not provided. */
-#ifndef PHP_WIN32
- childend = Z_LVAL_P(ztarget);
-#else
- switch (Z_LVAL_P(ztarget)) {
- case 0:
- childend = GetStdHandle(STD_INPUT_HANDLE);
- break;
- case 1:
- childend = GetStdHandle(STD_OUTPUT_HANDLE);
- break;
- case 2:
- childend = GetStdHandle(STD_ERROR_HANDLE);
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
-#endif
- }
+ cmdw = php_win32_cp_conv_any_to_w(ZSTR_VAL(command_str), ZSTR_LEN(command_str), &cmdw_len);
+ if (!cmdw) {
+ php_error_docref(NULL, E_WARNING, "Command conversion failed");
+ goto exit_fail;
+ }
-#ifdef PHP_WIN32
- descriptors[ndesc].childend = dup_handle(childend, TRUE, FALSE);
- if (descriptors[ndesc].childend == NULL) {
- php_error_docref(NULL, E_WARNING, "Failed to dup() for descriptor " ZEND_LONG_FMT, nindex);
- goto exit_fail;
- }
-#else
- descriptors[ndesc].childend = dup(childend);
- if (descriptors[ndesc].childend < 0) {
- php_error_docref(NULL,
- E_WARNING,
- "Failed to dup() for descriptor " ZEND_LONG_FMT " - %s",
- nindex,
- strerror(errno));
- goto exit_fail;
- }
-#endif
- descriptors[ndesc].mode = DESC_REDIRECT;
- } else if (strcmp(Z_STRVAL_P(ztype), "null") == 0) {
-#ifndef PHP_WIN32
- descriptors[ndesc].childend = open("/dev/null", O_RDWR);
- if (descriptors[ndesc].childend < 0) {
- php_error_docref(NULL, E_WARNING, "Failed to open /dev/null - %s", strerror(errno));
- goto exit_fail;
- }
-#else
- descriptors[ndesc].childend = CreateFileA("nul",
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL);
- if (descriptors[ndesc].childend == NULL) {
- php_error_docref(NULL, E_WARNING, "Failed to open nul");
- goto exit_fail;
- }
-#endif
- descriptors[ndesc].mode = DESC_FILE;
- } else if (strcmp(Z_STRVAL_P(ztype), "pty") == 0) {
- php_swoole_fatal_error(E_WARNING, "pty pseudo terminal not supported on this system");
- goto exit_fail;
- } else {
- php_swoole_fatal_error(E_WARNING, "%s is not a valid descriptor spec/mode", Z_STRVAL_P(ztype));
- goto exit_fail;
- }
+ if (!bypass_shell) {
+ if (convert_command_to_use_shell(&cmdw, cmdw_len) == FAILURE) {
+ goto exit_fail;
}
- ndesc++;
}
- ZEND_HASH_FOREACH_END();
+ newprocok = CreateProcessW(
+ NULL, cmdw, &php_proc_open_security, &php_proc_open_security, TRUE, dwCreateFlags, envpw, cwdw, &si, &pi);
- /* the unix way */
+ if (suppress_errors) {
+ SetErrorMode(old_error_mode);
+ }
+
+ if (newprocok == FALSE) {
+ DWORD dw = GetLastError();
+ close_all_descriptors(descriptors, ndesc);
+ php_error_docref(NULL, E_WARNING, "CreateProcess failed, error code: %u", dw);
+ goto exit_fail;
+ }
+
+ childHandle = pi.hProcess;
+ child = pi.dwProcessId;
+ CloseHandle(pi.hThread);
+#elif defined(USE_POSIX_SPAWN)
+ posix_spawn_file_actions_t factions;
+ int r;
+ posix_spawn_file_actions_init(&factions);
+
+ if (close_parentends_of_pipes(&factions, descriptors, ndesc) == FAILURE) {
+ posix_spawn_file_actions_destroy(&factions);
+ close_all_descriptors(descriptors, ndesc);
+ goto exit_fail;
+ }
+
+ if (cwd) {
+ r = posix_spawn_file_actions_addchdir_np(&factions, cwd);
+ if (r != 0) {
+ php_error_docref(NULL, E_WARNING, "posix_spawn_file_actions_addchdir_np() failed: %s", strerror(r));
+ }
+ }
+
+ if (argv) {
+ r = posix_spawnp(&child, ZSTR_VAL(command_str), &factions, NULL, argv, (env.envarray ? env.envarray : environ));
+ } else {
+ r = posix_spawn(&child,
+ "/bin/sh",
+ &factions,
+ NULL,
+ (char *const[]){"sh", "-c", ZSTR_VAL(command_str), NULL},
+ env.envarray ? env.envarray : environ);
+ }
+ posix_spawn_file_actions_destroy(&factions);
+ if (r != 0) {
+ close_all_descriptors(descriptors, ndesc);
+ php_error_docref(NULL, E_WARNING, "posix_spawn() failed: %s", strerror(r));
+ goto exit_fail;
+ }
+#elif HAVE_FORK
+ /* the Unix way */
child = swoole_fork(SW_FORK_EXEC);
if (child == 0) {
- /* this is the child process */
-
- /* close those descriptors that we just opened for the parent stuff,
- * dup new descriptors into required descriptors and close the original
- * cruft */
- for (i = 0; i < ndesc; i++) {
- switch (descriptors[i].mode & ~DESC_PARENT_MODE_WRITE) {
- case DESC_PIPE:
- close(descriptors[i].parentend);
- break;
- }
- if (dup2(descriptors[i].childend, descriptors[i].index) < 0) {
- perror("dup2");
- }
- if (descriptors[i].childend != descriptors[i].index) {
- close(descriptors[i].childend);
- }
+ /* This is the child process */
+
+ if (close_parentends_of_pipes(descriptors, ndesc) == FAILURE) {
+ /* We are already in child process and can't do anything to make
+ * `proc_open` return an error in the parent
+ * All we can do is exit with a non-zero (error) exit code */
+ _exit(127);
}
if (cwd) {
@@ -611,107 +1146,130 @@ PHP_FUNCTION(swoole_proc_open) {
if (env.envarray) {
environ = env.envarray;
}
- execvp(command, argv);
+ execvp(ZSTR_VAL(command_str), argv);
} else {
if (env.envarray) {
- execle("/bin/sh", "sh", "-c", command, NULL, env.envarray);
+ execle("/bin/sh", "sh", "-c", ZSTR_VAL(command_str), NULL, env.envarray);
} else {
- execl("/bin/sh", "sh", "-c", command, NULL);
+ execl("/bin/sh", "sh", "-c", ZSTR_VAL(command_str), NULL);
}
}
- _exit(127);
+ /* If execvp/execle/execl are successful, we will never reach here
+ * Display error and exit with non-zero (error) status code */
+ php_error_docref(NULL, E_WARNING, "Exec failed: %s", strerror(errno));
+ _exit(127);
} else if (child < 0) {
- /* failed to fork() */
-
- /* clean up all the descriptors */
- for (i = 0; i < ndesc; i++) {
- close(descriptors[i].childend);
- if (descriptors[i].parentend) {
- close(descriptors[i].parentend);
- }
- }
-
- php_swoole_fatal_error(E_WARNING, "fork failed - %s", strerror(errno));
-
+ /* Failed to fork() */
+ close_all_descriptors(descriptors, ndesc);
+ php_error_docref(NULL, E_WARNING, "Fork failed: %s", strerror(errno));
goto exit_fail;
}
+#else
+#error You lose (configure should not have let you get here)
+#endif
+
+ /* We forked/spawned and this is the parent */
- /* we forked/spawned and this is the parent */
pipes = zend_try_array_init(pipes);
if (!pipes) {
goto exit_fail;
}
- proc = (proc_co_t *) pemalloc(sizeof(proc_co_t), is_persistent);
- proc->is_persistent = is_persistent;
+ proc = (sw_php_process_handle *) emalloc(sizeof(sw_php_process_handle));
+ proc->command = zend_string_copy(command_str);
proc->wstatus = nullptr;
proc->running = true;
- proc->command = command;
proc->pipes = (zend_resource **) emalloc(sizeof(zend_resource *) * ndesc);
proc->npipes = ndesc;
proc->child = child;
proc->env = env;
- /* clean up all the child ends and then open streams on the parent
- * ends, where appropriate */
+ /* Clean up all the child ends and then open streams on the parent
+ * ends, where appropriate */
for (i = 0; i < ndesc; i++) {
php_stream *stream = NULL;
- close(descriptors[i].childend);
-
- switch (descriptors[i].mode & ~DESC_PARENT_MODE_WRITE) {
- case DESC_PIPE:
- stream = php_swoole_create_stream_from_socket(descriptors[i].parentend, AF_UNIX, SOCK_STREAM, 0 STREAMS_CC);
- /* mark the descriptor close-on-exec, so that it won't be inherited by potential other children */
- fcntl(descriptors[i].parentend, F_SETFD, FD_CLOEXEC);
- if (stream) {
- zval retfp;
+ close_descriptor(descriptors[i].childend);
- /* nasty hack; don't copy it */
- stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
+ if (descriptors[i].type == DESCRIPTOR_TYPE_PIPE) {
+ char *mode_string = NULL;
- php_stream_to_zval(stream, &retfp);
- (void) add_index_zval(pipes, descriptors[i].index, &retfp);
-
- proc->pipes[i] = Z_RES(retfp);
- Z_ADDREF(retfp);
+ switch (descriptors[i].mode_flags) {
+#ifdef PHP_WIN32
+ case O_WRONLY | O_BINARY:
+ mode_string = "wb";
+ break;
+ case O_RDONLY | O_BINARY:
+ mode_string = "rb";
+ break;
+#endif
+ case O_WRONLY:
+ mode_string = "w";
+ break;
+ case O_RDONLY:
+ mode_string = "r";
+ break;
+ case O_RDWR:
+ mode_string = "r+";
+ break;
}
- break;
- default:
+
+#ifdef PHP_WIN32
+ stream = php_stream_fopen_from_fd(
+ _open_osfhandle((intptr_t) descriptors[i].parentend, descriptors[i].mode_flags), mode_string, NULL);
+ php_stream_set_option(stream, PHP_STREAM_OPTION_PIPE_BLOCKING, blocking_pipes, NULL);
+#else
+ stream = php_swoole_create_stream_from_pipe(descriptors[i].parentend, mode_string, NULL STREAMS_CC);
+#endif
+ } else if (descriptors[i].type == DESCRIPTOR_TYPE_SOCKET) {
+ stream = php_swoole_create_stream_from_socket(
+ (php_socket_t) descriptors[i].parentend, AF_UNIX, SOCK_STREAM, 0 STREAMS_CC);
+ } else {
proc->pipes[i] = NULL;
}
- }
- if (argv) {
- char **arg = argv;
- while (*arg != NULL) {
- efree(*arg);
- arg++;
+ if (stream) {
+ zval retfp;
+
+ /* nasty hack; don't copy it */
+ stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
+
+ php_stream_to_zval(stream, &retfp);
+ add_index_zval(pipes, descriptors[i].index, &retfp);
+
+ proc->pipes[i] = Z_RES(retfp);
+ Z_ADDREF(retfp);
}
- efree(argv);
}
- efree(descriptors);
- ZVAL_RES(return_value, zend_register_resource(proc, le_proc_open));
- return;
+ if (1) {
+ RETVAL_RES(zend_register_resource(proc, le_proc_open));
+ } else {
+ exit_fail:
+ _php_free_envp(env);
+ RETVAL_FALSE;
+ }
-exit_fail:
- if (descriptors) {
- efree(descriptors);
+ zend_string_release_ex(command_str, false);
+#ifdef PHP_WIN32
+ free(cwdw);
+ free(cmdw);
+ free(envpw);
+#else
+ efree_argv(argv);
+#endif
+#ifdef HAVE_OPENPTY
+ if (pty_master_fd != -1) {
+ close(pty_master_fd);
}
- _php_free_envp(env, is_persistent);
- if (command) {
- pefree(command, is_persistent);
+ if (pty_slave_fd != -1) {
+ close(pty_slave_fd);
}
- if (argv) {
- char **arg = argv;
- while (*arg != NULL) {
- efree(*arg);
- arg++;
- }
- efree(argv);
+#endif
+ if (descriptors) {
+ efree(descriptors);
}
- RETURN_FALSE;
}
/* }}} */
+
diff --git a/thirdparty/php/standard/proc_open.h b/thirdparty/php/standard/proc_open.h
index 393c72591c5..5747f5968b8 100644
--- a/thirdparty/php/standard/proc_open.h
+++ b/thirdparty/php/standard/proc_open.h
@@ -1,31 +1,64 @@
+/*
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | https://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong |
+ +----------------------------------------------------------------------+
+ */
+
#include "php_swoole_cxx.h"
-extern "C"
-{
+SW_EXTERN_C_BEGIN
+void swoole_proc_open_init(int module_number);
PHP_FUNCTION(swoole_proc_open);
PHP_FUNCTION(swoole_proc_close);
PHP_FUNCTION(swoole_proc_get_status);
PHP_FUNCTION(swoole_proc_terminate);
-}
+SW_EXTERN_C_END
+#ifdef PHP_WIN32
+typedef HANDLE php_file_descriptor_t;
+typedef DWORD php_process_id_t;
+#define PHP_INVALID_FD INVALID_HANDLE_VALUE
+#else
typedef int php_file_descriptor_t;
+typedef pid_t php_process_id_t;
+#define PHP_INVALID_FD (-1)
+#endif
-void swoole_proc_open_init(int module_number);
-
-struct proc_co_env_t
-{
+/* Environment block under Win32 is a NUL terminated sequence of NUL terminated
+ * name=value strings.
+ * Under Unix, it is an argv style array. */
+typedef struct {
char *envp;
+#ifndef PHP_WIN32
char **envarray;
-};
+#endif
+} sw_php_process_env;
-struct proc_co_t
-{
- pid_t child;
+typedef struct {
bool running;
- int npipes;
int *wstatus;
+ php_process_id_t child;
+#ifdef PHP_WIN32
+ HANDLE childHandle;
+#endif
+ int npipes;
zend_resource **pipes;
- char *command;
- int is_persistent;
- proc_co_env_t env;
-};
+ zend_string *command;
+ sw_php_process_env env;
+#if HAVE_SYS_WAIT_H
+ /* We can only request the status once before it becomes unavailable.
+ * Cache the result so we can request it multiple times. */
+ int cached_exit_wait_status_value;
+ bool has_cached_exit_wait_status;
+#endif
+} sw_php_process_handle;
diff --git a/thirdparty/php/streams/plain_wrapper.c b/thirdparty/php/streams/plain_wrapper.c
index 4762dfd66a5..c4281f10687 100644
--- a/thirdparty/php/streams/plain_wrapper.c
+++ b/thirdparty/php/streams/plain_wrapper.c
@@ -170,7 +170,8 @@ typedef struct {
unsigned is_pipe_blocking:1; /* allow blocking read() on pipes, currently Windows only */
unsigned no_forced_fstat:1; /* Use fstat cache even if forced */
unsigned is_seekable:1; /* don't try and seek, if not set */
- unsigned _reserved:26;
+ unsigned can_poll:1;
+ unsigned _reserved:25;
int lock_flag; /* stores the lock state */
zend_string *temp_name; /* if non-null, this is the path to a temporary file that
@@ -234,16 +235,26 @@ static php_stream *_sw_php_stream_fopen_from_fd_int(int fd, const char *mode, co
return php_stream_alloc_rel(&sw_php_stream_stdio_ops, self, persistent_id, mode);
}
-static void detect_is_seekable(php_stdio_stream_data *self) {
+static void _sw_detect_is_seekable(php_stdio_stream_data *self) {
#if defined(S_ISFIFO) && defined(S_ISCHR)
if (self->fd >= 0 && do_fstat(self, 0) == 0) {
self->is_seekable = !(S_ISFIFO(self->sb.st_mode) || S_ISCHR(self->sb.st_mode));
self->is_pipe = S_ISFIFO(self->sb.st_mode);
+ self->can_poll = S_ISFIFO(self->sb.st_mode) || S_ISSOCK(self->sb.st_mode) || S_ISCHR(self->sb.st_mode);
+ if (self->can_poll) {
+ swoole_coroutine_socket_create(self->fd);
+ }
}
#elif defined(PHP_WIN32)
+#if PHP_VERSION_ID >= 80300
+ uintptr_t handle = _get_osfhandle(self->fd);
+
+ if (handle != (uintptr_t)INVALID_HANDLE_VALUE) {
+#else
zend_uintptr_t handle = _get_osfhandle(self->fd);
if (handle != (zend_uintptr_t)INVALID_HANDLE_VALUE) {
+#endif
DWORD file_type = GetFileType((HANDLE)handle);
self->is_seekable = !(file_type == FILE_TYPE_PIPE || file_type == FILE_TYPE_CHAR);
@@ -267,7 +278,7 @@ static php_stream *_sw_php_stream_fopen_from_fd(int fd, const char *mode, const
if (stream) {
php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract;
- detect_is_seekable(self);
+ _sw_detect_is_seekable(self);
if (!self->is_seekable) {
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
stream->position = -1;
@@ -306,7 +317,10 @@ static php_stream_size_t sw_php_stdiop_write(php_stream *stream, const char *buf
}
bytes_written = _write(data->fd, buf, (unsigned int)count);
#else
- ssize_t bytes_written = write(data->fd, buf, count);
+ php_stdio_stream_data *self = (php_stdio_stream_data*) stream->abstract;
+ ssize_t bytes_written = self->can_poll ?
+ swoole_coroutine_write(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count)) :
+ write(data->fd, buf, count);
#endif
if (bytes_written < 0) {
if (PHP_IS_TRANSIENT_ERROR(errno)) {
@@ -368,13 +382,18 @@ static php_stream_size_t sw_php_stdiop_read(php_stream *stream, char *buf, size_
}
}
#endif
- ret = read(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count));
+ php_stdio_stream_data *self = (php_stdio_stream_data*) stream->abstract;
+ ret = self->can_poll ?
+ swoole_coroutine_read(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count)) :
+ read(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count));
if (ret == (ssize_t) -1 && errno == EINTR) {
/* Read was interrupted, retry once,
- If read still fails, giveup with feof==0
- so script can retry if desired */
- ret = read(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count));
+ If read still fails, giveup with feof==0
+ so script can retry if desired */
+ ret = self->can_poll ?
+ swoole_coroutine_read(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count)) :
+ read(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count));
}
if (ret < 0) {
@@ -451,7 +470,11 @@ static int sw_php_stdiop_close(php_stream *stream, int close_handle) {
if ((data->lock_flag & LOCK_EX) || (data->lock_flag & LOCK_SH)) {
swoole_coroutine_flock_ex(stream->orig_path, data->fd, LOCK_UN);
}
- ret = close_file(data->fd);
+ if (data->can_poll) {
+ ret = swoole_coroutine_close(data->fd);
+ } else {
+ ret = close_file(data->fd);
+ }
data->fd = -1;
} else {
return 0; /* everything should be closed already -> success */
@@ -670,10 +693,15 @@ static int sw_php_stdiop_set_option(php_stream *stream, int option, int value, v
if (fd == -1) {
return -1;
}
-
+#if PHP_VERSION_ID >= 80300
+ if ((uintptr_t) ptrparam == PHP_STREAM_LOCK_SUPPORTED) {
+ return 0;
+ }
+#else
if ((zend_uintptr_t) ptrparam == PHP_STREAM_LOCK_SUPPORTED) {
return 0;
}
+#endif
if (!swoole_coroutine_flock_ex(stream->orig_path, fd, value)) {
data->lock_flag = value;
@@ -955,6 +983,13 @@ static php_stream_size_t php_plain_files_dirstream_read(php_stream *stream, char
result = readdir(dir);
if (result) {
PHP_STRLCPY(ent->d_name, result->d_name, sizeof(ent->d_name), strlen(result->d_name));
+#if PHP_VERSION_ID >= 80300
+#ifdef _DIRENT_HAVE_D_TYPE
+ ent->d_type = result->d_type;
+#else
+ ent->d_type = DT_UNKNOWN;
+#endif
+#endif
return sizeof(php_stream_dirent);
}
return 0;
diff --git a/thirdparty/php81/pdo_sqlite/sqlite_driver.c b/thirdparty/php81/pdo_sqlite/sqlite_driver.c
index 61a74de28bf..61f6948a202 100644
--- a/thirdparty/php81/pdo_sqlite/sqlite_driver.c
+++ b/thirdparty/php81/pdo_sqlite/sqlite_driver.c
@@ -16,7 +16,7 @@
#define SW_USE_SQLITE_HOOK
#include "php_swoole_sqlite.h"
-#if PHP_VERSION_ID >= 80100
+#if PHP_VERSION_ID >= 80100 && PHP_VERSION_ID < 80300
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
@@ -26,544 +26,510 @@
int _pdo_sqlite_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line) /* {{{ */
{
- pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
- pdo_error_type *pdo_err = stmt ? &stmt->error_code : &dbh->error_code;
- pdo_sqlite_error_info *einfo = &H->einfo;
-
- einfo->errcode = sqlite3_errcode(H->db);
- einfo->file = file;
- einfo->line = line;
-
- if (einfo->errcode != SQLITE_OK) {
- if (einfo->errmsg) {
- pefree(einfo->errmsg, dbh->is_persistent);
- }
- einfo->errmsg = pestrdup((char*)sqlite3_errmsg(H->db), dbh->is_persistent);
- } else { /* no error */
- strncpy(*pdo_err, PDO_ERR_NONE, sizeof(*pdo_err));
- return 0;
- }
- switch (einfo->errcode) {
- case SQLITE_NOTFOUND:
- strncpy(*pdo_err, "42S02", sizeof(*pdo_err));
- break;
-
- case SQLITE_INTERRUPT:
- strncpy(*pdo_err, "01002", sizeof(*pdo_err));
- break;
-
- case SQLITE_NOLFS:
- strncpy(*pdo_err, "HYC00", sizeof(*pdo_err));
- break;
-
- case SQLITE_TOOBIG:
- strncpy(*pdo_err, "22001", sizeof(*pdo_err));
- break;
-
- case SQLITE_CONSTRAINT:
- strncpy(*pdo_err, "23000", sizeof(*pdo_err));
- break;
-
- case SQLITE_ERROR:
- default:
- strncpy(*pdo_err, "HY000", sizeof(*pdo_err));
- break;
- }
-
- if (!dbh->methods) {
- pdo_throw_exception(einfo->errcode, einfo->errmsg, pdo_err);
- }
-
- return einfo->errcode;
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ pdo_error_type *pdo_err = stmt ? &stmt->error_code : &dbh->error_code;
+ pdo_sqlite_error_info *einfo = &H->einfo;
+
+ einfo->errcode = sqlite3_errcode(H->db);
+ einfo->file = file;
+ einfo->line = line;
+
+ if (einfo->errcode != SQLITE_OK) {
+ if (einfo->errmsg) {
+ pefree(einfo->errmsg, dbh->is_persistent);
+ }
+ einfo->errmsg = pestrdup((char *) sqlite3_errmsg(H->db), dbh->is_persistent);
+ } else { /* no error */
+ strncpy(*pdo_err, PDO_ERR_NONE, sizeof(*pdo_err));
+ return 0;
+ }
+ switch (einfo->errcode) {
+ case SQLITE_NOTFOUND:
+ strncpy(*pdo_err, "42S02", sizeof(*pdo_err));
+ break;
+
+ case SQLITE_INTERRUPT:
+ strncpy(*pdo_err, "01002", sizeof(*pdo_err));
+ break;
+
+ case SQLITE_NOLFS:
+ strncpy(*pdo_err, "HYC00", sizeof(*pdo_err));
+ break;
+
+ case SQLITE_TOOBIG:
+ strncpy(*pdo_err, "22001", sizeof(*pdo_err));
+ break;
+
+ case SQLITE_CONSTRAINT:
+ strncpy(*pdo_err, "23000", sizeof(*pdo_err));
+ break;
+
+ case SQLITE_ERROR:
+ default:
+ strncpy(*pdo_err, "HY000", sizeof(*pdo_err));
+ break;
+ }
+
+ if (!dbh->methods) {
+ pdo_throw_exception(einfo->errcode, einfo->errmsg, pdo_err);
+ }
+
+ return einfo->errcode;
}
/* }}} */
-static void pdo_sqlite_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info)
-{
- pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
- pdo_sqlite_error_info *einfo = &H->einfo;
+static void pdo_sqlite_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ pdo_sqlite_error_info *einfo = &H->einfo;
- if (einfo->errcode) {
- add_next_index_long(info, einfo->errcode);
- add_next_index_string(info, einfo->errmsg);
- }
+ if (einfo->errcode) {
+ add_next_index_long(info, einfo->errcode);
+ add_next_index_string(info, einfo->errmsg);
+ }
}
-static void pdo_sqlite_cleanup_callbacks(pdo_sqlite_db_handle *H)
-{
- struct pdo_sqlite_func *func;
-
- while (H->funcs) {
- func = H->funcs;
- H->funcs = func->next;
-
- if (H->db) {
- /* delete the function from the handle */
- sqlite3_create_function(H->db,
- func->funcname,
- func->argc,
- SQLITE_UTF8,
- func,
- NULL, NULL, NULL);
- }
-
- efree((char*)func->funcname);
- if (!Z_ISUNDEF(func->func)) {
- zval_ptr_dtor(&func->func);
- }
- if (!Z_ISUNDEF(func->step)) {
- zval_ptr_dtor(&func->step);
- }
- if (!Z_ISUNDEF(func->fini)) {
- zval_ptr_dtor(&func->fini);
- }
- efree(func);
- }
-
- while (H->collations) {
- struct pdo_sqlite_collation *collation;
- collation = H->collations;
- H->collations = collation->next;
-
- if (H->db) {
- /* delete the collation from the handle */
- sqlite3_create_collation(H->db,
- collation->name,
- SQLITE_UTF8,
- collation,
- NULL);
- }
-
- efree((char*)collation->name);
- if (!Z_ISUNDEF(collation->callback)) {
- zval_ptr_dtor(&collation->callback);
- }
- efree(collation);
- }
+static void pdo_sqlite_cleanup_callbacks(pdo_sqlite_db_handle *H) {
+ struct pdo_sqlite_func *func;
+
+ while (H->funcs) {
+ func = H->funcs;
+ H->funcs = func->next;
+
+ if (H->db) {
+ /* delete the function from the handle */
+ sqlite3_create_function(H->db, func->funcname, func->argc, SQLITE_UTF8, func, NULL, NULL, NULL);
+ }
+
+ efree((char *) func->funcname);
+ if (!Z_ISUNDEF(func->func)) {
+ zval_ptr_dtor(&func->func);
+ }
+ if (!Z_ISUNDEF(func->step)) {
+ zval_ptr_dtor(&func->step);
+ }
+ if (!Z_ISUNDEF(func->fini)) {
+ zval_ptr_dtor(&func->fini);
+ }
+ efree(func);
+ }
+
+ while (H->collations) {
+ struct pdo_sqlite_collation *collation;
+ collation = H->collations;
+ H->collations = collation->next;
+
+ if (H->db) {
+ /* delete the collation from the handle */
+ sqlite3_create_collation(H->db, collation->name, SQLITE_UTF8, collation, NULL);
+ }
+
+ efree((char *) collation->name);
+ if (!Z_ISUNDEF(collation->callback)) {
+ zval_ptr_dtor(&collation->callback);
+ }
+ efree(collation);
+ }
}
static void sqlite_handle_closer(pdo_dbh_t *dbh) /* {{{ */
{
- pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
- if (H) {
- pdo_sqlite_error_info *einfo = &H->einfo;
+ if (H) {
+ pdo_sqlite_error_info *einfo = &H->einfo;
- pdo_sqlite_cleanup_callbacks(H);
- if (H->db) {
+ pdo_sqlite_cleanup_callbacks(H);
+ if (H->db) {
#ifdef HAVE_SW_SQLITE3_CLOSE_V2
- sqlite3_close_v2(H->db);
+ sqlite3_close_v2(H->db);
#else
- sqlite3_close(H->db);
+ sqlite3_close(H->db);
#endif
- H->db = NULL;
- }
- if (einfo->errmsg) {
- pefree(einfo->errmsg, dbh->is_persistent);
- einfo->errmsg = NULL;
- }
- pefree(H, dbh->is_persistent);
- dbh->driver_data = NULL;
- }
+ H->db = NULL;
+ }
+ if (einfo->errmsg) {
+ pefree(einfo->errmsg, dbh->is_persistent);
+ einfo->errmsg = NULL;
+ }
+ pefree(H, dbh->is_persistent);
+ dbh->driver_data = NULL;
+ }
}
/* }}} */
-static bool sqlite_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *stmt, zval *driver_options)
-{
- pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
- pdo_sqlite_stmt *S = ecalloc(1, sizeof(pdo_sqlite_stmt));
- int i;
- const char *tail;
-
- S->H = H;
- stmt->driver_data = S;
- stmt->methods = &swoole_sqlite_stmt_methods;
- stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL|PDO_PLACEHOLDER_NAMED;
-
- if (PDO_CURSOR_FWDONLY != pdo_attr_lval(driver_options, PDO_ATTR_CURSOR, PDO_CURSOR_FWDONLY)) {
- H->einfo.errcode = SQLITE_ERROR;
- pdo_sqlite_error(dbh);
- return false;
- }
-
- i = sqlite3_prepare_v2(H->db, ZSTR_VAL(sql), ZSTR_LEN(sql), &S->stmt, &tail);
- if (i == SQLITE_OK) {
- return true;
- }
-
- pdo_sqlite_error(dbh);
-
- return false;
+static bool sqlite_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *stmt, zval *driver_options) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ pdo_sqlite_stmt *S = ecalloc(1, sizeof(pdo_sqlite_stmt));
+ int i;
+ const char *tail;
+
+ S->H = H;
+ stmt->driver_data = S;
+ stmt->methods = &swoole_sqlite_stmt_methods;
+ stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL | PDO_PLACEHOLDER_NAMED;
+
+ if (PDO_CURSOR_FWDONLY != pdo_attr_lval(driver_options, PDO_ATTR_CURSOR, PDO_CURSOR_FWDONLY)) {
+ H->einfo.errcode = SQLITE_ERROR;
+ pdo_sqlite_error(dbh);
+ return false;
+ }
+
+ i = sqlite3_prepare_v2(H->db, ZSTR_VAL(sql), ZSTR_LEN(sql), &S->stmt, &tail);
+ if (i == SQLITE_OK) {
+ return true;
+ }
+
+ pdo_sqlite_error(dbh);
+
+ return false;
}
-static zend_long sqlite_handle_doer(pdo_dbh_t *dbh, const zend_string *sql)
-{
- pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
- char *errmsg = NULL;
-
- if (sqlite3_exec(H->db, ZSTR_VAL(sql), NULL, NULL, &errmsg) != SQLITE_OK) {
- pdo_sqlite_error(dbh);
- if (errmsg)
- sqlite3_free(errmsg);
-
- return -1;
- } else {
- return sqlite3_changes(H->db);
- }
+static zend_long sqlite_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ char *errmsg = NULL;
+
+ if (sqlite3_exec(H->db, ZSTR_VAL(sql), NULL, NULL, &errmsg) != SQLITE_OK) {
+ pdo_sqlite_error(dbh);
+ if (errmsg) sqlite3_free(errmsg);
+
+ return -1;
+ } else {
+ return sqlite3_changes(H->db);
+ }
}
-static zend_string *pdo_sqlite_last_insert_id(pdo_dbh_t *dbh, const zend_string *name)
-{
- pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
+static zend_string *pdo_sqlite_last_insert_id(pdo_dbh_t *dbh, const zend_string *name) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
- return zend_i64_to_str(sqlite3_last_insert_rowid(H->db));
+ return zend_i64_to_str(sqlite3_last_insert_rowid(H->db));
}
/* NB: doesn't handle binary strings... use prepared stmts for that */
-static zend_string* sqlite_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquoted, enum pdo_param_type paramtype)
-{
- char *quoted;
- if (ZSTR_LEN(unquoted) > (INT_MAX - 3) / 2) {
- return NULL;
- }
- quoted = safe_emalloc(2, ZSTR_LEN(unquoted), 3);
- /* TODO use %Q format? */
- sqlite3_snprintf(2*ZSTR_LEN(unquoted) + 3, quoted, "'%q'", ZSTR_VAL(unquoted));
- zend_string *quoted_str = zend_string_init(quoted, strlen(quoted), 0);
- efree(quoted);
- return quoted_str;
+static zend_string *sqlite_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquoted, enum pdo_param_type paramtype) {
+ char *quoted;
+ if (ZSTR_LEN(unquoted) > (INT_MAX - 3) / 2) {
+ return NULL;
+ }
+ quoted = safe_emalloc(2, ZSTR_LEN(unquoted), 3);
+ /* TODO use %Q format? */
+ sqlite3_snprintf(2 * ZSTR_LEN(unquoted) + 3, quoted, "'%q'", ZSTR_VAL(unquoted));
+ zend_string *quoted_str = zend_string_init(quoted, strlen(quoted), 0);
+ efree(quoted);
+ return quoted_str;
}
-static bool sqlite_handle_begin(pdo_dbh_t *dbh)
-{
- pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
- char *errmsg = NULL;
-
- if (sqlite3_exec(H->db, "BEGIN", NULL, NULL, &errmsg) != SQLITE_OK) {
- pdo_sqlite_error(dbh);
- if (errmsg)
- sqlite3_free(errmsg);
- return false;
- }
- return true;
+static bool sqlite_handle_begin(pdo_dbh_t *dbh) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ char *errmsg = NULL;
+
+ if (sqlite3_exec(H->db, "BEGIN", NULL, NULL, &errmsg) != SQLITE_OK) {
+ pdo_sqlite_error(dbh);
+ if (errmsg) sqlite3_free(errmsg);
+ return false;
+ }
+ return true;
}
-static bool sqlite_handle_commit(pdo_dbh_t *dbh)
-{
- pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
- char *errmsg = NULL;
-
- if (sqlite3_exec(H->db, "COMMIT", NULL, NULL, &errmsg) != SQLITE_OK) {
- pdo_sqlite_error(dbh);
- if (errmsg)
- sqlite3_free(errmsg);
- return false;
- }
- return true;
+static bool sqlite_handle_commit(pdo_dbh_t *dbh) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ char *errmsg = NULL;
+
+ if (sqlite3_exec(H->db, "COMMIT", NULL, NULL, &errmsg) != SQLITE_OK) {
+ pdo_sqlite_error(dbh);
+ if (errmsg) sqlite3_free(errmsg);
+ return false;
+ }
+ return true;
}
-static bool sqlite_handle_rollback(pdo_dbh_t *dbh)
-{
- pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
- char *errmsg = NULL;
-
- if (sqlite3_exec(H->db, "ROLLBACK", NULL, NULL, &errmsg) != SQLITE_OK) {
- pdo_sqlite_error(dbh);
- if (errmsg)
- sqlite3_free(errmsg);
- return false;
- }
- return true;
+static bool sqlite_handle_rollback(pdo_dbh_t *dbh) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ char *errmsg = NULL;
+
+ if (sqlite3_exec(H->db, "ROLLBACK", NULL, NULL, &errmsg) != SQLITE_OK) {
+ pdo_sqlite_error(dbh);
+ if (errmsg) sqlite3_free(errmsg);
+ return false;
+ }
+ return true;
}
-static int pdo_sqlite_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_value)
-{
- switch (attr) {
- case PDO_ATTR_CLIENT_VERSION:
- case PDO_ATTR_SERVER_VERSION:
- ZVAL_STRING(return_value, (char *)sqlite3_libversion());
- break;
+static int pdo_sqlite_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_value) {
+ switch (attr) {
+ case PDO_ATTR_CLIENT_VERSION:
+ case PDO_ATTR_SERVER_VERSION:
+ ZVAL_STRING(return_value, (char *) sqlite3_libversion());
+ break;
- default:
- return 0;
- }
+ default:
+ return 0;
+ }
- return 1;
+ return 1;
}
-static bool pdo_sqlite_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
-{
- pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
- zend_long lval;
-
- switch (attr) {
- case PDO_ATTR_TIMEOUT:
- if (!pdo_get_long_param(&lval, val)) {
- return false;
- }
- sqlite3_busy_timeout(H->db, lval * 1000);
- return true;
- case PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES:
- if (!pdo_get_long_param(&lval, val)) {
- return false;
- }
- sqlite3_extended_result_codes(H->db, lval);
- return true;
- }
- return false;
+static bool pdo_sqlite_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ zend_long lval;
+
+ switch (attr) {
+ case PDO_ATTR_TIMEOUT:
+ if (!pdo_get_long_param(&lval, val)) {
+ return false;
+ }
+ sqlite3_busy_timeout(H->db, lval * 1000);
+ return true;
+ case PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES:
+ if (!pdo_get_long_param(&lval, val)) {
+ return false;
+ }
+ sqlite3_extended_result_codes(H->db, lval);
+ return true;
+ }
+ return false;
}
typedef struct {
- zval val;
- zend_long row;
+ zval val;
+ zend_long row;
} aggregate_context;
-static int do_callback(struct pdo_sqlite_fci *fc, zval *cb,
- int argc, sqlite3_value **argv, sqlite3_context *context,
- int is_agg)
-{
- zval *zargs = NULL;
- zval retval;
- int i;
- int ret;
- int fake_argc;
- aggregate_context *agg_context = NULL;
-
- if (is_agg) {
- is_agg = 2;
- }
-
- fake_argc = argc + is_agg;
-
- fc->fci.size = sizeof(fc->fci);
- ZVAL_COPY_VALUE(&fc->fci.function_name, cb);
- fc->fci.object = NULL;
- fc->fci.retval = &retval;
- fc->fci.param_count = fake_argc;
-
- /* build up the params */
-
- if (fake_argc) {
- zargs = safe_emalloc(fake_argc, sizeof(zval), 0);
- }
-
- if (is_agg) {
- agg_context = sqlite3_aggregate_context(context, sizeof(aggregate_context));
- if (!agg_context) {
- efree(zargs);
- return FAILURE;
- }
- if (Z_ISUNDEF(agg_context->val)) {
- ZVAL_NEW_REF(&agg_context->val, &EG(uninitialized_zval));
- }
- ZVAL_COPY_VALUE(&zargs[0], &agg_context->val);
- ZVAL_LONG(&zargs[1], ++agg_context->row);
- }
-
- for (i = 0; i < argc; i++) {
- /* get the value */
- switch (sqlite3_value_type(argv[i])) {
- case SQLITE_INTEGER:
- ZVAL_LONG(&zargs[i + is_agg], sqlite3_value_int(argv[i]));
- break;
-
- case SQLITE_FLOAT:
- ZVAL_DOUBLE(&zargs[i + is_agg], sqlite3_value_double(argv[i]));
- break;
-
- case SQLITE_NULL:
- ZVAL_NULL(&zargs[i + is_agg]);
- break;
-
- case SQLITE_BLOB:
- case SQLITE3_TEXT:
- default:
- ZVAL_STRINGL(&zargs[i + is_agg], (char*)sqlite3_value_text(argv[i]), sqlite3_value_bytes(argv[i]));
- break;
- }
- }
-
- fc->fci.params = zargs;
-
- if ((ret = zend_call_function(&fc->fci, &fc->fcc)) == FAILURE) {
- php_error_docref(NULL, E_WARNING, "An error occurred while invoking the callback");
- }
-
- /* clean up the params */
- if (zargs) {
- for (i = is_agg; i < fake_argc; i++) {
- zval_ptr_dtor(&zargs[i]);
- }
- if (is_agg) {
- zval_ptr_dtor(&zargs[1]);
- }
- efree(zargs);
- }
-
- if (!is_agg || !argv) {
- /* only set the sqlite return value if we are a scalar function,
- * or if we are finalizing an aggregate */
- if (!Z_ISUNDEF(retval)) {
- switch (Z_TYPE(retval)) {
- case IS_LONG:
- sqlite3_result_int(context, Z_LVAL(retval));
- break;
-
- case IS_NULL:
- sqlite3_result_null(context);
- break;
-
- case IS_DOUBLE:
- sqlite3_result_double(context, Z_DVAL(retval));
- break;
-
- default:
- if (!try_convert_to_string(&retval)) {
- ret = FAILURE;
- break;
- }
- sqlite3_result_text(context, Z_STRVAL(retval), Z_STRLEN(retval), SQLITE_TRANSIENT);
- break;
- }
- } else {
- sqlite3_result_error(context, "failed to invoke callback", 0);
- }
-
- if (agg_context) {
- zval_ptr_dtor(&agg_context->val);
- }
- } else {
- /* we're stepping in an aggregate; the return value goes into
- * the context */
- if (agg_context) {
- if (Z_ISUNDEF(retval)) {
- zval_ptr_dtor(&agg_context->val);
- return FAILURE;
- }
- zval_ptr_dtor(Z_REFVAL(agg_context->val));
- ZVAL_COPY_VALUE(Z_REFVAL(agg_context->val), &retval);
- ZVAL_UNDEF(&retval);
- }
- }
-
- if (!Z_ISUNDEF(retval)) {
- zval_ptr_dtor(&retval);
- }
-
- return ret;
+static int do_callback(
+ struct pdo_sqlite_fci *fc, zval *cb, int argc, sqlite3_value **argv, sqlite3_context *context, int is_agg) {
+ zval *zargs = NULL;
+ zval retval;
+ int i;
+ int ret;
+ int fake_argc;
+ aggregate_context *agg_context = NULL;
+
+ if (is_agg) {
+ is_agg = 2;
+ }
+
+ fake_argc = argc + is_agg;
+
+ fc->fci.size = sizeof(fc->fci);
+ ZVAL_COPY_VALUE(&fc->fci.function_name, cb);
+ fc->fci.object = NULL;
+ fc->fci.retval = &retval;
+ fc->fci.param_count = fake_argc;
+
+ /* build up the params */
+
+ if (fake_argc) {
+ zargs = safe_emalloc(fake_argc, sizeof(zval), 0);
+ }
+
+ if (is_agg) {
+ agg_context = sqlite3_aggregate_context(context, sizeof(aggregate_context));
+ if (!agg_context) {
+ efree(zargs);
+ return FAILURE;
+ }
+ if (Z_ISUNDEF(agg_context->val)) {
+ ZVAL_NEW_REF(&agg_context->val, &EG(uninitialized_zval));
+ }
+ ZVAL_COPY_VALUE(&zargs[0], &agg_context->val);
+ ZVAL_LONG(&zargs[1], ++agg_context->row);
+ }
+
+ for (i = 0; i < argc; i++) {
+ /* get the value */
+ switch (sqlite3_value_type(argv[i])) {
+ case SQLITE_INTEGER:
+ ZVAL_LONG(&zargs[i + is_agg], sqlite3_value_int(argv[i]));
+ break;
+
+ case SQLITE_FLOAT:
+ ZVAL_DOUBLE(&zargs[i + is_agg], sqlite3_value_double(argv[i]));
+ break;
+
+ case SQLITE_NULL:
+ ZVAL_NULL(&zargs[i + is_agg]);
+ break;
+
+ case SQLITE_BLOB:
+ case SQLITE3_TEXT:
+ default:
+ ZVAL_STRINGL(&zargs[i + is_agg], (char *) sqlite3_value_text(argv[i]), sqlite3_value_bytes(argv[i]));
+ break;
+ }
+ }
+
+ fc->fci.params = zargs;
+
+ if ((ret = zend_call_function(&fc->fci, &fc->fcc)) == FAILURE) {
+ php_error_docref(NULL, E_WARNING, "An error occurred while invoking the callback");
+ }
+
+ /* clean up the params */
+ if (zargs) {
+ for (i = is_agg; i < fake_argc; i++) {
+ zval_ptr_dtor(&zargs[i]);
+ }
+ if (is_agg) {
+ zval_ptr_dtor(&zargs[1]);
+ }
+ efree(zargs);
+ }
+
+ if (!is_agg || !argv) {
+ /* only set the sqlite return value if we are a scalar function,
+ * or if we are finalizing an aggregate */
+ if (!Z_ISUNDEF(retval)) {
+ switch (Z_TYPE(retval)) {
+ case IS_LONG:
+ sqlite3_result_int(context, Z_LVAL(retval));
+ break;
+
+ case IS_NULL:
+ sqlite3_result_null(context);
+ break;
+
+ case IS_DOUBLE:
+ sqlite3_result_double(context, Z_DVAL(retval));
+ break;
+
+ default:
+ if (!try_convert_to_string(&retval)) {
+ ret = FAILURE;
+ break;
+ }
+ sqlite3_result_text(context, Z_STRVAL(retval), Z_STRLEN(retval), SQLITE_TRANSIENT);
+ break;
+ }
+ } else {
+ sqlite3_result_error(context, "failed to invoke callback", 0);
+ }
+
+ if (agg_context) {
+ zval_ptr_dtor(&agg_context->val);
+ }
+ } else {
+ /* we're stepping in an aggregate; the return value goes into
+ * the context */
+ if (agg_context) {
+ if (Z_ISUNDEF(retval)) {
+ zval_ptr_dtor(&agg_context->val);
+ return FAILURE;
+ }
+ zval_ptr_dtor(Z_REFVAL(agg_context->val));
+ ZVAL_COPY_VALUE(Z_REFVAL(agg_context->val), &retval);
+ ZVAL_UNDEF(&retval);
+ }
+ }
+
+ if (!Z_ISUNDEF(retval)) {
+ zval_ptr_dtor(&retval);
+ }
+
+ return ret;
}
-static void php_sqlite3_func_callback(sqlite3_context *context, int argc,
- sqlite3_value **argv)
-{
- struct pdo_sqlite_func *func = (struct pdo_sqlite_func*)sqlite3_user_data(context);
+static void php_sqlite3_func_callback(sqlite3_context *context, int argc, sqlite3_value **argv) {
+ struct pdo_sqlite_func *func = (struct pdo_sqlite_func *) sqlite3_user_data(context);
- do_callback(&func->afunc, &func->func, argc, argv, context, 0);
+ do_callback(&func->afunc, &func->func, argc, argv, context, 0);
}
-static void php_sqlite3_func_step_callback(sqlite3_context *context, int argc,
- sqlite3_value **argv)
-{
- struct pdo_sqlite_func *func = (struct pdo_sqlite_func*)sqlite3_user_data(context);
+static void php_sqlite3_func_step_callback(sqlite3_context *context, int argc, sqlite3_value **argv) {
+ struct pdo_sqlite_func *func = (struct pdo_sqlite_func *) sqlite3_user_data(context);
- do_callback(&func->astep, &func->step, argc, argv, context, 1);
+ do_callback(&func->astep, &func->step, argc, argv, context, 1);
}
-static void php_sqlite3_func_final_callback(sqlite3_context *context)
-{
- struct pdo_sqlite_func *func = (struct pdo_sqlite_func*)sqlite3_user_data(context);
+static void php_sqlite3_func_final_callback(sqlite3_context *context) {
+ struct pdo_sqlite_func *func = (struct pdo_sqlite_func *) sqlite3_user_data(context);
- do_callback(&func->afini, &func->fini, 0, NULL, context, 1);
+ do_callback(&func->afini, &func->fini, 0, NULL, context, 1);
}
-static int php_sqlite3_collation_callback(void *context,
- int string1_len, const void *string1,
- int string2_len, const void *string2)
-{
- int ret;
- zval zargs[2];
- zval retval;
- struct pdo_sqlite_collation *collation = (struct pdo_sqlite_collation*) context;
-
- collation->fc.fci.size = sizeof(collation->fc.fci);
- ZVAL_COPY_VALUE(&collation->fc.fci.function_name, &collation->callback);
- collation->fc.fci.object = NULL;
- collation->fc.fci.retval = &retval;
-
- // Prepare the arguments.
- ZVAL_STRINGL(&zargs[0], (char *) string1, string1_len);
- ZVAL_STRINGL(&zargs[1], (char *) string2, string2_len);
- collation->fc.fci.param_count = 2;
- collation->fc.fci.params = zargs;
-
- if ((ret = zend_call_function(&collation->fc.fci, &collation->fc.fcc)) == FAILURE) {
- php_error_docref(NULL, E_WARNING, "An error occurred while invoking the callback");
- } else if (!Z_ISUNDEF(retval)) {
- if (Z_TYPE(retval) != IS_LONG) {
- convert_to_long(&retval);
- }
- ret = 0;
- if (Z_LVAL(retval) > 0) {
- ret = 1;
- } else if (Z_LVAL(retval) < 0) {
- ret = -1;
- }
- zval_ptr_dtor(&retval);
- }
-
- zval_ptr_dtor(&zargs[0]);
- zval_ptr_dtor(&zargs[1]);
-
- return ret;
+static int php_sqlite3_collation_callback(
+ void *context, int string1_len, const void *string1, int string2_len, const void *string2) {
+ int ret;
+ zval zargs[2];
+ zval retval;
+ struct pdo_sqlite_collation *collation = (struct pdo_sqlite_collation *) context;
+
+ collation->fc.fci.size = sizeof(collation->fc.fci);
+ ZVAL_COPY_VALUE(&collation->fc.fci.function_name, &collation->callback);
+ collation->fc.fci.object = NULL;
+ collation->fc.fci.retval = &retval;
+
+ // Prepare the arguments.
+ ZVAL_STRINGL(&zargs[0], (char *) string1, string1_len);
+ ZVAL_STRINGL(&zargs[1], (char *) string2, string2_len);
+ collation->fc.fci.param_count = 2;
+ collation->fc.fci.params = zargs;
+
+ if ((ret = zend_call_function(&collation->fc.fci, &collation->fc.fcc)) == FAILURE) {
+ php_error_docref(NULL, E_WARNING, "An error occurred while invoking the callback");
+ } else if (!Z_ISUNDEF(retval)) {
+ if (Z_TYPE(retval) != IS_LONG) {
+ convert_to_long(&retval);
+ }
+ ret = 0;
+ if (Z_LVAL(retval) > 0) {
+ ret = 1;
+ } else if (Z_LVAL(retval) < 0) {
+ ret = -1;
+ }
+ zval_ptr_dtor(&retval);
+ }
+
+ zval_ptr_dtor(&zargs[0]);
+ zval_ptr_dtor(&zargs[1]);
+
+ return ret;
}
/* {{{ bool SQLite::sqliteCreateFunction(string name, callable callback [, int argcount, int flags])
Registers a UDF with the sqlite db handle */
-PHP_METHOD(PDO_SQLite_Ext, sqliteCreateFunction)
-{
- struct pdo_sqlite_func *func;
- zend_fcall_info fci;
- zend_fcall_info_cache fcc;
- char *func_name;
- size_t func_name_len;
- zend_long argc = -1;
- zend_long flags = 0;
- pdo_dbh_t *dbh;
- pdo_sqlite_db_handle *H;
- int ret;
-
- ZEND_PARSE_PARAMETERS_START(2, 4)
- Z_PARAM_STRING(func_name, func_name_len)
- Z_PARAM_FUNC(fci, fcc)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(argc)
- Z_PARAM_LONG(flags)
- ZEND_PARSE_PARAMETERS_END();
-
- dbh = Z_PDO_DBH_P(ZEND_THIS);
- PDO_CONSTRUCT_CHECK;
-
- H = (pdo_sqlite_db_handle *)dbh->driver_data;
-
- func = (struct pdo_sqlite_func*)ecalloc(1, sizeof(*func));
-
- ret = sqlite3_create_function(H->db, func_name, argc, flags | SQLITE_UTF8,
- func, php_sqlite3_func_callback, NULL, NULL);
- if (ret == SQLITE_OK) {
- func->funcname = estrdup(func_name);
-
- ZVAL_COPY(&func->func, &fci.function_name);
-
- func->argc = argc;
-
- func->next = H->funcs;
- H->funcs = func;
-
- RETURN_TRUE;
- }
-
- efree(func);
- RETURN_FALSE;
+PHP_METHOD(PDO_SQLite_Ext, sqliteCreateFunction) {
+ struct pdo_sqlite_func *func;
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ char *func_name;
+ size_t func_name_len;
+ zend_long argc = -1;
+ zend_long flags = 0;
+ pdo_dbh_t *dbh;
+ pdo_sqlite_db_handle *H;
+ int ret;
+
+ ZEND_PARSE_PARAMETERS_START(2, 4)
+ Z_PARAM_STRING(func_name, func_name_len)
+ Z_PARAM_FUNC(fci, fcc)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_LONG(argc)
+ Z_PARAM_LONG(flags)
+ ZEND_PARSE_PARAMETERS_END();
+
+ dbh = Z_PDO_DBH_P(ZEND_THIS);
+ PDO_CONSTRUCT_CHECK;
+
+ H = (pdo_sqlite_db_handle *) dbh->driver_data;
+
+ func = (struct pdo_sqlite_func *) ecalloc(1, sizeof(*func));
+
+ ret = sqlite3_create_function(
+ H->db, func_name, argc, flags | SQLITE_UTF8, func, php_sqlite3_func_callback, NULL, NULL);
+ if (ret == SQLITE_OK) {
+ func->funcname = estrdup(func_name);
+
+ ZVAL_COPY(&func->func, &fci.function_name);
+
+ func->argc = argc;
+
+ func->next = H->funcs;
+ H->funcs = func;
+
+ RETURN_TRUE;
+ }
+
+ efree(func);
+ RETURN_FALSE;
}
/* }}} */
@@ -586,274 +552,266 @@ PHP_METHOD(PDO_SQLite_Ext, sqliteCreateFunction)
aggregate UDF.
*/
-PHP_METHOD(PDO_SQLite_Ext, sqliteCreateAggregate)
-{
- struct pdo_sqlite_func *func;
- zend_fcall_info step_fci, fini_fci;
- zend_fcall_info_cache step_fcc, fini_fcc;
- char *func_name;
- size_t func_name_len;
- zend_long argc = -1;
- pdo_dbh_t *dbh;
- pdo_sqlite_db_handle *H;
- int ret;
-
- ZEND_PARSE_PARAMETERS_START(3, 4)
- Z_PARAM_STRING(func_name, func_name_len)
- Z_PARAM_FUNC(step_fci, step_fcc)
- Z_PARAM_FUNC(fini_fci, fini_fcc)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(argc)
- ZEND_PARSE_PARAMETERS_END();
-
- dbh = Z_PDO_DBH_P(ZEND_THIS);
- PDO_CONSTRUCT_CHECK;
-
- H = (pdo_sqlite_db_handle *)dbh->driver_data;
-
- func = (struct pdo_sqlite_func*)ecalloc(1, sizeof(*func));
-
- ret = sqlite3_create_function(H->db, func_name, argc, SQLITE_UTF8,
- func, NULL, php_sqlite3_func_step_callback, php_sqlite3_func_final_callback);
- if (ret == SQLITE_OK) {
- func->funcname = estrdup(func_name);
-
- ZVAL_COPY(&func->step, &step_fci.function_name);
-
- ZVAL_COPY(&func->fini, &fini_fci.function_name);
-
- func->argc = argc;
-
- func->next = H->funcs;
- H->funcs = func;
-
- RETURN_TRUE;
- }
-
- efree(func);
- RETURN_FALSE;
+PHP_METHOD(PDO_SQLite_Ext, sqliteCreateAggregate) {
+ struct pdo_sqlite_func *func;
+ zend_fcall_info step_fci, fini_fci;
+ zend_fcall_info_cache step_fcc, fini_fcc;
+ char *func_name;
+ size_t func_name_len;
+ zend_long argc = -1;
+ pdo_dbh_t *dbh;
+ pdo_sqlite_db_handle *H;
+ int ret;
+
+ ZEND_PARSE_PARAMETERS_START(3, 4)
+ Z_PARAM_STRING(func_name, func_name_len)
+ Z_PARAM_FUNC(step_fci, step_fcc)
+ Z_PARAM_FUNC(fini_fci, fini_fcc)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_LONG(argc)
+ ZEND_PARSE_PARAMETERS_END();
+
+ dbh = Z_PDO_DBH_P(ZEND_THIS);
+ PDO_CONSTRUCT_CHECK;
+
+ H = (pdo_sqlite_db_handle *) dbh->driver_data;
+
+ func = (struct pdo_sqlite_func *) ecalloc(1, sizeof(*func));
+
+ ret = sqlite3_create_function(H->db,
+ func_name,
+ argc,
+ SQLITE_UTF8,
+ func,
+ NULL,
+ php_sqlite3_func_step_callback,
+ php_sqlite3_func_final_callback);
+ if (ret == SQLITE_OK) {
+ func->funcname = estrdup(func_name);
+
+ ZVAL_COPY(&func->step, &step_fci.function_name);
+
+ ZVAL_COPY(&func->fini, &fini_fci.function_name);
+
+ func->argc = argc;
+
+ func->next = H->funcs;
+ H->funcs = func;
+
+ RETURN_TRUE;
+ }
+
+ efree(func);
+ RETURN_FALSE;
}
/* }}} */
/* {{{ bool SQLite::sqliteCreateCollation(string name, callable callback)
Registers a collation with the sqlite db handle */
-PHP_METHOD(PDO_SQLite_Ext, sqliteCreateCollation)
-{
- struct pdo_sqlite_collation *collation;
- zend_fcall_info fci;
- zend_fcall_info_cache fcc;
- char *collation_name;
- size_t collation_name_len;
- pdo_dbh_t *dbh;
- pdo_sqlite_db_handle *H;
- int ret;
+PHP_METHOD(PDO_SQLite_Ext, sqliteCreateCollation) {
+ struct pdo_sqlite_collation *collation;
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ char *collation_name;
+ size_t collation_name_len;
+ pdo_dbh_t *dbh;
+ pdo_sqlite_db_handle *H;
+ int ret;
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_STRING(collation_name, collation_name_len)
- Z_PARAM_FUNC(fci, fcc)
- ZEND_PARSE_PARAMETERS_END();
+ ZEND_PARSE_PARAMETERS_START(2, 2)
+ Z_PARAM_STRING(collation_name, collation_name_len)
+ Z_PARAM_FUNC(fci, fcc)
+ ZEND_PARSE_PARAMETERS_END();
- dbh = Z_PDO_DBH_P(ZEND_THIS);
- PDO_CONSTRUCT_CHECK;
+ dbh = Z_PDO_DBH_P(ZEND_THIS);
+ PDO_CONSTRUCT_CHECK;
- H = (pdo_sqlite_db_handle *)dbh->driver_data;
+ H = (pdo_sqlite_db_handle *) dbh->driver_data;
- collation = (struct pdo_sqlite_collation*)ecalloc(1, sizeof(*collation));
+ collation = (struct pdo_sqlite_collation *) ecalloc(1, sizeof(*collation));
- ret = sqlite3_create_collation(H->db, collation_name, SQLITE_UTF8, collation, php_sqlite3_collation_callback);
- if (ret == SQLITE_OK) {
- collation->name = estrdup(collation_name);
+ ret = sqlite3_create_collation(H->db, collation_name, SQLITE_UTF8, collation, php_sqlite3_collation_callback);
+ if (ret == SQLITE_OK) {
+ collation->name = estrdup(collation_name);
- ZVAL_COPY(&collation->callback, &fci.function_name);
+ ZVAL_COPY(&collation->callback, &fci.function_name);
- collation->next = H->collations;
- H->collations = collation;
+ collation->next = H->collations;
+ H->collations = collation;
- RETURN_TRUE;
- }
+ RETURN_TRUE;
+ }
- efree(collation);
- RETURN_FALSE;
+ efree(collation);
+ RETURN_FALSE;
}
/* }}} */
-static const zend_function_entry *get_driver_methods(pdo_dbh_t *dbh, int kind)
-{
- switch (kind) {
- case PDO_DBH_DRIVER_METHOD_KIND_DBH:
- return class_PDO_SQLite_Ext_methods;
+static const zend_function_entry *get_driver_methods(pdo_dbh_t *dbh, int kind) {
+ switch (kind) {
+ case PDO_DBH_DRIVER_METHOD_KIND_DBH:
+ return class_PDO_SQLite_Ext_methods;
- default:
- return NULL;
- }
+ default:
+ return NULL;
+ }
}
-static void pdo_sqlite_request_shutdown(pdo_dbh_t *dbh)
-{
- pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
- /* unregister functions, so that they don't linger for the next
- * request */
- if (H) {
- pdo_sqlite_cleanup_callbacks(H);
- }
+static void pdo_sqlite_request_shutdown(pdo_dbh_t *dbh) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ /* unregister functions, so that they don't linger for the next
+ * request */
+ if (H) {
+ pdo_sqlite_cleanup_callbacks(H);
+ }
}
-static void pdo_sqlite_get_gc(pdo_dbh_t *dbh, zend_get_gc_buffer *gc_buffer)
-{
- pdo_sqlite_db_handle *H = dbh->driver_data;
-
- struct pdo_sqlite_func *func = H->funcs;
- while (func) {
- zend_get_gc_buffer_add_zval(gc_buffer, &func->func);
- zend_get_gc_buffer_add_zval(gc_buffer, &func->step);
- zend_get_gc_buffer_add_zval(gc_buffer, &func->fini);
- func = func->next;
- }
-
- struct pdo_sqlite_collation *collation = H->collations;
- while (collation) {
- zend_get_gc_buffer_add_zval(gc_buffer, &collation->callback);
- collation = collation->next;
- }
+static void pdo_sqlite_get_gc(pdo_dbh_t *dbh, zend_get_gc_buffer *gc_buffer) {
+ pdo_sqlite_db_handle *H = dbh->driver_data;
+
+ struct pdo_sqlite_func *func = H->funcs;
+ while (func) {
+ zend_get_gc_buffer_add_zval(gc_buffer, &func->func);
+ zend_get_gc_buffer_add_zval(gc_buffer, &func->step);
+ zend_get_gc_buffer_add_zval(gc_buffer, &func->fini);
+ func = func->next;
+ }
+
+ struct pdo_sqlite_collation *collation = H->collations;
+ while (collation) {
+ zend_get_gc_buffer_add_zval(gc_buffer, &collation->callback);
+ collation = collation->next;
+ }
}
-static const struct pdo_dbh_methods sqlite_methods = {
- sqlite_handle_closer,
- sqlite_handle_preparer,
- sqlite_handle_doer,
- sqlite_handle_quoter,
- sqlite_handle_begin,
- sqlite_handle_commit,
- sqlite_handle_rollback,
- pdo_sqlite_set_attr,
- pdo_sqlite_last_insert_id,
- pdo_sqlite_fetch_error_func,
- pdo_sqlite_get_attribute,
- NULL, /* check_liveness: not needed */
- get_driver_methods,
- pdo_sqlite_request_shutdown,
- NULL, /* in transaction, use PDO's internal tracking mechanism */
- pdo_sqlite_get_gc
-};
-
-static char *make_filename_safe(const char *filename)
-{
- if (!filename) {
- return NULL;
- }
- if (*filename && strncasecmp(filename, "file:", 5) == 0) {
- if (PG(open_basedir) && *PG(open_basedir)) {
- return NULL;
- }
- return estrdup(filename);
- }
- if (*filename && memcmp(filename, ":memory:", sizeof(":memory:"))) {
- char *fullpath = expand_filepath(filename, NULL);
-
- if (!fullpath) {
- return NULL;
- }
-
- if (php_check_open_basedir(fullpath)) {
- efree(fullpath);
- return NULL;
- }
- return fullpath;
- }
- return estrdup(filename);
+static const struct pdo_dbh_methods sqlite_methods = {sqlite_handle_closer,
+ sqlite_handle_preparer,
+ sqlite_handle_doer,
+ sqlite_handle_quoter,
+ sqlite_handle_begin,
+ sqlite_handle_commit,
+ sqlite_handle_rollback,
+ pdo_sqlite_set_attr,
+ pdo_sqlite_last_insert_id,
+ pdo_sqlite_fetch_error_func,
+ pdo_sqlite_get_attribute,
+ NULL, /* check_liveness: not needed */
+ get_driver_methods,
+ pdo_sqlite_request_shutdown,
+ NULL, /* in transaction, use PDO's internal tracking mechanism */
+ pdo_sqlite_get_gc};
+
+static char *make_filename_safe(const char *filename) {
+ if (!filename) {
+ return NULL;
+ }
+ if (*filename && strncasecmp(filename, "file:", 5) == 0) {
+ if (PG(open_basedir) && *PG(open_basedir)) {
+ return NULL;
+ }
+ return estrdup(filename);
+ }
+ if (*filename && memcmp(filename, ":memory:", sizeof(":memory:"))) {
+ char *fullpath = expand_filepath(filename, NULL);
+
+ if (!fullpath) {
+ return NULL;
+ }
+
+ if (php_check_open_basedir(fullpath)) {
+ efree(fullpath);
+ return NULL;
+ }
+ return fullpath;
+ }
+ return estrdup(filename);
}
-static int authorizer(void *autharg, int access_type, const char *arg3, const char *arg4,
- const char *arg5, const char *arg6)
-{
- char *filename;
- switch (access_type) {
- case SQLITE_COPY: {
- filename = make_filename_safe(arg4);
- if (!filename) {
- return SQLITE_DENY;
- }
- efree(filename);
- return SQLITE_OK;
- }
-
- case SQLITE_ATTACH: {
- filename = make_filename_safe(arg3);
- if (!filename) {
- return SQLITE_DENY;
- }
- efree(filename);
- return SQLITE_OK;
- }
-
- default:
- /* access allowed */
- return SQLITE_OK;
- }
+static int authorizer(
+ void *autharg, int access_type, const char *arg3, const char *arg4, const char *arg5, const char *arg6) {
+ char *filename;
+ switch (access_type) {
+ case SQLITE_COPY: {
+ filename = make_filename_safe(arg4);
+ if (!filename) {
+ return SQLITE_DENY;
+ }
+ efree(filename);
+ return SQLITE_OK;
+ }
+
+ case SQLITE_ATTACH: {
+ filename = make_filename_safe(arg3);
+ if (!filename) {
+ return SQLITE_DENY;
+ }
+ efree(filename);
+ return SQLITE_OK;
+ }
+
+ default:
+ /* access allowed */
+ return SQLITE_OK;
+ }
}
static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ */
{
- pdo_sqlite_db_handle *H;
- int i, ret = 0;
- zend_long timeout = 60, flags;
- char *filename;
+ pdo_sqlite_db_handle *H;
+ int i, ret = 0;
+ zend_long timeout = 60, flags;
+ char *filename;
- H = pecalloc(1, sizeof(pdo_sqlite_db_handle), dbh->is_persistent);
+ H = pecalloc(1, sizeof(pdo_sqlite_db_handle), dbh->is_persistent);
- H->einfo.errcode = 0;
- H->einfo.errmsg = NULL;
- dbh->driver_data = H;
+ H->einfo.errcode = 0;
+ H->einfo.errmsg = NULL;
+ dbh->driver_data = H;
- /* skip all but this one param event */
- dbh->skip_param_evt = 0x7F ^ (1 << PDO_PARAM_EVT_EXEC_PRE);
+ /* skip all but this one param event */
+ dbh->skip_param_evt = 0x7F ^ (1 << PDO_PARAM_EVT_EXEC_PRE);
- filename = make_filename_safe(dbh->data_source);
+ filename = make_filename_safe(dbh->data_source);
- if (!filename) {
- zend_throw_exception_ex(php_pdo_get_exception(), 0,
- "open_basedir prohibits opening %s",
- dbh->data_source);
- goto cleanup;
- }
+ if (!filename) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0, "open_basedir prohibits opening %s", dbh->data_source);
+ goto cleanup;
+ }
- flags = pdo_attr_lval(driver_options, PDO_SQLITE_ATTR_OPEN_FLAGS, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
+ flags = pdo_attr_lval(driver_options, PDO_SQLITE_ATTR_OPEN_FLAGS, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
- if (!(PG(open_basedir) && *PG(open_basedir))) {
- flags |= SQLITE_OPEN_URI;
- }
- i = sqlite3_open_v2(filename, &H->db, flags, NULL);
+ if (!(PG(open_basedir) && *PG(open_basedir))) {
+ flags |= SQLITE_OPEN_URI;
+ }
+ i = sqlite3_open_v2(filename, &H->db, flags, NULL);
- efree(filename);
+ efree(filename);
- if (i != SQLITE_OK) {
- pdo_sqlite_error(dbh);
- goto cleanup;
- }
+ if (i != SQLITE_OK) {
+ pdo_sqlite_error(dbh);
+ goto cleanup;
+ }
- if (PG(open_basedir) && *PG(open_basedir)) {
- sqlite3_set_authorizer(H->db, authorizer, NULL);
- }
+ if (PG(open_basedir) && *PG(open_basedir)) {
+ sqlite3_set_authorizer(H->db, authorizer, NULL);
+ }
- if (driver_options) {
- timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, timeout);
- }
- sqlite3_busy_timeout(H->db, timeout * 1000);
+ if (driver_options) {
+ timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, timeout);
+ }
+ sqlite3_busy_timeout(H->db, timeout * 1000);
- dbh->alloc_own_columns = 1;
- dbh->max_escaped_char_length = 2;
+ dbh->alloc_own_columns = 1;
+ dbh->max_escaped_char_length = 2;
- ret = 1;
+ ret = 1;
cleanup:
- dbh->methods = &sqlite_methods;
+ dbh->methods = &sqlite_methods;
- return ret;
+ return ret;
}
/* }}} */
-const pdo_driver_t swoole_pdo_sqlite_driver = {
- PDO_DRIVER_HEADER(sqlite),
- pdo_sqlite_handle_factory
-};
+const pdo_driver_t swoole_pdo_sqlite_driver = {PDO_DRIVER_HEADER(sqlite), pdo_sqlite_handle_factory};
#endif
diff --git a/thirdparty/php81/pdo_sqlite/sqlite_statement.c b/thirdparty/php81/pdo_sqlite/sqlite_statement.c
index 3647e58b311..9081cbb7788 100644
--- a/thirdparty/php81/pdo_sqlite/sqlite_statement.c
+++ b/thirdparty/php81/pdo_sqlite/sqlite_statement.c
@@ -17,385 +17,365 @@
#define SW_USE_SQLITE_HOOK
#include "php_swoole_sqlite.h"
-#if PHP_VERSION_ID >= 80100
+#if PHP_VERSION_ID >= 80100 && PHP_VERSION_ID < 80300
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "pdo/php_pdo.h"
-static int pdo_sqlite_stmt_dtor(pdo_stmt_t *stmt)
-{
- pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
+static int pdo_sqlite_stmt_dtor(pdo_stmt_t *stmt) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
- if (S->stmt) {
- sqlite3_finalize(S->stmt);
- S->stmt = NULL;
- }
- efree(S);
- return 1;
+ if (S->stmt) {
+ sqlite3_finalize(S->stmt);
+ S->stmt = NULL;
+ }
+ efree(S);
+ return 1;
}
-static int pdo_sqlite_stmt_execute(pdo_stmt_t *stmt)
-{
- pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
-
- if (stmt->executed && !S->done) {
- sqlite3_reset(S->stmt);
- }
-
- S->done = 0;
- switch (sqlite3_step(S->stmt)) {
- case SQLITE_ROW:
- S->pre_fetched = 1;
- php_pdo_stmt_set_column_count(stmt, sqlite3_data_count(S->stmt));
- return 1;
-
- case SQLITE_DONE:
- php_pdo_stmt_set_column_count(stmt, sqlite3_column_count(S->stmt));
- stmt->row_count = sqlite3_changes(S->H->db);
- sqlite3_reset(S->stmt);
- S->done = 1;
- return 1;
-
- case SQLITE_ERROR:
- sqlite3_reset(S->stmt);
- ZEND_FALLTHROUGH;
- case SQLITE_MISUSE:
- case SQLITE_BUSY:
- default:
- pdo_sqlite_error_stmt(stmt);
- return 0;
- }
+static int pdo_sqlite_stmt_execute(pdo_stmt_t *stmt) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+
+ if (stmt->executed && !S->done) {
+ sqlite3_reset(S->stmt);
+ }
+
+ S->done = 0;
+ switch (sqlite3_step(S->stmt)) {
+ case SQLITE_ROW:
+ S->pre_fetched = 1;
+ php_pdo_stmt_set_column_count(stmt, sqlite3_data_count(S->stmt));
+ return 1;
+
+ case SQLITE_DONE:
+ php_pdo_stmt_set_column_count(stmt, sqlite3_column_count(S->stmt));
+ stmt->row_count = sqlite3_changes(S->H->db);
+ sqlite3_reset(S->stmt);
+ S->done = 1;
+ return 1;
+
+ case SQLITE_ERROR:
+ sqlite3_reset(S->stmt);
+ ZEND_FALLTHROUGH;
+ case SQLITE_MISUSE:
+ case SQLITE_BUSY:
+ default:
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ }
}
-static int pdo_sqlite_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
- enum pdo_param_event event_type)
-{
- pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
- zval *parameter;
-
- switch (event_type) {
- case PDO_PARAM_EVT_EXEC_PRE:
- if (stmt->executed && !S->done) {
- sqlite3_reset(S->stmt);
- S->done = 1;
- }
-
- if (param->is_param) {
-
- if (param->paramno == -1) {
- param->paramno = sqlite3_bind_parameter_index(S->stmt, ZSTR_VAL(param->name)) - 1;
- }
-
- switch (PDO_PARAM_TYPE(param->param_type)) {
- case PDO_PARAM_STMT:
- return 0;
-
- case PDO_PARAM_NULL:
- if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
- return 1;
- }
- pdo_sqlite_error_stmt(stmt);
- return 0;
-
- case PDO_PARAM_INT:
- case PDO_PARAM_BOOL:
- if (Z_ISREF(param->parameter)) {
- parameter = Z_REFVAL(param->parameter);
- } else {
- parameter = ¶m->parameter;
- }
- if (Z_TYPE_P(parameter) == IS_NULL) {
- if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
- return 1;
- }
- } else {
- convert_to_long(parameter);
+static int pdo_sqlite_stmt_param_hook(pdo_stmt_t *stmt,
+ struct pdo_bound_param_data *param,
+ enum pdo_param_event event_type) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ zval *parameter;
+
+ switch (event_type) {
+ case PDO_PARAM_EVT_EXEC_PRE:
+ if (stmt->executed && !S->done) {
+ sqlite3_reset(S->stmt);
+ S->done = 1;
+ }
+
+ if (param->is_param) {
+ if (param->paramno == -1) {
+ param->paramno = sqlite3_bind_parameter_index(S->stmt, ZSTR_VAL(param->name)) - 1;
+ }
+
+ switch (PDO_PARAM_TYPE(param->param_type)) {
+ case PDO_PARAM_STMT:
+ return 0;
+
+ case PDO_PARAM_NULL:
+ if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
+ return 1;
+ }
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+
+ case PDO_PARAM_INT:
+ case PDO_PARAM_BOOL:
+ if (Z_ISREF(param->parameter)) {
+ parameter = Z_REFVAL(param->parameter);
+ } else {
+ parameter = ¶m->parameter;
+ }
+ if (Z_TYPE_P(parameter) == IS_NULL) {
+ if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
+ return 1;
+ }
+ } else {
+ convert_to_long(parameter);
#if ZEND_LONG_MAX > 2147483647
- if (SQLITE_OK == sqlite3_bind_int64(S->stmt, param->paramno + 1, Z_LVAL_P(parameter))) {
- return 1;
- }
+ if (SQLITE_OK == sqlite3_bind_int64(S->stmt, param->paramno + 1, Z_LVAL_P(parameter))) {
+ return 1;
+ }
#else
- if (SQLITE_OK == sqlite3_bind_int(S->stmt, param->paramno + 1, Z_LVAL_P(parameter))) {
- return 1;
- }
+ if (SQLITE_OK == sqlite3_bind_int(S->stmt, param->paramno + 1, Z_LVAL_P(parameter))) {
+ return 1;
+ }
#endif
- }
- pdo_sqlite_error_stmt(stmt);
- return 0;
-
- case PDO_PARAM_LOB:
- if (Z_ISREF(param->parameter)) {
- parameter = Z_REFVAL(param->parameter);
- } else {
- parameter = ¶m->parameter;
- }
- if (Z_TYPE_P(parameter) == IS_RESOURCE) {
- php_stream *stm = NULL;
- php_stream_from_zval_no_verify(stm, parameter);
- if (stm) {
- zend_string *mem = php_stream_copy_to_mem(stm, PHP_STREAM_COPY_ALL, 0);
- zval_ptr_dtor(parameter);
- ZVAL_STR(parameter, mem ? mem : ZSTR_EMPTY_ALLOC());
- } else {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource");
- return 0;
- }
- } else if (Z_TYPE_P(parameter) == IS_NULL) {
- if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
- return 1;
- }
- pdo_sqlite_error_stmt(stmt);
- return 0;
- } else {
- if (!try_convert_to_string(parameter)) {
- return 0;
- }
- }
-
- if (SQLITE_OK == sqlite3_bind_blob(S->stmt, param->paramno + 1,
- Z_STRVAL_P(parameter),
- Z_STRLEN_P(parameter),
- SQLITE_STATIC)) {
- return 1;
- }
- return 0;
-
- case PDO_PARAM_STR:
- default:
- if (Z_ISREF(param->parameter)) {
- parameter = Z_REFVAL(param->parameter);
- } else {
- parameter = ¶m->parameter;
- }
- if (Z_TYPE_P(parameter) == IS_NULL) {
- if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
- return 1;
- }
- } else {
- if (!try_convert_to_string(parameter)) {
- return 0;
- }
- if (SQLITE_OK == sqlite3_bind_text(S->stmt, param->paramno + 1,
- Z_STRVAL_P(parameter),
- Z_STRLEN_P(parameter),
- SQLITE_STATIC)) {
- return 1;
- }
- }
- pdo_sqlite_error_stmt(stmt);
- return 0;
- }
- }
- break;
-
- default:
- ;
- }
- return 1;
+ }
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+
+ case PDO_PARAM_LOB:
+ if (Z_ISREF(param->parameter)) {
+ parameter = Z_REFVAL(param->parameter);
+ } else {
+ parameter = ¶m->parameter;
+ }
+ if (Z_TYPE_P(parameter) == IS_RESOURCE) {
+ php_stream *stm = NULL;
+ php_stream_from_zval_no_verify(stm, parameter);
+ if (stm) {
+ zend_string *mem = php_stream_copy_to_mem(stm, PHP_STREAM_COPY_ALL, 0);
+ zval_ptr_dtor(parameter);
+ ZVAL_STR(parameter, mem ? mem : ZSTR_EMPTY_ALLOC());
+ } else {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource");
+ return 0;
+ }
+ } else if (Z_TYPE_P(parameter) == IS_NULL) {
+ if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
+ return 1;
+ }
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ } else {
+ if (!try_convert_to_string(parameter)) {
+ return 0;
+ }
+ }
+
+ if (SQLITE_OK ==
+ sqlite3_bind_blob(
+ S->stmt, param->paramno + 1, Z_STRVAL_P(parameter), Z_STRLEN_P(parameter), SQLITE_STATIC)) {
+ return 1;
+ }
+ return 0;
+
+ case PDO_PARAM_STR:
+ default:
+ if (Z_ISREF(param->parameter)) {
+ parameter = Z_REFVAL(param->parameter);
+ } else {
+ parameter = ¶m->parameter;
+ }
+ if (Z_TYPE_P(parameter) == IS_NULL) {
+ if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
+ return 1;
+ }
+ } else {
+ if (!try_convert_to_string(parameter)) {
+ return 0;
+ }
+ if (SQLITE_OK ==
+ sqlite3_bind_text(
+ S->stmt, param->paramno + 1, Z_STRVAL_P(parameter), Z_STRLEN_P(parameter), SQLITE_STATIC)) {
+ return 1;
+ }
+ }
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ }
+ }
+ break;
+
+ default:;
+ }
+ return 1;
}
-static int pdo_sqlite_stmt_fetch(pdo_stmt_t *stmt,
- enum pdo_fetch_orientation ori, zend_long offset)
-{
- pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
- int i;
- if (!S->stmt) {
- return 0;
- }
- if (S->pre_fetched) {
- S->pre_fetched = 0;
- return 1;
- }
- if (S->done) {
- return 0;
- }
- i = sqlite3_step(S->stmt);
- switch (i) {
- case SQLITE_ROW:
- return 1;
-
- case SQLITE_DONE:
- S->done = 1;
- sqlite3_reset(S->stmt);
- return 0;
-
- case SQLITE_ERROR:
- sqlite3_reset(S->stmt);
- ZEND_FALLTHROUGH;
- default:
- pdo_sqlite_error_stmt(stmt);
- return 0;
- }
+static int pdo_sqlite_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, zend_long offset) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ int i;
+ if (!S->stmt) {
+ return 0;
+ }
+ if (S->pre_fetched) {
+ S->pre_fetched = 0;
+ return 1;
+ }
+ if (S->done) {
+ return 0;
+ }
+ i = sqlite3_step(S->stmt);
+ switch (i) {
+ case SQLITE_ROW:
+ return 1;
+
+ case SQLITE_DONE:
+ S->done = 1;
+ sqlite3_reset(S->stmt);
+ return 0;
+
+ case SQLITE_ERROR:
+ sqlite3_reset(S->stmt);
+ ZEND_FALLTHROUGH;
+ default:
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ }
}
-static int pdo_sqlite_stmt_describe(pdo_stmt_t *stmt, int colno)
-{
- pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
- const char *str;
+static int pdo_sqlite_stmt_describe(pdo_stmt_t *stmt, int colno) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ const char *str;
- if(colno >= sqlite3_column_count(S->stmt)) {
- /* error invalid column */
- pdo_sqlite_error_stmt(stmt);
- return 0;
- }
+ if (colno >= sqlite3_column_count(S->stmt)) {
+ /* error invalid column */
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ }
- str = sqlite3_column_name(S->stmt, colno);
- stmt->columns[colno].name = zend_string_init(str, strlen(str), 0);
- stmt->columns[colno].maxlen = SIZE_MAX;
- stmt->columns[colno].precision = 0;
+ str = sqlite3_column_name(S->stmt, colno);
+ stmt->columns[colno].name = zend_string_init(str, strlen(str), 0);
+ stmt->columns[colno].maxlen = SIZE_MAX;
+ stmt->columns[colno].precision = 0;
- return 1;
+ return 1;
}
-static int pdo_sqlite_stmt_get_col(
- pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type)
-{
- pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
- if (!S->stmt) {
- return 0;
- }
- if(colno >= sqlite3_data_count(S->stmt)) {
- /* error invalid column */
- pdo_sqlite_error_stmt(stmt);
- return 0;
- }
- switch (sqlite3_column_type(S->stmt, colno)) {
- case SQLITE_NULL:
- ZVAL_NULL(result);
- return 1;
-
- case SQLITE_INTEGER: {
- int64_t i = sqlite3_column_int64(S->stmt, colno);
+static int pdo_sqlite_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ if (!S->stmt) {
+ return 0;
+ }
+ if (colno >= sqlite3_data_count(S->stmt)) {
+ /* error invalid column */
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ }
+ switch (sqlite3_column_type(S->stmt, colno)) {
+ case SQLITE_NULL:
+ ZVAL_NULL(result);
+ return 1;
+
+ case SQLITE_INTEGER: {
+ int64_t i = sqlite3_column_int64(S->stmt, colno);
#if SIZEOF_ZEND_LONG < 8
- if (i > ZEND_LONG_MAX || i < ZEND_LONG_MIN) {
- ZVAL_STRINGL(result,
- (char *) sqlite3_column_text(S->stmt, colno),
- sqlite3_column_bytes(S->stmt, colno));
- return 1;
- }
+ if (i > ZEND_LONG_MAX || i < ZEND_LONG_MIN) {
+ ZVAL_STRINGL(result, (char *) sqlite3_column_text(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno));
+ return 1;
+ }
#endif
- ZVAL_LONG(result, i);
- return 1;
- }
-
- case SQLITE_FLOAT:
- ZVAL_DOUBLE(result, sqlite3_column_double(S->stmt, colno));
- return 1;
-
- case SQLITE_BLOB:
- ZVAL_STRINGL_FAST(result,
- sqlite3_column_blob(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno));
- return 1;
-
- default:
- ZVAL_STRINGL_FAST(result,
- (char *) sqlite3_column_text(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno));
- return 1;
- }
+ ZVAL_LONG(result, i);
+ return 1;
+ }
+
+ case SQLITE_FLOAT:
+ ZVAL_DOUBLE(result, sqlite3_column_double(S->stmt, colno));
+ return 1;
+
+ case SQLITE_BLOB:
+ ZVAL_STRINGL_FAST(result, sqlite3_column_blob(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno));
+ return 1;
+
+ default:
+ ZVAL_STRINGL_FAST(result, (char *) sqlite3_column_text(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno));
+ return 1;
+ }
}
-static int pdo_sqlite_stmt_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value)
-{
- pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
- const char *str;
- zval flags;
-
- if (!S->stmt) {
- return FAILURE;
- }
- if(colno >= sqlite3_column_count(S->stmt)) {
- /* error invalid column */
- pdo_sqlite_error_stmt(stmt);
- return FAILURE;
- }
-
- array_init(return_value);
- array_init(&flags);
-
- switch (sqlite3_column_type(S->stmt, colno)) {
- case SQLITE_NULL:
- add_assoc_string(return_value, "native_type", "null");
- add_assoc_long(return_value, "pdo_type", PDO_PARAM_NULL);
- break;
-
- case SQLITE_FLOAT:
- add_assoc_string(return_value, "native_type", "double");
- add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
- break;
-
- case SQLITE_BLOB:
- add_next_index_string(&flags, "blob");
- /* TODO Check this is correct */
- ZEND_FALLTHROUGH;
- case SQLITE_TEXT:
- add_assoc_string(return_value, "native_type", "string");
- add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
- break;
-
- case SQLITE_INTEGER:
- add_assoc_string(return_value, "native_type", "integer");
- add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT);
- break;
- }
-
- str = sqlite3_column_decltype(S->stmt, colno);
- if (str) {
- add_assoc_string(return_value, "sqlite:decl_type", (char *)str);
- }
+static int pdo_sqlite_stmt_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ const char *str;
+ zval flags;
+
+ if (!S->stmt) {
+ return FAILURE;
+ }
+ if (colno >= sqlite3_column_count(S->stmt)) {
+ /* error invalid column */
+ pdo_sqlite_error_stmt(stmt);
+ return FAILURE;
+ }
+
+ array_init(return_value);
+ array_init(&flags);
+
+ switch (sqlite3_column_type(S->stmt, colno)) {
+ case SQLITE_NULL:
+ add_assoc_string(return_value, "native_type", "null");
+ add_assoc_long(return_value, "pdo_type", PDO_PARAM_NULL);
+ break;
+
+ case SQLITE_FLOAT:
+ add_assoc_string(return_value, "native_type", "double");
+ add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
+ break;
+
+ case SQLITE_BLOB:
+ add_next_index_string(&flags, "blob");
+ /* TODO Check this is correct */
+ ZEND_FALLTHROUGH;
+ case SQLITE_TEXT:
+ add_assoc_string(return_value, "native_type", "string");
+ add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
+ break;
+
+ case SQLITE_INTEGER:
+ add_assoc_string(return_value, "native_type", "integer");
+ add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT);
+ break;
+ }
+
+ str = sqlite3_column_decltype(S->stmt, colno);
+ if (str) {
+ add_assoc_string(return_value, "sqlite:decl_type", (char *) str);
+ }
#ifdef HAVE_SW_SQLITE3_COLUMN_TABLE_NAME
- str = sqlite3_column_table_name(S->stmt, colno);
- if (str) {
- add_assoc_string(return_value, "table", (char *)str);
- }
+ str = sqlite3_column_table_name(S->stmt, colno);
+ if (str) {
+ add_assoc_string(return_value, "table", (char *) str);
+ }
#endif
- add_assoc_zval(return_value, "flags", &flags);
+ add_assoc_zval(return_value, "flags", &flags);
- return SUCCESS;
+ return SUCCESS;
}
-static int pdo_sqlite_stmt_cursor_closer(pdo_stmt_t *stmt)
-{
- pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
- sqlite3_reset(S->stmt);
- return 1;
+static int pdo_sqlite_stmt_cursor_closer(pdo_stmt_t *stmt) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ sqlite3_reset(S->stmt);
+ return 1;
}
-static int pdo_sqlite_stmt_get_attribute(pdo_stmt_t *stmt, zend_long attr, zval *val)
-{
- pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
+static int pdo_sqlite_stmt_get_attribute(pdo_stmt_t *stmt, zend_long attr, zval *val) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
- switch (attr) {
- case PDO_SQLITE_ATTR_READONLY_STATEMENT:
- ZVAL_FALSE(val);
+ switch (attr) {
+ case PDO_SQLITE_ATTR_READONLY_STATEMENT:
+ ZVAL_FALSE(val);
#if SQLITE_VERSION_NUMBER >= 3007004
- if (sqlite3_stmt_readonly(S->stmt)) {
- ZVAL_TRUE(val);
- }
+ if (sqlite3_stmt_readonly(S->stmt)) {
+ ZVAL_TRUE(val);
+ }
#endif
- break;
+ break;
- default:
- return 0;
- }
+ default:
+ return 0;
+ }
- return 1;
+ return 1;
}
-const struct pdo_stmt_methods swoole_sqlite_stmt_methods = {
- pdo_sqlite_stmt_dtor,
- pdo_sqlite_stmt_execute,
- pdo_sqlite_stmt_fetch,
- pdo_sqlite_stmt_describe,
- pdo_sqlite_stmt_get_col,
- pdo_sqlite_stmt_param_hook,
- NULL, /* set_attr */
- pdo_sqlite_stmt_get_attribute, /* get_attr */
- pdo_sqlite_stmt_col_meta,
- NULL, /* next_rowset */
- pdo_sqlite_stmt_cursor_closer
-};
+const struct pdo_stmt_methods swoole_sqlite_stmt_methods = {pdo_sqlite_stmt_dtor,
+ pdo_sqlite_stmt_execute,
+ pdo_sqlite_stmt_fetch,
+ pdo_sqlite_stmt_describe,
+ pdo_sqlite_stmt_get_col,
+ pdo_sqlite_stmt_param_hook,
+ NULL, /* set_attr */
+ pdo_sqlite_stmt_get_attribute, /* get_attr */
+ pdo_sqlite_stmt_col_meta,
+ NULL, /* next_rowset */
+ pdo_sqlite_stmt_cursor_closer};
#endif
diff --git a/thirdparty/php83/pdo_sqlite/php_pdo_sqlite_int.h b/thirdparty/php83/pdo_sqlite/php_pdo_sqlite_int.h
new file mode 100644
index 00000000000..0e78c4be19d
--- /dev/null
+++ b/thirdparty/php83/pdo_sqlite/php_pdo_sqlite_int.h
@@ -0,0 +1,80 @@
+/*
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | https://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHP_PDO_SQLITE_INT_H
+#define PHP_PDO_SQLITE_INT_H
+
+#include
+
+typedef struct {
+ const char *file;
+ int line;
+ unsigned int errcode;
+ char *errmsg;
+} pdo_sqlite_error_info;
+
+struct pdo_sqlite_fci {
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+};
+
+struct pdo_sqlite_func {
+ struct pdo_sqlite_func *next;
+
+ zval func, step, fini;
+ int argc;
+ const char *funcname;
+
+ /* accelerated callback references */
+ struct pdo_sqlite_fci afunc, astep, afini;
+};
+
+struct pdo_sqlite_collation {
+ struct pdo_sqlite_collation *next;
+
+ const char *name;
+ zval callback;
+ struct pdo_sqlite_fci fc;
+};
+
+typedef struct {
+ sqlite3 *db;
+ pdo_sqlite_error_info einfo;
+ struct pdo_sqlite_func *funcs;
+ struct pdo_sqlite_collation *collations;
+} pdo_sqlite_db_handle;
+
+typedef struct {
+ pdo_sqlite_db_handle *H;
+ sqlite3_stmt *stmt;
+ unsigned pre_fetched:1;
+ unsigned done:1;
+} pdo_sqlite_stmt;
+
+
+extern int _pdo_sqlite_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line);
+#define pdo_sqlite_error(s) _pdo_sqlite_error(s, NULL, __FILE__, __LINE__)
+#define pdo_sqlite_error_stmt(s) _pdo_sqlite_error(stmt->dbh, stmt, __FILE__, __LINE__)
+
+extern const struct pdo_stmt_methods swoole_sqlite_stmt_methods;
+
+enum {
+ PDO_SQLITE_ATTR_OPEN_FLAGS = PDO_ATTR_DRIVER_SPECIFIC,
+ PDO_SQLITE_ATTR_READONLY_STATEMENT,
+ PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES
+};
+
+#endif
diff --git a/thirdparty/php83/pdo_sqlite/sqlite_driver.c b/thirdparty/php83/pdo_sqlite/sqlite_driver.c
new file mode 100644
index 00000000000..e130d779f9c
--- /dev/null
+++ b/thirdparty/php83/pdo_sqlite/sqlite_driver.c
@@ -0,0 +1,802 @@
+/*
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | https://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong |
+ +----------------------------------------------------------------------+
+*/
+#define SW_USE_SQLITE_HOOK
+#include "php_swoole_sqlite.h"
+#include "php_swoole_call_stack.h"
+
+#if PHP_VERSION_ID >= 80300
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "pdo/php_pdo.h"
+#include "zend_exceptions.h"
+#include "sqlite_driver_arginfo.h"
+
+int _pdo_sqlite_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line) /* {{{ */
+{
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ pdo_error_type *pdo_err = stmt ? &stmt->error_code : &dbh->error_code;
+ pdo_sqlite_error_info *einfo = &H->einfo;
+
+ einfo->errcode = sqlite3_errcode(H->db);
+ einfo->file = file;
+ einfo->line = line;
+
+ if (einfo->errcode != SQLITE_OK) {
+ if (einfo->errmsg) {
+ pefree(einfo->errmsg, dbh->is_persistent);
+ }
+ einfo->errmsg = pestrdup((char *) sqlite3_errmsg(H->db), dbh->is_persistent);
+ } else { /* no error */
+ strncpy(*pdo_err, PDO_ERR_NONE, sizeof(*pdo_err));
+ return 0;
+ }
+ switch (einfo->errcode) {
+ case SQLITE_NOTFOUND:
+ strncpy(*pdo_err, "42S02", sizeof(*pdo_err));
+ break;
+
+ case SQLITE_INTERRUPT:
+ strncpy(*pdo_err, "01002", sizeof(*pdo_err));
+ break;
+
+ case SQLITE_NOLFS:
+ strncpy(*pdo_err, "HYC00", sizeof(*pdo_err));
+ break;
+
+ case SQLITE_TOOBIG:
+ strncpy(*pdo_err, "22001", sizeof(*pdo_err));
+ break;
+
+ case SQLITE_CONSTRAINT:
+ strncpy(*pdo_err, "23000", sizeof(*pdo_err));
+ break;
+
+ case SQLITE_ERROR:
+ default:
+ strncpy(*pdo_err, "HY000", sizeof(*pdo_err));
+ break;
+ }
+
+ if (!dbh->methods) {
+ pdo_throw_exception(einfo->errcode, einfo->errmsg, pdo_err);
+ }
+
+ return einfo->errcode;
+}
+/* }}} */
+
+static void pdo_sqlite_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ pdo_sqlite_error_info *einfo = &H->einfo;
+
+ if (einfo->errcode) {
+ add_next_index_long(info, einfo->errcode);
+ add_next_index_string(info, einfo->errmsg);
+ }
+}
+
+static void pdo_sqlite_cleanup_callbacks(pdo_sqlite_db_handle *H) {
+ struct pdo_sqlite_func *func;
+
+ while (H->funcs) {
+ func = H->funcs;
+ H->funcs = func->next;
+
+ if (H->db) {
+ /* delete the function from the handle */
+ sqlite3_create_function(H->db, func->funcname, func->argc, SQLITE_UTF8, func, NULL, NULL, NULL);
+ }
+
+ efree((char *) func->funcname);
+ if (!Z_ISUNDEF(func->func)) {
+ zval_ptr_dtor(&func->func);
+ }
+ if (!Z_ISUNDEF(func->step)) {
+ zval_ptr_dtor(&func->step);
+ }
+ if (!Z_ISUNDEF(func->fini)) {
+ zval_ptr_dtor(&func->fini);
+ }
+ efree(func);
+ }
+
+ while (H->collations) {
+ struct pdo_sqlite_collation *collation;
+ collation = H->collations;
+ H->collations = collation->next;
+
+ if (H->db) {
+ /* delete the collation from the handle */
+ sqlite3_create_collation(H->db, collation->name, SQLITE_UTF8, collation, NULL);
+ }
+
+ efree((char *) collation->name);
+ if (!Z_ISUNDEF(collation->callback)) {
+ zval_ptr_dtor(&collation->callback);
+ }
+ efree(collation);
+ }
+}
+
+static void sqlite_handle_closer(pdo_dbh_t *dbh) /* {{{ */
+{
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+
+ if (H) {
+ pdo_sqlite_error_info *einfo = &H->einfo;
+
+ pdo_sqlite_cleanup_callbacks(H);
+ if (H->db) {
+#ifdef HAVE_SW_SQLITE3_CLOSE_V2
+ sqlite3_close_v2(H->db);
+#else
+ sqlite3_close(H->db);
+#endif
+ H->db = NULL;
+ }
+ if (einfo->errmsg) {
+ pefree(einfo->errmsg, dbh->is_persistent);
+ einfo->errmsg = NULL;
+ }
+ pefree(H, dbh->is_persistent);
+ dbh->driver_data = NULL;
+ }
+}
+/* }}} */
+
+static bool sqlite_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *stmt, zval *driver_options) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ pdo_sqlite_stmt *S = ecalloc(1, sizeof(pdo_sqlite_stmt));
+ int i;
+ const char *tail;
+
+ S->H = H;
+ stmt->driver_data = S;
+ stmt->methods = &swoole_sqlite_stmt_methods;
+ stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL | PDO_PLACEHOLDER_NAMED;
+
+ if (PDO_CURSOR_FWDONLY != pdo_attr_lval(driver_options, PDO_ATTR_CURSOR, PDO_CURSOR_FWDONLY)) {
+ H->einfo.errcode = SQLITE_ERROR;
+ pdo_sqlite_error(dbh);
+ return false;
+ }
+
+ i = sqlite3_prepare_v2(H->db, ZSTR_VAL(sql), ZSTR_LEN(sql), &S->stmt, &tail);
+ if (i == SQLITE_OK) {
+ return true;
+ }
+
+ pdo_sqlite_error(dbh);
+
+ return false;
+}
+
+static zend_long sqlite_handle_doer(pdo_dbh_t *dbh, const zend_string *sql) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+
+ if (sqlite3_exec(H->db, ZSTR_VAL(sql), NULL, NULL, NULL) != SQLITE_OK) {
+ pdo_sqlite_error(dbh);
+ return -1;
+ } else {
+ return sqlite3_changes(H->db);
+ }
+}
+
+static zend_string *pdo_sqlite_last_insert_id(pdo_dbh_t *dbh, const zend_string *name) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+
+ return zend_i64_to_str(sqlite3_last_insert_rowid(H->db));
+}
+
+/* NB: doesn't handle binary strings... use prepared stmts for that */
+static zend_string *sqlite_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquoted, enum pdo_param_type paramtype) {
+ char *quoted;
+ if (ZSTR_LEN(unquoted) > (INT_MAX - 3) / 2) {
+ return NULL;
+ }
+ quoted = safe_emalloc(2, ZSTR_LEN(unquoted), 3);
+ /* TODO use %Q format? */
+ sqlite3_snprintf(2 * ZSTR_LEN(unquoted) + 3, quoted, "'%q'", ZSTR_VAL(unquoted));
+ zend_string *quoted_str = zend_string_init(quoted, strlen(quoted), 0);
+ efree(quoted);
+ return quoted_str;
+}
+
+static bool sqlite_handle_begin(pdo_dbh_t *dbh) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+
+ if (sqlite3_exec(H->db, "BEGIN", NULL, NULL, NULL) != SQLITE_OK) {
+ pdo_sqlite_error(dbh);
+ return false;
+ }
+ return true;
+}
+
+static bool sqlite_handle_commit(pdo_dbh_t *dbh) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+
+ if (sqlite3_exec(H->db, "COMMIT", NULL, NULL, NULL) != SQLITE_OK) {
+ pdo_sqlite_error(dbh);
+ return false;
+ }
+ return true;
+}
+
+static bool sqlite_handle_rollback(pdo_dbh_t *dbh) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+
+ if (sqlite3_exec(H->db, "ROLLBACK", NULL, NULL, NULL) != SQLITE_OK) {
+ pdo_sqlite_error(dbh);
+ return false;
+ }
+ return true;
+}
+
+static int pdo_sqlite_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_value) {
+ switch (attr) {
+ case PDO_ATTR_CLIENT_VERSION:
+ case PDO_ATTR_SERVER_VERSION:
+ ZVAL_STRING(return_value, (char *) sqlite3_libversion());
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static bool pdo_sqlite_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ zend_long lval;
+
+ switch (attr) {
+ case PDO_ATTR_TIMEOUT:
+ if (!pdo_get_long_param(&lval, val)) {
+ return false;
+ }
+ sqlite3_busy_timeout(H->db, lval * 1000);
+ return true;
+ case PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES:
+ if (!pdo_get_long_param(&lval, val)) {
+ return false;
+ }
+ sqlite3_extended_result_codes(H->db, lval);
+ return true;
+ }
+ return false;
+}
+
+typedef struct {
+ zval val;
+ zend_long row;
+} aggregate_context;
+
+static int do_callback(
+ struct pdo_sqlite_fci *fc, zval *cb, int argc, sqlite3_value **argv, sqlite3_context *context, int is_agg) {
+ zval *zargs = NULL;
+ zval retval;
+ int i;
+ int ret;
+ int fake_argc;
+ aggregate_context *agg_context = NULL;
+
+ if (is_agg) {
+ is_agg = 2;
+ }
+
+ fake_argc = argc + is_agg;
+
+ fc->fci.size = sizeof(fc->fci);
+ ZVAL_COPY_VALUE(&fc->fci.function_name, cb);
+ fc->fci.object = NULL;
+ fc->fci.retval = &retval;
+ fc->fci.param_count = fake_argc;
+
+ /* build up the params */
+
+ if (fake_argc) {
+ zargs = safe_emalloc(fake_argc, sizeof(zval), 0);
+ }
+
+ if (is_agg) {
+ agg_context = sqlite3_aggregate_context(context, sizeof(aggregate_context));
+ if (!agg_context) {
+ efree(zargs);
+ return FAILURE;
+ }
+ if (Z_ISUNDEF(agg_context->val)) {
+ ZVAL_NEW_REF(&agg_context->val, &EG(uninitialized_zval));
+ }
+ ZVAL_COPY_VALUE(&zargs[0], &agg_context->val);
+ ZVAL_LONG(&zargs[1], ++agg_context->row);
+ }
+
+ for (i = 0; i < argc; i++) {
+ /* get the value */
+ switch (sqlite3_value_type(argv[i])) {
+ case SQLITE_INTEGER:
+ ZVAL_LONG(&zargs[i + is_agg], sqlite3_value_int(argv[i]));
+ break;
+
+ case SQLITE_FLOAT:
+ ZVAL_DOUBLE(&zargs[i + is_agg], sqlite3_value_double(argv[i]));
+ break;
+
+ case SQLITE_NULL:
+ ZVAL_NULL(&zargs[i + is_agg]);
+ break;
+
+ case SQLITE_BLOB:
+ case SQLITE3_TEXT:
+ default:
+ ZVAL_STRINGL(&zargs[i + is_agg], (char *) sqlite3_value_text(argv[i]), sqlite3_value_bytes(argv[i]));
+ break;
+ }
+ }
+
+ fc->fci.params = zargs;
+
+ HOOK_PHP_CALL_STACK(ret = zend_call_function(&fc->fci, &fc->fcc););
+ if (ret == FAILURE) {
+ php_error_docref(NULL, E_WARNING, "An error occurred while invoking the callback");
+ }
+
+ /* clean up the params */
+ if (zargs) {
+ for (i = is_agg; i < fake_argc; i++) {
+ zval_ptr_dtor(&zargs[i]);
+ }
+ if (is_agg) {
+ zval_ptr_dtor(&zargs[1]);
+ }
+ efree(zargs);
+ }
+
+ if (!is_agg || !argv) {
+ /* only set the sqlite return value if we are a scalar function,
+ * or if we are finalizing an aggregate */
+ if (!Z_ISUNDEF(retval)) {
+ switch (Z_TYPE(retval)) {
+ case IS_LONG:
+ sqlite3_result_int(context, Z_LVAL(retval));
+ break;
+
+ case IS_NULL:
+ sqlite3_result_null(context);
+ break;
+
+ case IS_DOUBLE:
+ sqlite3_result_double(context, Z_DVAL(retval));
+ break;
+
+ default:
+ if (!try_convert_to_string(&retval)) {
+ ret = FAILURE;
+ break;
+ }
+ sqlite3_result_text(context, Z_STRVAL(retval), Z_STRLEN(retval), SQLITE_TRANSIENT);
+ break;
+ }
+ } else {
+ sqlite3_result_error(context, "failed to invoke callback", 0);
+ }
+
+ if (agg_context) {
+ zval_ptr_dtor(&agg_context->val);
+ }
+ } else {
+ /* we're stepping in an aggregate; the return value goes into
+ * the context */
+ if (agg_context) {
+ if (Z_ISUNDEF(retval)) {
+ zval_ptr_dtor(&agg_context->val);
+ return FAILURE;
+ }
+ zval_ptr_dtor(Z_REFVAL(agg_context->val));
+ ZVAL_COPY_VALUE(Z_REFVAL(agg_context->val), &retval);
+ ZVAL_UNDEF(&retval);
+ }
+ }
+
+ if (!Z_ISUNDEF(retval)) {
+ zval_ptr_dtor(&retval);
+ }
+
+ return ret;
+}
+
+static void php_sqlite3_func_callback(sqlite3_context *context, int argc, sqlite3_value **argv) {
+ struct pdo_sqlite_func *func = (struct pdo_sqlite_func *) sqlite3_user_data(context);
+
+ do_callback(&func->afunc, &func->func, argc, argv, context, 0);
+}
+
+static void php_sqlite3_func_step_callback(sqlite3_context *context, int argc, sqlite3_value **argv) {
+ struct pdo_sqlite_func *func = (struct pdo_sqlite_func *) sqlite3_user_data(context);
+
+ do_callback(&func->astep, &func->step, argc, argv, context, 1);
+}
+
+static void php_sqlite3_func_final_callback(sqlite3_context *context) {
+ struct pdo_sqlite_func *func = (struct pdo_sqlite_func *) sqlite3_user_data(context);
+
+ do_callback(&func->afini, &func->fini, 0, NULL, context, 1);
+}
+
+static int php_sqlite3_collation_callback(
+ void *context, int string1_len, const void *string1, int string2_len, const void *string2) {
+ int ret;
+ zval zargs[2];
+ zval retval;
+ struct pdo_sqlite_collation *collation = (struct pdo_sqlite_collation *) context;
+
+ collation->fc.fci.size = sizeof(collation->fc.fci);
+ ZVAL_COPY_VALUE(&collation->fc.fci.function_name, &collation->callback);
+ collation->fc.fci.object = NULL;
+ collation->fc.fci.retval = &retval;
+
+ // Prepare the arguments.
+ ZVAL_STRINGL(&zargs[0], (char *) string1, string1_len);
+ ZVAL_STRINGL(&zargs[1], (char *) string2, string2_len);
+ collation->fc.fci.param_count = 2;
+ collation->fc.fci.params = zargs;
+
+ HOOK_PHP_CALL_STACK(ret = zend_call_function(&collation->fc.fci, &collation->fc.fcc););
+ if (ret == FAILURE) {
+ php_error_docref(NULL, E_WARNING, "An error occurred while invoking the callback");
+ } else if (!Z_ISUNDEF(retval)) {
+ if (Z_TYPE(retval) != IS_LONG) {
+ convert_to_long(&retval);
+ }
+ ret = 0;
+ if (Z_LVAL(retval) > 0) {
+ ret = 1;
+ } else if (Z_LVAL(retval) < 0) {
+ ret = -1;
+ }
+ zval_ptr_dtor(&retval);
+ }
+
+ zval_ptr_dtor(&zargs[0]);
+ zval_ptr_dtor(&zargs[1]);
+
+ return ret;
+}
+
+/* {{{ bool SQLite::sqliteCreateFunction(string name, callable callback [, int argcount, int flags])
+ Registers a UDF with the sqlite db handle */
+PHP_METHOD(PDO_SQLite_Ext, sqliteCreateFunction) {
+ struct pdo_sqlite_func *func;
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ char *func_name;
+ size_t func_name_len;
+ zend_long argc = -1;
+ zend_long flags = 0;
+ pdo_dbh_t *dbh;
+ pdo_sqlite_db_handle *H;
+ int ret;
+
+ ZEND_PARSE_PARAMETERS_START(2, 4)
+ Z_PARAM_STRING(func_name, func_name_len)
+ Z_PARAM_FUNC(fci, fcc)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_LONG(argc)
+ Z_PARAM_LONG(flags)
+ ZEND_PARSE_PARAMETERS_END();
+
+ dbh = Z_PDO_DBH_P(ZEND_THIS);
+ PDO_CONSTRUCT_CHECK;
+
+ H = (pdo_sqlite_db_handle *) dbh->driver_data;
+
+ func = (struct pdo_sqlite_func *) ecalloc(1, sizeof(*func));
+
+ ret = sqlite3_create_function(
+ H->db, func_name, argc, flags | SQLITE_UTF8, func, php_sqlite3_func_callback, NULL, NULL);
+ if (ret == SQLITE_OK) {
+ func->funcname = estrdup(func_name);
+
+ ZVAL_COPY(&func->func, &fci.function_name);
+
+ func->argc = argc;
+
+ func->next = H->funcs;
+ H->funcs = func;
+
+ RETURN_TRUE;
+ }
+
+ efree(func);
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ bool SQLite::sqliteCreateAggregate(string name, callable step, callable fini [, int argcount])
+ Registers a UDF with the sqlite db handle */
+
+/* The step function should have the prototype:
+ mixed step(mixed $context, int $rownumber, $value [, $value2 [, ...]])
+
+ $context will be null for the first row; on subsequent rows it will have
+ the value that was previously returned from the step function; you should
+ use this to maintain state for the aggregate.
+
+ The fini function should have the prototype:
+ mixed fini(mixed $context, int $rownumber)
+
+ $context will hold the return value from the very last call to the step function.
+ rownumber will hold the number of rows over which the aggregate was performed.
+ The return value of this function will be used as the return value for this
+ aggregate UDF.
+*/
+
+PHP_METHOD(PDO_SQLite_Ext, sqliteCreateAggregate) {
+ struct pdo_sqlite_func *func;
+ zend_fcall_info step_fci, fini_fci;
+ zend_fcall_info_cache step_fcc, fini_fcc;
+ char *func_name;
+ size_t func_name_len;
+ zend_long argc = -1;
+ pdo_dbh_t *dbh;
+ pdo_sqlite_db_handle *H;
+ int ret;
+
+ ZEND_PARSE_PARAMETERS_START(3, 4)
+ Z_PARAM_STRING(func_name, func_name_len)
+ Z_PARAM_FUNC(step_fci, step_fcc)
+ Z_PARAM_FUNC(fini_fci, fini_fcc)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_LONG(argc)
+ ZEND_PARSE_PARAMETERS_END();
+
+ dbh = Z_PDO_DBH_P(ZEND_THIS);
+ PDO_CONSTRUCT_CHECK;
+
+ H = (pdo_sqlite_db_handle *) dbh->driver_data;
+
+ func = (struct pdo_sqlite_func *) ecalloc(1, sizeof(*func));
+
+ ret = sqlite3_create_function(H->db,
+ func_name,
+ argc,
+ SQLITE_UTF8,
+ func,
+ NULL,
+ php_sqlite3_func_step_callback,
+ php_sqlite3_func_final_callback);
+ if (ret == SQLITE_OK) {
+ func->funcname = estrdup(func_name);
+
+ ZVAL_COPY(&func->step, &step_fci.function_name);
+
+ ZVAL_COPY(&func->fini, &fini_fci.function_name);
+
+ func->argc = argc;
+
+ func->next = H->funcs;
+ H->funcs = func;
+
+ RETURN_TRUE;
+ }
+
+ efree(func);
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ bool SQLite::sqliteCreateCollation(string name, callable callback)
+ Registers a collation with the sqlite db handle */
+PHP_METHOD(PDO_SQLite_Ext, sqliteCreateCollation) {
+ struct pdo_sqlite_collation *collation;
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ char *collation_name;
+ size_t collation_name_len;
+ pdo_dbh_t *dbh;
+ pdo_sqlite_db_handle *H;
+ int ret;
+
+ ZEND_PARSE_PARAMETERS_START(2, 2)
+ Z_PARAM_STRING(collation_name, collation_name_len)
+ Z_PARAM_FUNC(fci, fcc)
+ ZEND_PARSE_PARAMETERS_END();
+
+ dbh = Z_PDO_DBH_P(ZEND_THIS);
+ PDO_CONSTRUCT_CHECK;
+
+ H = (pdo_sqlite_db_handle *) dbh->driver_data;
+
+ collation = (struct pdo_sqlite_collation *) ecalloc(1, sizeof(*collation));
+
+ ret = sqlite3_create_collation(H->db, collation_name, SQLITE_UTF8, collation, php_sqlite3_collation_callback);
+ if (ret == SQLITE_OK) {
+ collation->name = estrdup(collation_name);
+
+ ZVAL_COPY(&collation->callback, &fci.function_name);
+
+ collation->next = H->collations;
+ H->collations = collation;
+
+ RETURN_TRUE;
+ }
+
+ efree(collation);
+ RETURN_FALSE;
+}
+/* }}} */
+
+static const zend_function_entry *get_driver_methods(pdo_dbh_t *dbh, int kind) {
+ switch (kind) {
+ case PDO_DBH_DRIVER_METHOD_KIND_DBH:
+ return class_PDO_SQLite_Ext_methods;
+
+ default:
+ return NULL;
+ }
+}
+
+static void pdo_sqlite_request_shutdown(pdo_dbh_t *dbh) {
+ pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *) dbh->driver_data;
+ /* unregister functions, so that they don't linger for the next
+ * request */
+ if (H) {
+ pdo_sqlite_cleanup_callbacks(H);
+ }
+}
+
+static void pdo_sqlite_get_gc(pdo_dbh_t *dbh, zend_get_gc_buffer *gc_buffer) {
+ pdo_sqlite_db_handle *H = dbh->driver_data;
+
+ struct pdo_sqlite_func *func = H->funcs;
+ while (func) {
+ zend_get_gc_buffer_add_zval(gc_buffer, &func->func);
+ zend_get_gc_buffer_add_zval(gc_buffer, &func->step);
+ zend_get_gc_buffer_add_zval(gc_buffer, &func->fini);
+ func = func->next;
+ }
+
+ struct pdo_sqlite_collation *collation = H->collations;
+ while (collation) {
+ zend_get_gc_buffer_add_zval(gc_buffer, &collation->callback);
+ collation = collation->next;
+ }
+}
+
+static const struct pdo_dbh_methods sqlite_methods = {sqlite_handle_closer,
+ sqlite_handle_preparer,
+ sqlite_handle_doer,
+ sqlite_handle_quoter,
+ sqlite_handle_begin,
+ sqlite_handle_commit,
+ sqlite_handle_rollback,
+ pdo_sqlite_set_attr,
+ pdo_sqlite_last_insert_id,
+ pdo_sqlite_fetch_error_func,
+ pdo_sqlite_get_attribute,
+ NULL, /* check_liveness: not needed */
+ get_driver_methods,
+ pdo_sqlite_request_shutdown,
+ NULL, /* in transaction, use PDO's internal tracking mechanism */
+ pdo_sqlite_get_gc};
+
+static char *make_filename_safe(const char *filename) {
+ if (!filename) {
+ return NULL;
+ }
+ if (*filename && strncasecmp(filename, "file:", 5) == 0) {
+ if (PG(open_basedir) && *PG(open_basedir)) {
+ return NULL;
+ }
+ return estrdup(filename);
+ }
+ if (*filename && memcmp(filename, ":memory:", sizeof(":memory:"))) {
+ char *fullpath = expand_filepath(filename, NULL);
+
+ if (!fullpath) {
+ return NULL;
+ }
+
+ if (php_check_open_basedir(fullpath)) {
+ efree(fullpath);
+ return NULL;
+ }
+ return fullpath;
+ }
+ return estrdup(filename);
+}
+
+static int authorizer(
+ void *autharg, int access_type, const char *arg3, const char *arg4, const char *arg5, const char *arg6) {
+ char *filename;
+ switch (access_type) {
+ case SQLITE_ATTACH: {
+ filename = make_filename_safe(arg3);
+ if (!filename) {
+ return SQLITE_DENY;
+ }
+ efree(filename);
+ return SQLITE_OK;
+ }
+
+ default:
+ /* access allowed */
+ return SQLITE_OK;
+ }
+}
+
+static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ */
+{
+ pdo_sqlite_db_handle *H;
+ int i, ret = 0;
+ zend_long timeout = 60, flags;
+ char *filename;
+
+ H = pecalloc(1, sizeof(pdo_sqlite_db_handle), dbh->is_persistent);
+
+ H->einfo.errcode = 0;
+ H->einfo.errmsg = NULL;
+ dbh->driver_data = H;
+
+ /* skip all but this one param event */
+ dbh->skip_param_evt = 0x7F ^ (1 << PDO_PARAM_EVT_EXEC_PRE);
+
+ filename = make_filename_safe(dbh->data_source);
+
+ if (!filename) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0, "open_basedir prohibits opening %s", dbh->data_source);
+ goto cleanup;
+ }
+
+ flags = pdo_attr_lval(driver_options, PDO_SQLITE_ATTR_OPEN_FLAGS, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
+
+ if (!(PG(open_basedir) && *PG(open_basedir))) {
+ flags |= SQLITE_OPEN_URI;
+ }
+ i = sqlite3_open_v2(filename, &H->db, flags, NULL);
+
+ efree(filename);
+
+ if (i != SQLITE_OK) {
+ pdo_sqlite_error(dbh);
+ goto cleanup;
+ }
+
+ if (PG(open_basedir) && *PG(open_basedir)) {
+ sqlite3_set_authorizer(H->db, authorizer, NULL);
+ }
+
+ if (driver_options) {
+ timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, timeout);
+ }
+ sqlite3_busy_timeout(H->db, timeout * 1000);
+
+ dbh->alloc_own_columns = 1;
+ dbh->max_escaped_char_length = 2;
+
+ ret = 1;
+
+cleanup:
+ dbh->methods = &sqlite_methods;
+
+ return ret;
+}
+/* }}} */
+
+const pdo_driver_t swoole_pdo_sqlite_driver = {PDO_DRIVER_HEADER(sqlite), pdo_sqlite_handle_factory};
+#endif
diff --git a/thirdparty/php83/pdo_sqlite/sqlite_driver.stub.php b/thirdparty/php83/pdo_sqlite/sqlite_driver.stub.php
new file mode 100644
index 00000000000..add395f2b99
--- /dev/null
+++ b/thirdparty/php83/pdo_sqlite/sqlite_driver.stub.php
@@ -0,0 +1,18 @@
+ |
+ +----------------------------------------------------------------------+
+*/
+
+#define SW_USE_SQLITE_HOOK
+#include "php_swoole_sqlite.h"
+
+#if PHP_VERSION_ID >= 80300
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "pdo/php_pdo.h"
+
+static int pdo_sqlite_stmt_dtor(pdo_stmt_t *stmt) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+
+ if (S->stmt) {
+ sqlite3_finalize(S->stmt);
+ S->stmt = NULL;
+ }
+ efree(S);
+ return 1;
+}
+
+static int pdo_sqlite_stmt_execute(pdo_stmt_t *stmt) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+
+ if (stmt->executed && !S->done) {
+ sqlite3_reset(S->stmt);
+ }
+
+ S->done = 0;
+ switch (sqlite3_step(S->stmt)) {
+ case SQLITE_ROW:
+ S->pre_fetched = 1;
+ php_pdo_stmt_set_column_count(stmt, sqlite3_data_count(S->stmt));
+ return 1;
+
+ case SQLITE_DONE:
+ php_pdo_stmt_set_column_count(stmt, sqlite3_column_count(S->stmt));
+ stmt->row_count = sqlite3_changes(S->H->db);
+ sqlite3_reset(S->stmt);
+ S->done = 1;
+ return 1;
+
+ case SQLITE_ERROR:
+ sqlite3_reset(S->stmt);
+ ZEND_FALLTHROUGH;
+ case SQLITE_MISUSE:
+ case SQLITE_BUSY:
+ default:
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ }
+}
+
+static int pdo_sqlite_stmt_param_hook(pdo_stmt_t *stmt,
+ struct pdo_bound_param_data *param,
+ enum pdo_param_event event_type) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ zval *parameter;
+
+ switch (event_type) {
+ case PDO_PARAM_EVT_EXEC_PRE:
+ if (stmt->executed && !S->done) {
+ sqlite3_reset(S->stmt);
+ S->done = 1;
+ }
+
+ if (param->is_param) {
+ if (param->paramno == -1) {
+ param->paramno = sqlite3_bind_parameter_index(S->stmt, ZSTR_VAL(param->name)) - 1;
+ }
+
+ switch (PDO_PARAM_TYPE(param->param_type)) {
+ case PDO_PARAM_STMT:
+ return 0;
+
+ case PDO_PARAM_NULL:
+ if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
+ return 1;
+ }
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+
+ case PDO_PARAM_INT:
+ case PDO_PARAM_BOOL:
+ if (Z_ISREF(param->parameter)) {
+ parameter = Z_REFVAL(param->parameter);
+ } else {
+ parameter = ¶m->parameter;
+ }
+ if (Z_TYPE_P(parameter) == IS_NULL) {
+ if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
+ return 1;
+ }
+ } else {
+ convert_to_long(parameter);
+#if ZEND_LONG_MAX > 2147483647
+ if (SQLITE_OK == sqlite3_bind_int64(S->stmt, param->paramno + 1, Z_LVAL_P(parameter))) {
+ return 1;
+ }
+#else
+ if (SQLITE_OK == sqlite3_bind_int(S->stmt, param->paramno + 1, Z_LVAL_P(parameter))) {
+ return 1;
+ }
+#endif
+ }
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+
+ case PDO_PARAM_LOB:
+ if (Z_ISREF(param->parameter)) {
+ parameter = Z_REFVAL(param->parameter);
+ } else {
+ parameter = ¶m->parameter;
+ }
+ if (Z_TYPE_P(parameter) == IS_RESOURCE) {
+ php_stream *stm = NULL;
+ php_stream_from_zval_no_verify(stm, parameter);
+ if (stm) {
+ zend_string *mem = php_stream_copy_to_mem(stm, PHP_STREAM_COPY_ALL, 0);
+ zval_ptr_dtor(parameter);
+ ZVAL_STR(parameter, mem ? mem : ZSTR_EMPTY_ALLOC());
+ } else {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource");
+ return 0;
+ }
+ } else if (Z_TYPE_P(parameter) == IS_NULL) {
+ if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
+ return 1;
+ }
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ } else {
+ if (!try_convert_to_string(parameter)) {
+ return 0;
+ }
+ }
+
+ if (SQLITE_OK ==
+ sqlite3_bind_blob(
+ S->stmt, param->paramno + 1, Z_STRVAL_P(parameter), Z_STRLEN_P(parameter), SQLITE_STATIC)) {
+ return 1;
+ }
+ return 0;
+
+ case PDO_PARAM_STR:
+ default:
+ if (Z_ISREF(param->parameter)) {
+ parameter = Z_REFVAL(param->parameter);
+ } else {
+ parameter = ¶m->parameter;
+ }
+ if (Z_TYPE_P(parameter) == IS_NULL) {
+ if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
+ return 1;
+ }
+ } else {
+ if (!try_convert_to_string(parameter)) {
+ return 0;
+ }
+ if (SQLITE_OK ==
+ sqlite3_bind_text(
+ S->stmt, param->paramno + 1, Z_STRVAL_P(parameter), Z_STRLEN_P(parameter), SQLITE_STATIC)) {
+ return 1;
+ }
+ }
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ }
+ }
+ break;
+
+ default:;
+ }
+ return 1;
+}
+
+static int pdo_sqlite_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, zend_long offset) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ int i;
+ if (!S->stmt) {
+ return 0;
+ }
+ if (S->pre_fetched) {
+ S->pre_fetched = 0;
+ return 1;
+ }
+ if (S->done) {
+ return 0;
+ }
+ i = sqlite3_step(S->stmt);
+ switch (i) {
+ case SQLITE_ROW:
+ return 1;
+
+ case SQLITE_DONE:
+ S->done = 1;
+ sqlite3_reset(S->stmt);
+ return 0;
+
+ case SQLITE_ERROR:
+ sqlite3_reset(S->stmt);
+ ZEND_FALLTHROUGH;
+ default:
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ }
+}
+
+static int pdo_sqlite_stmt_describe(pdo_stmt_t *stmt, int colno) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ const char *str;
+
+ if (colno >= sqlite3_column_count(S->stmt)) {
+ /* error invalid column */
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ }
+
+ str = sqlite3_column_name(S->stmt, colno);
+ stmt->columns[colno].name = zend_string_init(str, strlen(str), 0);
+ stmt->columns[colno].maxlen = SIZE_MAX;
+ stmt->columns[colno].precision = 0;
+
+ return 1;
+}
+
+static int pdo_sqlite_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo_param_type *type) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ if (!S->stmt) {
+ return 0;
+ }
+ if (colno >= sqlite3_data_count(S->stmt)) {
+ /* error invalid column */
+ pdo_sqlite_error_stmt(stmt);
+ return 0;
+ }
+ switch (sqlite3_column_type(S->stmt, colno)) {
+ case SQLITE_NULL:
+ ZVAL_NULL(result);
+ return 1;
+
+ case SQLITE_INTEGER: {
+ int64_t i = sqlite3_column_int64(S->stmt, colno);
+#if SIZEOF_ZEND_LONG < 8
+ if (i > ZEND_LONG_MAX || i < ZEND_LONG_MIN) {
+ ZVAL_STRINGL(result, (char *) sqlite3_column_text(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno));
+ return 1;
+ }
+#endif
+ ZVAL_LONG(result, i);
+ return 1;
+ }
+
+ case SQLITE_FLOAT:
+ ZVAL_DOUBLE(result, sqlite3_column_double(S->stmt, colno));
+ return 1;
+
+ case SQLITE_BLOB:
+ ZVAL_STRINGL_FAST(result, sqlite3_column_blob(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno));
+ return 1;
+
+ default:
+ ZVAL_STRINGL_FAST(result, (char *) sqlite3_column_text(S->stmt, colno), sqlite3_column_bytes(S->stmt, colno));
+ return 1;
+ }
+}
+
+static int pdo_sqlite_stmt_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ const char *str;
+ zval flags;
+
+ if (!S->stmt) {
+ return FAILURE;
+ }
+ if (colno >= sqlite3_column_count(S->stmt)) {
+ /* error invalid column */
+ pdo_sqlite_error_stmt(stmt);
+ return FAILURE;
+ }
+
+ array_init(return_value);
+ array_init(&flags);
+
+ switch (sqlite3_column_type(S->stmt, colno)) {
+ case SQLITE_NULL:
+ add_assoc_str(return_value, "native_type", ZSTR_KNOWN(ZEND_STR_NULL_LOWERCASE));
+ add_assoc_long(return_value, "pdo_type", PDO_PARAM_NULL);
+ break;
+
+ case SQLITE_FLOAT:
+ add_assoc_str(return_value, "native_type", ZSTR_KNOWN(ZEND_STR_DOUBLE));
+ add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
+ break;
+
+ case SQLITE_BLOB:
+ add_next_index_string(&flags, "blob");
+ /* TODO Check this is correct */
+ ZEND_FALLTHROUGH;
+ case SQLITE_TEXT:
+ add_assoc_str(return_value, "native_type", ZSTR_KNOWN(ZEND_STR_STRING));
+ add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR);
+ break;
+
+ case SQLITE_INTEGER:
+ add_assoc_str(return_value, "native_type", ZSTR_KNOWN(ZEND_STR_INTEGER));
+ add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT);
+ break;
+ }
+
+ str = sqlite3_column_decltype(S->stmt, colno);
+ if (str) {
+ add_assoc_string(return_value, "sqlite:decl_type", (char *) str);
+ }
+
+#ifdef HAVE_SW_SQLITE3_COLUMN_TABLE_NAME
+ str = sqlite3_column_table_name(S->stmt, colno);
+ if (str) {
+ add_assoc_string(return_value, "table", (char *) str);
+ }
+#endif
+
+ add_assoc_zval(return_value, "flags", &flags);
+
+ return SUCCESS;
+}
+
+static int pdo_sqlite_stmt_cursor_closer(pdo_stmt_t *stmt) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+ sqlite3_reset(S->stmt);
+ return 1;
+}
+
+static int pdo_sqlite_stmt_get_attribute(pdo_stmt_t *stmt, zend_long attr, zval *val) {
+ pdo_sqlite_stmt *S = (pdo_sqlite_stmt *) stmt->driver_data;
+
+ switch (attr) {
+ case PDO_SQLITE_ATTR_READONLY_STATEMENT:
+ ZVAL_FALSE(val);
+
+#if SQLITE_VERSION_NUMBER >= 3007004
+ if (sqlite3_stmt_readonly(S->stmt)) {
+ ZVAL_TRUE(val);
+ }
+#endif
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+const struct pdo_stmt_methods swoole_sqlite_stmt_methods = {pdo_sqlite_stmt_dtor,
+ pdo_sqlite_stmt_execute,
+ pdo_sqlite_stmt_fetch,
+ pdo_sqlite_stmt_describe,
+ pdo_sqlite_stmt_get_col,
+ pdo_sqlite_stmt_param_hook,
+ NULL, /* set_attr */
+ pdo_sqlite_stmt_get_attribute, /* get_attr */
+ pdo_sqlite_stmt_col_meta,
+ NULL, /* next_rowset */
+ pdo_sqlite_stmt_cursor_closer};
+#endif