Skip to content

Commit d54258b

Browse files
authored
add --enable-thread-context option (swoole#3970)
* Support Apple m1 system * fix bug * fix bug [2] * fix
1 parent 7f54ce2 commit d54258b

File tree

17 files changed

+201
-180
lines changed

17 files changed

+201
-180
lines changed

config.m4

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ PHP_ARG_ENABLE(swoole-json, whether to enable Swoole JSON build flags,
5858
PHP_ARG_ENABLE(swoole-curl, whether to enable Swoole CURL build flags,
5959
[ --enable-swoole-curl Enable cURL support], no, no)
6060

61+
PHP_ARG_ENABLE(thread-context, whether to enable thread context,
62+
[ --enable-thread-context Use thread context], no, no)
63+
6164
AC_DEFUN([SWOOLE_HAVE_PHP_EXT], [
6265
extname=$1
6366
haveext=$[PHP_]translit($1,a-z_-,A-Z__)
@@ -671,6 +674,11 @@ if test "$PHP_SWOOLE" != "no"; then
671674
else
672675
SW_USE_ASM_CONTEXT="no"
673676
fi
677+
678+
if test "$PHP_THREAD_CONTEXT" != "no"; then
679+
AC_DEFINE(SW_USE_THREAD_CONTEXT, 1, [do we enable thread context])
680+
SW_USE_ASM_CONTEXT="no"
681+
fi
674682

675683
if test "$SW_USE_ASM_CONTEXT" = "yes"; then
676684
swoole_source_file="$swoole_source_file \

examples/coroutine/coro_empty.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
<?php
2-
use Swoole\Coroutine as co;
32
// co::set(['trace_flags' => 1]);
43

5-
var_dump(SWOOLE_CORO_SCHEDULE);
64
co::create(function () {
75
echo "no coro exit\n";
86
});

ext-src/php_swoole.cc

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -813,16 +813,19 @@ PHP_MINFO_FUNCTION(swoole) {
813813
php_info_print_table_row(2, "Version", SWOOLE_VERSION);
814814
snprintf(buf, sizeof(buf), "%s %s", __DATE__, __TIME__);
815815
php_info_print_table_row(2, "Built", buf);
816-
php_info_print_table_row(2, "coroutine", "enabled");
816+
#if defined(SW_USE_THREAD_CONTEXT)
817+
php_info_print_table_row(2, "coroutine", "enabled with thread context");
818+
#elif defined(SW_USE_ASM_CONTEXT)
819+
php_info_print_table_row(2, "coroutine", "enabled with boost asm context");
820+
#else
821+
php_info_print_table_row(2, "coroutine", "enabled with ucontext");
822+
#endif
817823
#ifdef SW_DEBUG
818824
php_info_print_table_row(2, "debug", "enabled");
819825
#endif
820826
#ifdef SW_LOG_TRACE_OPEN
821827
php_info_print_table_row(2, "trace_log", "enabled");
822828
#endif
823-
#ifdef SW_NO_USE_ASM_CONTEXT
824-
php_info_print_table_row(2, "ucontext", "enabled");
825-
#endif
826829
#ifdef HAVE_EPOLL
827830
php_info_print_table_row(2, "epoll", "enabled");
828831
#endif

ext-src/php_swoole.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ extern zend_module_entry swoole_module_entry;
100100
#error "require PHP version 7.2 or later"
101101
#endif
102102

103+
#if defined(ZTS) && defined(SW_USE_THREAD_CONTEXT)
104+
#error "thread context cannot be used with ZTS"
105+
#endif
106+
103107
//--------------------------------------------------------
104108
#define SW_MAX_FIND_COUNT 100 //for swoole_server::connection_list
105109
#define SW_PHP_CLIENT_BUFFER_SIZE 65535

ext-src/swoole_coroutine.cc

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,10 @@ void PHPCoroutine::activate() {
340340
/* update the last coroutine's info */
341341
save_task(get_context());
342342
}
343-
bool _ori_value = config.enable_deadlock_check;
344-
config.enable_deadlock_check = false;
345-
swoole_event_free();
346-
config.enable_deadlock_check = _ori_value;
343+
if (sw_reactor()) {
344+
sw_reactor()->running = false;
345+
sw_reactor()->bailout = true;
346+
}
347347
}
348348
if (sw_likely(orig_error_function)) {
349349
orig_error_function(type, error_filename, error_lineno, ZEND_ERROR_CB_LAST_ARG_RELAY);
@@ -381,7 +381,7 @@ void PHPCoroutine::deadlock_check() {
381381
if (Coroutine::count() == 0) {
382382
return;
383383
}
384-
if (php_swoole_is_fatal_error()) {
384+
if (php_swoole_is_fatal_error() || (sw_reactor() && sw_reactor()->bailout)) {
385385
return;
386386
}
387387
if (SWOOLE_G(enable_library)) {
@@ -769,7 +769,10 @@ void PHPCoroutine::main_func(void *arg) {
769769
}
770770
zend_catch {
771771
Coroutine::bailout([]() {
772-
swoole_event_free();
772+
if (sw_reactor()) {
773+
sw_reactor()->running = false;
774+
sw_reactor()->bailout = true;
775+
}
773776
sw_zend_bailout();
774777
});
775778
}
@@ -938,8 +941,14 @@ PHP_METHOD(swoole_coroutine, stats) {
938941
add_assoc_long_ex(return_value, ZEND_STRL("event_num"), SwooleTG.reactor ? SwooleTG.reactor->event_num : 0);
939942
add_assoc_long_ex(
940943
return_value, ZEND_STRL("signal_listener_num"), SwooleTG.signal_listener_num + SwooleTG.co_signal_listener_num);
941-
add_assoc_long_ex(return_value, ZEND_STRL("aio_task_num"), SwooleTG.aio_task_num);
942-
add_assoc_long_ex(return_value, ZEND_STRL("aio_worker_num"), swoole::async::thread_count());
944+
945+
if (SwooleTG.async_threads) {
946+
add_assoc_long_ex(return_value, ZEND_STRL("aio_task_num"), SwooleTG.async_threads->task_num);
947+
add_assoc_long_ex(return_value, ZEND_STRL("aio_worker_num"), SwooleTG.async_threads->thread_count());
948+
} else {
949+
add_assoc_long_ex(return_value, ZEND_STRL("aio_task_num"), 0);
950+
add_assoc_long_ex(return_value, ZEND_STRL("aio_worker_num"), 0);
951+
}
943952
add_assoc_long_ex(return_value, ZEND_STRL("c_stack_size"), Coroutine::get_stack_size());
944953
add_assoc_long_ex(return_value, ZEND_STRL("coroutine_num"), Coroutine::count());
945954
add_assoc_long_ex(return_value, ZEND_STRL("coroutine_peak_num"), Coroutine::get_peak_num());

ext-src/swoole_event.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ void php_swoole_event_wait() {
281281
swSignalfd_setup(sw_reactor());
282282
}
283283
#endif
284-
if (!sw_reactor()->if_exit()) {
284+
if (!sw_reactor()->if_exit() && !sw_reactor()->bailout) {
285285
// Don't disable object slot reuse while running shutdown functions:
286286
// https://github.com/php/php-src/commit/bd6eabd6591ae5a7c9ad75dfbe7cc575fa907eac
287287
#if defined(EG_FLAGS_IN_SHUTDOWN) && !defined(EG_FLAGS_OBJECT_STORE_NO_REUSE)

ext-src/swoole_process.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ static PHP_METHOD(swoole_process, __construct) {
347347
RETURN_FALSE;
348348
}
349349

350-
if (SwooleTG.aio_init) {
350+
if (SwooleTG.async_threads) {
351351
php_swoole_fatal_error(E_ERROR, "unable to create %s with async-io threads", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS));
352352
RETURN_FALSE;
353353
}

include/swoole.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ namespace network {
179179
struct Socket;
180180
struct Address;
181181
} // namespace network
182+
class AsyncThreads;
183+
namespace async {
184+
class ThreadPool;
185+
}
182186
struct Protocol;
183187
struct EventData;
184188
struct DataHead;
@@ -588,12 +592,7 @@ struct ThreadGlobal {
588592
String *buffer_stack;
589593
Reactor *reactor;
590594
Timer *timer;
591-
uint8_t aio_init;
592-
uint8_t aio_schedule;
593-
uint32_t aio_task_num;
594-
Pipe *aio_pipe;
595-
network::Socket *aio_read_socket;
596-
network::Socket *aio_write_socket;
595+
AsyncThreads *async_threads;
597596
uint32_t signal_listener_num;
598597
uint32_t co_signal_listener_num;
599598
int error;

include/swoole_async.h

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,20 @@
2020

2121
#include <vector>
2222
#include <string>
23+
#include <mutex>
24+
#include <atomic>
2325

2426
#ifndef O_DIRECT
2527
#define O_DIRECT 040000
2628
#endif
2729

28-
enum flag {
30+
namespace swoole {
31+
32+
enum AsyncFlags {
2933
SW_AIO_WRITE_FSYNC = 1u << 1,
3034
SW_AIO_EOF = 1u << 2,
3135
};
3236

33-
namespace swoole {
34-
3537
struct AsyncEvent {
3638
int fd;
3739
size_t task_id;
@@ -60,18 +62,31 @@ struct AsyncEvent {
6062
void (*callback)(AsyncEvent *event);
6163
};
6264

65+
class AsyncThreads {
66+
public:
67+
bool schedule = false;
68+
uint32_t task_num = 0;
69+
Pipe *pipe = nullptr;
70+
async::ThreadPool *pool = nullptr;
71+
network::Socket *read_socket = nullptr;
72+
network::Socket *write_socket = nullptr;
73+
74+
AsyncThreads();
75+
~AsyncThreads();
76+
77+
size_t thread_count();
78+
void notify_one();
79+
80+
static int callback(Reactor *reactor, Event *event);
81+
private:
82+
std::mutex init_lock;
83+
};
84+
6385
namespace async {
6486

6587
typedef void (*Handler)(AsyncEvent *event);
6688

6789
AsyncEvent *dispatch(const AsyncEvent *request);
68-
int cancel(int task_id);
69-
int callback(Reactor *reactor, swEvent *_event);
70-
size_t thread_count();
71-
72-
#ifdef SW_DEBUG
73-
void notify_one();
74-
#endif
7590

7691
void handler_gethostbyname(AsyncEvent *event);
7792
void handler_getaddrinfo(AsyncEvent *event);

include/swoole_error.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,13 @@ enum swErrorCode {
167167

168168
SW_ERROR_END
169169
};
170+
171+
namespace swoole {
172+
class Exception {
173+
public:
174+
int code;
175+
const char *msg;
176+
177+
Exception(int code);
178+
};
179+
}

include/swoole_reactor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ class Reactor {
118118
bool once = false;
119119
bool wait_exit = false;
120120
bool destroyed = false;
121+
bool bailout = false;
121122
/**
122123
* callback signal
123124
*/

src/core/base.cc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,8 @@ pid_t swoole_fork(int flags) {
258258
if (swoole_coroutine_is_in()) {
259259
swFatalError(SW_ERROR_OPERATION_NOT_SUPPORT, "must be forked outside the coroutine");
260260
}
261-
if (SwooleTG.aio_init) {
262-
printf("aio_init=%d, aio_task_num=%d, reactor=%p\n",
263-
SwooleTG.aio_init,
264-
SwooleTG.aio_task_num,
265-
SwooleTG.reactor);
261+
if (SwooleTG.async_threads) {
262+
swTrace("aio_task_num=%d, reactor=%p", SwooleTG.async_threads->task_num, SwooleTG.reactor);
266263
swFatalError(SW_ERROR_OPERATION_NOT_SUPPORT, "can not create server after using async file operation");
267264
}
268265
}

src/core/error.cc

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,9 @@
1919
#include "swoole.h"
2020

2121
namespace swoole {
22-
23-
class Exception {
24-
public:
25-
int code;
26-
const char *msg;
27-
28-
Exception(int code) : code(code) {
29-
msg = swoole_strerror(code);
30-
}
31-
};
22+
Exception::Exception(int code) : code(code) {
23+
msg = swoole_strerror(code);
24+
}
3225
} // namespace swoole
3326

3427
const char *swoole_strerror(int code) {

src/coroutine/system.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ void System::init_reactor(Reactor *reactor) {
593593
reactor->set_handler(SW_FD_CORO_EVENT | SW_EVENT_WRITE, event_waiter_write_callback);
594594
reactor->set_handler(SW_FD_CORO_EVENT | SW_EVENT_ERROR, event_waiter_error_callback);
595595

596-
reactor->set_handler(SW_FD_AIO | SW_EVENT_READ, async::callback);
596+
reactor->set_handler(SW_FD_AIO | SW_EVENT_READ, AsyncThreads::callback);
597597
}
598598

599599
static void async_task_completed(AsyncEvent *event) {

src/coroutine/thread_context.cc

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,38 @@
1515
*/
1616

1717
#include "swoole_api.h"
18+
#include "swoole_async.h"
1819
#include "swoole_coroutine_context.h"
1920

2021
#ifdef SW_USE_THREAD_CONTEXT
2122

2223
namespace swoole {
2324
namespace coroutine {
2425

25-
static std::mutex global_lock;
26+
static std::mutex g_lock;
2627
static Reactor *g_reactor = nullptr;
2728
static Timer *g_timer = nullptr;
29+
static String *g_buffer = nullptr;
30+
static AsyncThreads *g_async_threads = nullptr;
2831
static std::mutex *current_lock = nullptr;
2932

30-
static void empty_timer(Timer *timer, TimerNode *tnode) {
31-
// do nothing
32-
}
33-
3433
Context::Context(size_t stack_size, const coroutine_func_t &fn, void *private_data)
3534
: fn_(fn), private_data_(private_data) {
3635
if (sw_unlikely(current_lock == nullptr)) {
37-
current_lock = &global_lock;
38-
g_reactor = SwooleTG.reactor;
36+
current_lock = &g_lock;
3937
if (SwooleTG.timer == nullptr) {
40-
swoole_timer_add(1, 0, empty_timer, nullptr);
38+
swoole_timer_add(1, false, [](Timer *timer, TimerNode *tnode) {
39+
// do nothing
40+
}, nullptr);
41+
}
42+
if (SwooleTG.async_threads == nullptr) {
43+
SwooleTG.async_threads = new AsyncThreads();
4144
}
45+
g_reactor = SwooleTG.reactor;
46+
g_buffer = SwooleTG.buffer_stack;
4247
g_timer = SwooleTG.timer;
43-
global_lock.lock();
48+
g_async_threads = SwooleTG.async_threads;
49+
g_lock.lock();
4450
}
4551
end_ = false;
4652
lock_.lock();
@@ -71,11 +77,13 @@ void Context::context_func(void *arg) {
7177
Context *_this = (Context *) arg;
7278
SwooleTG.reactor = g_reactor;
7379
SwooleTG.timer = g_timer;
80+
SwooleTG.buffer_stack = g_buffer;
81+
SwooleTG.async_threads = g_async_threads;
7482
_this->lock_.lock();
7583
_this->fn_(_this->private_data_);
76-
_this->lock_.unlock();
77-
_this->swap_lock_->unlock();
7884
_this->end_ = true;
85+
current_lock = _this->swap_lock_;
86+
_this->swap_lock_->unlock();
7987
}
8088
} // namespace coroutine
8189
} // namespace swoole

0 commit comments

Comments
 (0)