18
18
*/
19
19
20
20
#include " php_swoole_cxx.h"
21
+ #include " swoole_coroutine_scheduler.h"
22
+ #include " swoole_coroutine_system.h"
21
23
22
- using namespace swoole ;
24
+ using swoole::coroutine::System;
25
+ using swoole::coroutine::Socket;
26
+ using swoole::Coroutine;
27
+ using swoole::PHPCoroutine;
23
28
24
29
#define PHP_CORO_TASK_SLOT ((int )((ZEND_MM_ALIGNED_SIZE(sizeof (php_coro_task)) + ZEND_MM_ALIGNED_SIZE(sizeof (zval)) - 1 ) / ZEND_MM_ALIGNED_SIZE(sizeof (zval))))
25
30
31
+ enum sw_exit_flags
32
+ {
33
+ SW_EXIT_IN_COROUTINE = 1 << 1 ,
34
+ SW_EXIT_IN_SERVER = 1 << 2
35
+ };
36
+
37
+ ZEND_BEGIN_ARG_INFO_EX (arginfo_swoole_coroutine_void, 0 , 0 , 0 )
38
+ ZEND_END_ARG_INFO()
39
+
40
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_set, 0 , 0 , 1 )
41
+ ZEND_ARG_INFO(0 , options)
42
+ ZEND_END_ARG_INFO()
43
+
44
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_create, 0 , 0 , 1 )
45
+ ZEND_ARG_CALLABLE_INFO(0 , func, 0 )
46
+ ZEND_ARG_VARIADIC_INFO(0 , params)
47
+ ZEND_END_ARG_INFO()
48
+
49
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_resume, 0 , 0 , 1 )
50
+ ZEND_ARG_INFO(0 , cid)
51
+ ZEND_END_ARG_INFO()
52
+
53
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_exists, 0 , 0 , 1 )
54
+ ZEND_ARG_INFO(0 , cid)
55
+ ZEND_END_ARG_INFO()
56
+
57
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_getContext, 0 , 0 , 0 )
58
+ ZEND_ARG_INFO(0 , cid)
59
+ ZEND_END_ARG_INFO()
60
+
61
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_exec, 0 , 0 , 1 )
62
+ ZEND_ARG_INFO(0 , command)
63
+ ZEND_ARG_INFO(0 , get_error_stream)
64
+ ZEND_END_ARG_INFO()
65
+
66
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_sleep, 0 , 0 , 1 )
67
+ ZEND_ARG_INFO(0 , seconds)
68
+ ZEND_END_ARG_INFO()
69
+
70
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_fread, 0 , 0 , 1 )
71
+ ZEND_ARG_INFO(0 , handle)
72
+ ZEND_ARG_INFO(0 , length)
73
+ ZEND_END_ARG_INFO()
74
+
75
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_fgets, 0 , 0 , 1 )
76
+ ZEND_ARG_INFO(0 , handle)
77
+ ZEND_END_ARG_INFO()
78
+
79
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_fwrite, 0 , 0 , 2 )
80
+ ZEND_ARG_INFO(0 , handle)
81
+ ZEND_ARG_INFO(0 , string)
82
+ ZEND_ARG_INFO(0 , length)
83
+ ZEND_END_ARG_INFO()
84
+
85
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_gethostbyname, 0 , 0 , 1 )
86
+ ZEND_ARG_INFO(0 , domain_name)
87
+ ZEND_ARG_INFO(0 , family)
88
+ ZEND_ARG_INFO(0 , timeout)
89
+ ZEND_END_ARG_INFO()
90
+
91
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_defer, 0 , 0 , 1 )
92
+ ZEND_ARG_INFO(0 , callback)
93
+ ZEND_END_ARG_INFO()
94
+
95
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_getaddrinfo, 0 , 0 , 1 )
96
+ ZEND_ARG_INFO(0 , hostname)
97
+ ZEND_ARG_INFO(0 , family)
98
+ ZEND_ARG_INFO(0 , socktype)
99
+ ZEND_ARG_INFO(0 , protocol)
100
+ ZEND_ARG_INFO(0 , service)
101
+ ZEND_ARG_INFO(0 , timeout)
102
+ ZEND_END_ARG_INFO()
103
+
104
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_readFile, 0 , 0 , 1 )
105
+ ZEND_ARG_INFO(0 , filename)
106
+ ZEND_END_ARG_INFO()
107
+
108
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_writeFile, 0 , 0 , 2 )
109
+ ZEND_ARG_INFO(0 , filename)
110
+ ZEND_ARG_INFO(0 , data)
111
+ ZEND_ARG_INFO(0 , flags)
112
+ ZEND_END_ARG_INFO()
113
+
114
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_statvfs, 0 , 0 , 1 )
115
+ ZEND_ARG_INFO(0 , path)
116
+ ZEND_END_ARG_INFO()
117
+
118
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_getBackTrace, 0 , 0 , 0 )
119
+ ZEND_ARG_INFO(0 , cid)
120
+ ZEND_ARG_INFO(0 , options)
121
+ ZEND_ARG_INFO(0 , limit)
122
+ ZEND_END_ARG_INFO()
123
+
26
124
bool PHPCoroutine::active = false;
27
125
uint64_t PHPCoroutine::max_num = SW_DEFAULT_MAX_CORO_NUM;
28
126
php_coro_task PHPCoroutine::main_task = {0 };
@@ -31,11 +129,122 @@ bool PHPCoroutine::schedule_thread_running = false;
31
129
32
130
static zend_bool* zend_vm_interrupt = nullptr ;
33
131
static pthread_t pidt;
132
+ static user_opcode_handler_t ori_exit_handler = NULL ;
34
133
35
134
static void (*orig_interrupt_function)(zend_execute_data *execute_data);
36
-
37
135
static void (*orig_error_function)(int type, const char *error_filename, const uint32_t error_lineno, const char *format, va_list args);
38
136
137
+ static zend_class_entry *swoole_coroutine_util_ce;
138
+ static zend_class_entry *swoole_exit_exception_ce;
139
+ static zend_object_handlers swoole_exit_exception_handlers;
140
+
141
+ static const zend_function_entry swoole_coroutine_util_methods[] =
142
+ {
143
+ /* *
144
+ * Coroutine Scheduler
145
+ */
146
+ ZEND_FENTRY (create, ZEND_FN (swoole_coroutine_create), arginfo_swoole_coroutine_create, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
147
+ ZEND_FENTRY (defer, ZEND_FN (swoole_coroutine_defer), arginfo_swoole_coroutine_defer, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
148
+ PHP_ME (swoole_coroutine_scheduler, set, arginfo_swoole_coroutine_set, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
149
+ PHP_ME (swoole_coroutine_scheduler, exists, arginfo_swoole_coroutine_exists, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
150
+ PHP_ME (swoole_coroutine_scheduler, yield, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
151
+ PHP_MALIAS (swoole_coroutine_scheduler, suspend, yield, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
152
+ PHP_ME (swoole_coroutine_scheduler, resume, arginfo_swoole_coroutine_resume, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
153
+ PHP_ME (swoole_coroutine_scheduler, stats, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
154
+ PHP_ME (swoole_coroutine_scheduler, getCid, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
155
+ PHP_MALIAS (swoole_coroutine_scheduler, getuid , getCid, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
156
+ PHP_ME (swoole_coroutine_scheduler, getPcid, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
157
+ PHP_ME (swoole_coroutine_scheduler, getContext, arginfo_swoole_coroutine_getContext, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
158
+ PHP_ME (swoole_coroutine_scheduler, getBackTrace, arginfo_swoole_coroutine_getBackTrace, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
159
+ PHP_ME (swoole_coroutine_scheduler, list, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
160
+ PHP_MALIAS (swoole_coroutine_scheduler, listCoroutines, list, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
161
+ PHP_ME (swoole_coroutine_scheduler, enableScheduler, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
162
+ PHP_ME (swoole_coroutine_scheduler, disableScheduler, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
163
+ /* *
164
+ * Coroutine System API
165
+ */
166
+ ZEND_FENTRY (exec, ZEND_FN (swoole_coroutine_exec), arginfo_swoole_coroutine_exec, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
167
+ ZEND_FENTRY (gethostbyname, ZEND_FN (swoole_coroutine_gethostbyname), arginfo_swoole_coroutine_gethostbyname, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
168
+ PHP_ME (swoole_coroutine_system, sleep , arginfo_swoole_coroutine_sleep, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
169
+ PHP_ME (swoole_coroutine_system, fread , arginfo_swoole_coroutine_fread, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
170
+ PHP_ME (swoole_coroutine_system, fgets , arginfo_swoole_coroutine_fgets, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
171
+ PHP_ME (swoole_coroutine_system, fwrite , arginfo_swoole_coroutine_fwrite, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
172
+ PHP_ME (swoole_coroutine_system, readFile, arginfo_swoole_coroutine_readFile, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
173
+ PHP_ME (swoole_coroutine_system, writeFile, arginfo_swoole_coroutine_writeFile, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
174
+ PHP_ME (swoole_coroutine_system, getaddrinfo, arginfo_swoole_coroutine_getaddrinfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
175
+ PHP_ME (swoole_coroutine_system, statvfs, arginfo_swoole_coroutine_statvfs, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
176
+
177
+ PHP_FE_END
178
+ };
179
+
180
+ /* *
181
+ * Exit Exception
182
+ */
183
+ static PHP_METHOD (swoole_exit_exception, getFlags);
184
+ static PHP_METHOD (swoole_exit_exception, getStatus);
185
+
186
+ static const zend_function_entry swoole_exit_exception_methods[] =
187
+ {
188
+ PHP_ME (swoole_exit_exception, getFlags, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC)
189
+ PHP_ME (swoole_exit_exception, getStatus, arginfo_swoole_coroutine_void, ZEND_ACC_PUBLIC)
190
+ PHP_FE_END
191
+ };
192
+
193
+ static int coro_exit_handler (zend_execute_data *execute_data)
194
+ {
195
+ zval ex;
196
+ zend_object *obj;
197
+ zend_long flags = 0 ;
198
+ if (Coroutine::get_current ())
199
+ {
200
+ flags |= SW_EXIT_IN_COROUTINE;
201
+ }
202
+ if (SwooleG.serv && SwooleG.serv ->gs ->start )
203
+ {
204
+ flags |= SW_EXIT_IN_SERVER;
205
+ }
206
+ if (flags)
207
+ {
208
+ const zend_op *opline = EX (opline);
209
+ zval _exit_status;
210
+ zval *exit_status = NULL ;
211
+
212
+ if (opline->op1_type != IS_UNUSED)
213
+ {
214
+ if (opline->op1_type == IS_CONST)
215
+ {
216
+ // see: https://github.com/php/php-src/commit/e70618aff6f447a298605d07648f2ce9e5a284f5
217
+ #ifdef EX_CONSTANT
218
+ exit_status = EX_CONSTANT (opline->op1 );
219
+ #else
220
+ exit_status = RT_CONSTANT (opline, opline->op1 );
221
+ #endif
222
+ }
223
+ else
224
+ {
225
+ exit_status = EX_VAR (opline->op1 .var );
226
+ }
227
+ if (Z_ISREF_P (exit_status))
228
+ {
229
+ exit_status = Z_REFVAL_P (exit_status);
230
+ }
231
+ ZVAL_DUP (&_exit_status, exit_status);
232
+ exit_status = &_exit_status;
233
+ }
234
+ else
235
+ {
236
+ exit_status = &_exit_status;
237
+ ZVAL_NULL (exit_status);
238
+ }
239
+ obj = zend_throw_error_exception (swoole_exit_exception_ce, " swoole exit" , 0 , E_ERROR);
240
+ ZVAL_OBJ (&ex, obj);
241
+ zend_update_property_long (swoole_exit_exception_ce, &ex, ZEND_STRL (" flags" ), flags);
242
+ Z_TRY_ADDREF_P (exit_status);
243
+ zend_update_property (swoole_exit_exception_ce, &ex, ZEND_STRL (" status" ), exit_status);
244
+ }
245
+
246
+ return ZEND_USER_OPCODE_DISPATCH;
247
+ }
39
248
40
249
static void swoole_interrupt_resume (void *data)
41
250
{
@@ -550,3 +759,49 @@ int PHPCoroutine::resume_m(php_coro_context *sw_current_context, zval *retval, z
550
759
task->co ->resume_naked ();
551
760
return SW_CORO_ERR_END;
552
761
}
762
+
763
+ void swoole_coroutine_init (int module_number)
764
+ {
765
+ PHPCoroutine::init ();
766
+
767
+ SW_INIT_CLASS_ENTRY_BASE (swoole_coroutine_util, " Swoole\\ Coroutine" , NULL , " Co" , swoole_coroutine_util_methods, NULL );
768
+ SW_SET_CLASS_CREATE (swoole_coroutine_util, sw_zend_create_object_deny);
769
+
770
+ swoole_coroutine_scheduler_init (module_number);
771
+
772
+ SW_REGISTER_LONG_CONSTANT (" SWOOLE_DEFAULT_MAX_CORO_NUM" , SW_DEFAULT_MAX_CORO_NUM);
773
+ SW_REGISTER_LONG_CONSTANT (" SWOOLE_CORO_MAX_NUM_LIMIT" , SW_CORO_MAX_NUM_LIMIT);
774
+ SW_REGISTER_LONG_CONSTANT (" SWOOLE_CORO_INIT" , SW_CORO_INIT);
775
+ SW_REGISTER_LONG_CONSTANT (" SWOOLE_CORO_WAITING" , SW_CORO_WAITING);
776
+ SW_REGISTER_LONG_CONSTANT (" SWOOLE_CORO_RUNNING" , SW_CORO_RUNNING);
777
+ SW_REGISTER_LONG_CONSTANT (" SWOOLE_CORO_END" , SW_CORO_END);
778
+
779
+ // prohibit exit in coroutine
780
+ SW_INIT_CLASS_ENTRY_EX (swoole_exit_exception, " Swoole\\ ExitException" , NULL , NULL , swoole_exit_exception_methods, swoole_exception);
781
+ zend_declare_property_long (swoole_exit_exception_ce, ZEND_STRL (" flags" ), 0 , ZEND_ACC_PRIVATE);
782
+ zend_declare_property_long (swoole_exit_exception_ce, ZEND_STRL (" status" ), 0 , ZEND_ACC_PRIVATE);
783
+
784
+ SW_REGISTER_LONG_CONSTANT (" SWOOLE_EXIT_IN_COROUTINE" , SW_EXIT_IN_COROUTINE);
785
+ SW_REGISTER_LONG_CONSTANT (" SWOOLE_EXIT_IN_SERVER" , SW_EXIT_IN_SERVER);
786
+
787
+ if (SWOOLE_G (cli))
788
+ {
789
+ ori_exit_handler = zend_get_user_opcode_handler (ZEND_EXIT);
790
+ zend_set_user_opcode_handler (ZEND_EXIT, coro_exit_handler);
791
+ }
792
+ }
793
+
794
+ void swoole_coroutine_rshutdown ()
795
+ {
796
+ PHPCoroutine::shutdown ();
797
+ }
798
+
799
+ static PHP_METHOD (swoole_exit_exception, getFlags)
800
+ {
801
+ SW_RETURN_PROPERTY (" flags" );
802
+ }
803
+
804
+ static PHP_METHOD (swoole_exit_exception, getStatus)
805
+ {
806
+ SW_RETURN_PROPERTY (" status" );
807
+ }
0 commit comments