Skip to content

Commit 8dd0911

Browse files
committed
refactor coroutine_util
1 parent 4072490 commit 8dd0911

8 files changed

+1157
-1065
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ tests/.idea
6868
/tests/swoole_*/*.exp
6969
/tests/swoole_*/*.mem
7070
/tests/swoole_*/*.php
71+
/tests/swoole_library/curl/_skip
7172
/core-tests/server/*.log
7273
cmake-build-debug/
7374
*.cbp

config.m4

+2
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,8 @@ if test "$PHP_SWOOLE" != "no"; then
515515
swoole_client.cc \
516516
swoole_client_coro.cc \
517517
swoole_coroutine.cc \
518+
swoole_coroutine_scheduler.cc \
519+
swoole_coroutine_system.cc \
518520
swoole_coroutine_util.cc \
519521
swoole_event.cc \
520522
swoole_http2_client_coro.cc \

include/coroutine_c_api.h

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern "C"
2626
#include <sys/socket.h>
2727
#include <sys/types.h>
2828
#include <sys/wait.h>
29+
#include <sys/statvfs.h>
2930
#include <stdint.h>
3031
#include <poll.h>
3132

@@ -49,6 +50,7 @@ int swoole_coroutine_rmdir(const char *pathname);
4950
int swoole_coroutine_rename(const char *oldpath, const char *newpath);
5051
int swoole_coroutine_flock(int fd, int operation);
5152
int swoole_coroutine_flock_ex(char *filename, int fd, int operation);
53+
int swoole_coroutine_statvfs(const char *path, struct statvfs *buf);
5254

5355
/**
5456
* socket

swoole_coroutine_scheduler.cc

+291
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Swoole |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 2.0 of the Apache license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| http://www.apache.org/licenses/LICENSE-2.0.html |
9+
| If you did not receive a copy of the Apache2.0 license and are unable|
10+
| to obtain it through the world-wide-web, please send a note to |
11+
| license@swoole.com so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Author: Xinyu Zhu <xyzhu1120@gmail.com> |
14+
| shiguangqi <shiguangqi2008@gmail.com> |
15+
| Tianfeng Han <mikan.tenny@gmail.com> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
#include "swoole_coroutine_scheduler.h"
20+
#include "ext/spl/spl_array.h"
21+
#include "zend_builtin_functions.h"
22+
#include "coroutine_c_api.h"
23+
24+
#include <unordered_map>
25+
26+
using namespace std;
27+
using swoole::coroutine::System;
28+
using swoole::coroutine::Socket;
29+
using swoole::Coroutine;
30+
using swoole::PHPCoroutine;
31+
32+
static zend_class_entry *swoole_coroutine_iterator_ce;
33+
static zend_class_entry *swoole_coroutine_context_ce;
34+
35+
static unordered_map<long, Coroutine *> user_yield_coros;
36+
37+
void swoole_coroutine_scheduler_init(int module_number)
38+
{
39+
SW_INIT_CLASS_ENTRY_BASE(swoole_coroutine_iterator, "Swoole\\Coroutine\\Iterator", NULL, "Co\\Iterator", NULL, spl_ce_ArrayIterator);
40+
SW_INIT_CLASS_ENTRY_BASE(swoole_coroutine_context, "Swoole\\Coroutine\\Context", NULL, "Co\\Context", NULL, spl_ce_ArrayObject);
41+
}
42+
43+
PHP_FUNCTION(swoole_coroutine_create)
44+
{
45+
zend_fcall_info fci = empty_fcall_info;
46+
zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
47+
48+
ZEND_PARSE_PARAMETERS_START(1, -1)
49+
Z_PARAM_FUNC(fci, fci_cache)
50+
Z_PARAM_VARIADIC('*', fci.params, fci.param_count)
51+
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
52+
53+
if (unlikely(SWOOLE_G(req_status) == PHP_SWOOLE_CALL_USER_SHUTDOWNFUNC_BEGIN))
54+
{
55+
zend_function *func = (zend_function *) EG(current_execute_data)->prev_execute_data->func;
56+
if (func->common.function_name && unlikely(memcmp(ZSTR_VAL(func->common.function_name), ZEND_STRS("__destruct")) == 0))
57+
{
58+
swoole_php_fatal_error(E_ERROR, "can not use coroutine in __destruct after php_request_shutdown");
59+
RETURN_FALSE;
60+
}
61+
}
62+
63+
long cid = PHPCoroutine::create(&fci_cache, fci.param_count, fci.params);
64+
if (likely(cid > 0))
65+
{
66+
RETURN_LONG(cid);
67+
}
68+
else
69+
{
70+
RETURN_FALSE;
71+
}
72+
}
73+
74+
PHP_FUNCTION(swoole_coroutine_defer)
75+
{
76+
zend_fcall_info fci = empty_fcall_info;
77+
zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
78+
php_swoole_fci *defer_fci;
79+
80+
ZEND_PARSE_PARAMETERS_START(1, 1)
81+
Z_PARAM_FUNC(fci, fci_cache)
82+
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
83+
84+
Coroutine::get_current_safe();
85+
defer_fci = (php_swoole_fci *) emalloc(sizeof(php_swoole_fci));
86+
defer_fci->fci = fci;
87+
defer_fci->fci_cache = fci_cache;
88+
sw_fci_cache_persist(&defer_fci->fci_cache);
89+
PHPCoroutine::defer(defer_fci);
90+
}
91+
92+
PHP_METHOD(swoole_coroutine_scheduler, set)
93+
{
94+
zval *zset = NULL;
95+
HashTable *vht = NULL;
96+
zval *v;
97+
98+
ZEND_PARSE_PARAMETERS_START(1, 1)
99+
Z_PARAM_ARRAY(zset)
100+
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
101+
102+
vht = Z_ARRVAL_P(zset);
103+
if (php_swoole_array_get_value(vht, "max_coroutine", v))
104+
{
105+
zend_long max_num = zval_get_long(v);
106+
PHPCoroutine::set_max_num(max_num <= 0 ? SW_DEFAULT_MAX_CORO_NUM : max_num);
107+
}
108+
if (php_swoole_array_get_value(vht, "c_stack_size", v) || php_swoole_array_get_value(vht, "stack_size", v))
109+
{
110+
Coroutine::set_stack_size(zval_get_long(v));
111+
}
112+
if (php_swoole_array_get_value(vht, "socket_connect_timeout", v))
113+
{
114+
double t = zval_get_double(v);
115+
if (t != 0) { Socket::default_connect_timeout = t; }
116+
}
117+
if (php_swoole_array_get_value(vht, "socket_timeout", v))
118+
{
119+
double t = zval_get_double(v);
120+
if (t != 0) { Socket::default_read_timeout = Socket::default_write_timeout = t; }
121+
}
122+
if (php_swoole_array_get_value(vht, "socket_read_timeout", v))
123+
{
124+
double t = zval_get_double(v);
125+
if (t != 0) { Socket::default_read_timeout = t; }
126+
}
127+
if (php_swoole_array_get_value(vht, "socket_write_timeout", v))
128+
{
129+
double t = zval_get_double(v);
130+
if (t != 0) { Socket::default_write_timeout = t; }
131+
}
132+
if (php_swoole_array_get_value(vht, "log_level", v))
133+
{
134+
zend_long level = zval_get_long(v);
135+
SwooleG.log_level = (uint32_t) (level < 0 ? UINT32_MAX : level);
136+
}
137+
if (php_swoole_array_get_value(vht, "trace_flags", v))
138+
{
139+
SwooleG.trace_flags = (uint32_t) SW_MAX(0, zval_get_long(v));
140+
}
141+
if (php_swoole_array_get_value(vht, "dns_cache_expire", v))
142+
{
143+
System::set_dns_cache_expire((time_t) zval_get_long(v));
144+
}
145+
if (php_swoole_array_get_value(vht, "dns_cache_capacity", v))
146+
{
147+
System::set_dns_cache_capacity((size_t) zval_get_long(v));
148+
}
149+
if (php_swoole_array_get_value(vht, "display_errors", v))
150+
{
151+
SWOOLE_G(display_errors) = zval_is_true(v);
152+
}
153+
}
154+
155+
PHP_METHOD(swoole_coroutine_scheduler, stats)
156+
{
157+
array_init(return_value);
158+
if (SwooleG.main_reactor)
159+
{
160+
add_assoc_long_ex(return_value, ZEND_STRL("event_num"), SwooleG.main_reactor->event_num);
161+
add_assoc_long_ex(return_value, ZEND_STRL("signal_listener_num"), SwooleG.main_reactor->signal_listener_num);
162+
}
163+
add_assoc_long_ex(return_value, ZEND_STRL("aio_task_num"), SwooleAIO.task_num);
164+
add_assoc_long_ex(return_value, ZEND_STRL("c_stack_size"), Coroutine::get_stack_size());
165+
add_assoc_long_ex(return_value, ZEND_STRL("coroutine_num"), Coroutine::count());
166+
add_assoc_long_ex(return_value, ZEND_STRL("coroutine_peak_num"), Coroutine::get_peak_num());
167+
add_assoc_long_ex(return_value, ZEND_STRL("coroutine_last_cid"), Coroutine::get_last_cid());
168+
}
169+
170+
PHP_METHOD(swoole_coroutine_scheduler, getCid)
171+
{
172+
RETURN_LONG(PHPCoroutine::get_cid());
173+
}
174+
175+
PHP_METHOD(swoole_coroutine_scheduler, getPcid)
176+
{
177+
RETURN_LONG(PHPCoroutine::get_pcid());
178+
}
179+
180+
PHP_METHOD(swoole_coroutine_scheduler, getContext)
181+
{
182+
zend_long cid = 0;
183+
184+
ZEND_PARSE_PARAMETERS_START(0, 1)
185+
Z_PARAM_OPTIONAL
186+
Z_PARAM_LONG(cid)
187+
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
188+
189+
php_coro_task *task = (php_coro_task *) (EXPECTED(cid == 0) ? Coroutine::get_current_task() : Coroutine::get_task_by_cid(cid));
190+
if (UNEXPECTED(!task))
191+
{
192+
RETURN_NULL();
193+
}
194+
if (UNEXPECTED(!task->context))
195+
{
196+
object_init_ex(return_value, swoole_coroutine_context_ce);
197+
task->context = Z_OBJ_P(return_value);
198+
}
199+
GC_ADDREF(task->context);
200+
RETURN_OBJ(task->context);
201+
}
202+
203+
PHP_METHOD(swoole_coroutine_scheduler, exists)
204+
{
205+
zend_long cid;
206+
207+
ZEND_PARSE_PARAMETERS_START(1, 1)
208+
Z_PARAM_LONG(cid)
209+
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
210+
211+
RETURN_BOOL(Coroutine::get_by_cid(cid) != nullptr);
212+
}
213+
214+
PHP_METHOD(swoole_coroutine_scheduler, resume)
215+
{
216+
long cid;
217+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &cid) == FAILURE)
218+
{
219+
RETURN_FALSE;
220+
}
221+
222+
auto coroutine_iterator = user_yield_coros.find(cid);
223+
if (coroutine_iterator == user_yield_coros.end())
224+
{
225+
swoole_php_fatal_error(E_WARNING, "you can not resume the coroutine which is in IO operation or non-existent");
226+
RETURN_FALSE;
227+
}
228+
229+
Coroutine* co = coroutine_iterator->second;
230+
user_yield_coros.erase(cid);
231+
co->resume();
232+
RETURN_TRUE;
233+
}
234+
235+
PHP_METHOD(swoole_coroutine_scheduler, yield)
236+
{
237+
Coroutine* co = Coroutine::get_current_safe();
238+
user_yield_coros[co->get_cid()] = co;
239+
co->yield();
240+
RETURN_TRUE;
241+
}
242+
243+
PHP_METHOD(swoole_coroutine_scheduler, getBackTrace)
244+
{
245+
zend_long cid = 0;
246+
zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
247+
zend_long limit = 0;
248+
249+
ZEND_PARSE_PARAMETERS_START(0, 3)
250+
Z_PARAM_OPTIONAL
251+
Z_PARAM_LONG(cid)
252+
Z_PARAM_LONG(options)
253+
Z_PARAM_LONG(limit)
254+
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
255+
256+
if (!cid || cid == PHPCoroutine::get_cid())
257+
{
258+
zend_fetch_debug_backtrace(return_value, 0, options, limit);
259+
}
260+
else
261+
{
262+
php_coro_task *task = (php_coro_task *) PHPCoroutine::get_task_by_cid(cid);
263+
if (UNEXPECTED(!task))
264+
{
265+
RETURN_FALSE;
266+
}
267+
zend_execute_data *ex_backup = EG(current_execute_data);
268+
EG(current_execute_data) = task->execute_data;
269+
zend_fetch_debug_backtrace(return_value, 0, options, limit);
270+
EG(current_execute_data) = ex_backup;
271+
}
272+
}
273+
274+
PHP_METHOD(swoole_coroutine_scheduler, list)
275+
{
276+
zval zlist;
277+
array_init(&zlist);
278+
for (auto &co : Coroutine::coroutines) {
279+
add_next_index_long(&zlist, co.second->get_cid());
280+
}
281+
object_init_ex(return_value, swoole_coroutine_iterator_ce);
282+
sw_zend_call_method_with_1_params(
283+
return_value,
284+
swoole_coroutine_iterator_ce,
285+
&swoole_coroutine_iterator_ce->constructor,
286+
(const char *) "__construct",
287+
NULL,
288+
&zlist
289+
);
290+
zval_ptr_dtor(&zlist);
291+
}

swoole_coroutine_scheduler.h

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Swoole |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 2.0 of the Apache license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| http://www.apache.org/licenses/LICENSE-2.0.html |
9+
| If you did not receive a copy of the Apache2.0 license and are unable|
10+
| to obtain it through the world-wide-web, please send a note to |
11+
| license@swoole.com so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Author: Xinyu Zhu <xyzhu1120@gmail.com> |
14+
| shiguangqi <shiguangqi2008@gmail.com> |
15+
| Tianfeng Han <mikan.tenny@gmail.com> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
#include "php_swoole_cxx.h"
20+
21+
void swoole_coroutine_scheduler_init(int module_number);
22+
23+
PHP_METHOD(swoole_coroutine_scheduler, set);
24+
PHP_METHOD(swoole_coroutine_scheduler, exists);
25+
PHP_METHOD(swoole_coroutine_scheduler, yield);
26+
PHP_METHOD(swoole_coroutine_scheduler, resume);
27+
PHP_METHOD(swoole_coroutine_scheduler, stats);
28+
PHP_METHOD(swoole_coroutine_scheduler, getCid);
29+
PHP_METHOD(swoole_coroutine_scheduler, getPcid);
30+
PHP_METHOD(swoole_coroutine_scheduler, getContext);
31+
PHP_METHOD(swoole_coroutine_scheduler, getBackTrace);
32+
PHP_METHOD(swoole_coroutine_scheduler, list);

0 commit comments

Comments
 (0)