-
Notifications
You must be signed in to change notification settings - Fork 8
/
php_coroutine.c
198 lines (169 loc) · 6.2 KB
/
php_coroutine.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/**
* 协程工具入口文件
*/
#include "base.h"
#include "coroutine.h"
#include "wm_signal.h"
//创建协程接口参数声明
ZEND_BEGIN_ARG_INFO_EX(arginfo_workerman_coroutine_create, 0, 0, 1) //
ZEND_ARG_CALLABLE_INFO(0, func, 0)
ZEND_END_ARG_INFO()
//不需要参数的方法用
ZEND_BEGIN_ARG_INFO_EX(arginfo_workerman_coroutine_void, 0, 0, 0) //
ZEND_END_ARG_INFO()
//传入协程resume参数声明
ZEND_BEGIN_ARG_INFO_EX(arginfo_workerman_coroutine_resume, 0, 0, 1) //
ZEND_ARG_INFO(0, cid)
ZEND_END_ARG_INFO()
//判断协程是否存在
ZEND_BEGIN_ARG_INFO_EX(arginfo_workerman_coroutine_isExist, 0, 0, 1) //
ZEND_ARG_INFO(0, cid)
ZEND_END_ARG_INFO()
//defer
ZEND_BEGIN_ARG_INFO_EX(arginfo_workerman_coroutine_defer, 0, 0, 1) //
ZEND_ARG_CALLABLE_INFO(0, func, 0)
ZEND_END_ARG_INFO()
//sleep
ZEND_BEGIN_ARG_INFO_EX(arginfo_workerman_coroutine_sleep, 0, 0, 1) //
ZEND_ARG_INFO(0, seconds)
ZEND_END_ARG_INFO()
//协程创建实现
PHP_FUNCTION(workerman_coroutine_create) {
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fcc = empty_fcall_info_cache;
//第一个参数表示必传的参数个数,第二个参数表示最多传入的参数个数,-1代表可变参数
ZEND_PARSE_PARAMETERS_START(1, -1)
Z_PARAM_FUNC(fci, fcc)
//第一个参数是一个匿名方法
// Z_PARAM_VARIADIC这个宏是用来解析可变参数的,'*'对于Z_PARAM_VARIADIC实际上并没有用到。
// 接下来获取其他参数。* 表示可变参数可传或者不传递。与之对应的是'+',表示可变参数至少传递一个。
// 这个宏设置fci.params指针的起始位置,以及fci.param_count的值
Z_PARAM_VARIADIC('*', fci.params, fci.param_count) //
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); //如果不满足传入条件,返回false
long cid = wmCoroutine_create(&fcc, fci.param_count, fci.params);
RETURN_LONG(cid);
}
//协程yield
PHP_METHOD(workerman_coroutine, yield) {
wmCoroutine_yield();
RETURN_TRUE
}
//协程resume
PHP_METHOD(workerman_coroutine, resume) {
zend_long cid = 0;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_LONG(cid)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
wmCoroutine *co = wmCoroutine_get_by_cid(cid);
if (co == NULL) {
php_error_docref(NULL, E_WARNING, "resume error");
RETURN_FALSE
}
if (!wmCoroutine_resume(co)) {
RETURN_FALSE
} else {
RETURN_TRUE
}
}
//获取协程cid
PHP_METHOD(workerman_coroutine, getCid) {
wmCoroutine *co = wmCoroutine_get_current();
if (co == NULL) {
RETURN_LONG(-1);
}
RETURN_LONG(co->cid);
}
//获取协程数量
PHP_METHOD(workerman_coroutine, getTotalNum) {
RETURN_LONG(wmCoroutine_getTotalNum());
}
//判断协程是否存在
PHP_METHOD(workerman_coroutine, isExist) {
zend_long cid = 0;
bool is_exist;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_LONG(cid)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
wmCoroutine *co = wmCoroutine_get_by_cid(cid);
is_exist = (co != NULL);
RETURN_BOOL(is_exist);
}
PHP_METHOD(workerman_coroutine, defer) {
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fcc = empty_fcall_info_cache;
ZEND_PARSE_PARAMETERS_START(1, -1)
Z_PARAM_FUNC(fci, fcc)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
php_fci_fcc *defer_fci_fcc = (php_fci_fcc*) emalloc(sizeof(php_fci_fcc));
defer_fci_fcc->fci = fci;
defer_fci_fcc->fcc = fcc;
wm_zend_fci_cache_persist(&defer_fci_fcc->fcc);
wmCoroutine_defer(defer_fci_fcc);
}
/**
* sleep方法
*/
PHP_METHOD(workerman_coroutine, sleep) {
double seconds;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(seconds)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
if (UNEXPECTED(seconds < 0.001)) {
php_error_docref(NULL, E_WARNING, "Timer must be greater than or equal to 0.001");
RETURN_FALSE
}
wmCoroutine_sleep(seconds);
RETURN_TRUE
}
//获取协程cid
PHP_METHOD(workerman_coroutine, wait) {
int ret = wm_event_wait();
if (ret < 0) {
RETURN_FALSE
}
RETURN_TRUE
}
/**
* 开始监听信号
* 私有静态方法&扩展内部使用
*/
PHP_METHOD(workerman_coroutine, signal_wait) {
wmSignal_wait();
RETURN_TRUE
}
/**
* 我们需要对这个方法进行收集,放在变量 workerman_coroutine_methods里面
*/
const zend_function_entry workerman_coroutine_methods[] = { //
//PHP_ME(workerman_coroutine, create, arginfo_workerman_coroutine_create, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) //
ZEND_FENTRY(create, ZEND_FN(workerman_coroutine_create),
arginfo_workerman_coroutine_create,
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) // ZEND_FENTRY这行是新增的
PHP_ME(workerman_coroutine, yield, arginfo_workerman_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) //
PHP_ME(workerman_coroutine, resume, arginfo_workerman_coroutine_resume, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) //
PHP_ME(workerman_coroutine, wait, arginfo_workerman_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) //
PHP_ME(workerman_coroutine, getCid, arginfo_workerman_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) //
PHP_ME(workerman_coroutine, getTotalNum, arginfo_workerman_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) //
PHP_ME(workerman_coroutine, isExist, arginfo_workerman_coroutine_isExist, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) //
PHP_ME(workerman_coroutine, defer, arginfo_workerman_coroutine_defer, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) //
PHP_ME(workerman_coroutine, sleep, arginfo_workerman_coroutine_sleep, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) //
PHP_ME(workerman_coroutine, signal_wait, arginfo_workerman_coroutine_void, ZEND_ACC_PRIVATE | ZEND_ACC_STATIC) //
PHP_FE_END //
};
/**
* 定义 zend class entry
*/
zend_class_entry workerman_coroutine_ce;
zend_class_entry *workerman_coroutine_ce_ptr;
/**
* 注册我们的Warriorman\Coroutine这个类
* 考虑到以后我们会有许多的类,我们不在MINIT里面直接写注册的代码,而是让study_coroutine_util.cc提供一个函数,我们在这个函数里面实现注册功能:
*/
void workerman_coroutine_init() {
//定义好一个类
INIT_NS_CLASS_ENTRY(workerman_coroutine_ce, "Warriorman", "Coroutine", workerman_coroutine_methods);
//在zedn中注册类
workerman_coroutine_ce_ptr = zend_register_internal_class(&workerman_coroutine_ce TSRMLS_CC); // 在 Zend Engine 中注册
//短名
zend_register_class_alias("Corker", workerman_coroutine_ce_ptr);
}