Skip to content

Commit 3205a37

Browse files
committed
% refactoring async_API.c and coroutine.c
1 parent 01931c8 commit 3205a37

File tree

3 files changed

+125
-111
lines changed

3 files changed

+125
-111
lines changed

async_API.c

Lines changed: 5 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ zend_coroutine_t *spawn(zend_async_scope_t *scope, zend_object * scope_provider)
8989
return NULL;
9090
}
9191

92-
async_coroutine_t *coroutine = (async_coroutine_t *) new_coroutine(scope);
92+
async_coroutine_t *coroutine = (async_coroutine_t *) async_new_coroutine(scope);
9393
if (UNEXPECTED(EG(exception))) {
9494
return NULL;
9595
}
@@ -179,110 +179,6 @@ zend_coroutine_t *spawn(zend_async_scope_t *scope, zend_object * scope_provider)
179179
return &coroutine->coroutine;
180180
}
181181

182-
void suspend(const bool from_main)
183-
{
184-
if (UNEXPECTED(from_main)) {
185-
// If the Scheduler was never used, it means no coroutines were created,
186-
// so execution can be finished without doing anything.
187-
if (circular_buffer_is_empty(&ASYNC_G(microtasks)) && zend_hash_num_elements(&ASYNC_G(coroutines)) == 0) {
188-
return;
189-
}
190-
191-
async_scheduler_main_coroutine_suspend();
192-
return;
193-
}
194-
195-
async_scheduler_coroutine_suspend(NULL);
196-
}
197-
198-
void resume(zend_coroutine_t *coroutine, zend_object * error, const bool transfer_error)
199-
{
200-
if (UNEXPECTED(coroutine->waker == NULL)) {
201-
async_throw_error("Cannot resume a coroutine that has not been suspended");
202-
return;
203-
}
204-
205-
if (error != NULL) {
206-
if (coroutine->waker->error != NULL) {
207-
zend_exception_set_previous(error, coroutine->waker->error);
208-
OBJ_RELEASE(coroutine->waker->error);
209-
}
210-
211-
coroutine->waker->error = error;
212-
213-
if (false == transfer_error) {
214-
GC_ADDREF(error);
215-
}
216-
}
217-
218-
if (UNEXPECTED(coroutine->waker->status == ZEND_ASYNC_WAKER_QUEUED)) {
219-
return;
220-
}
221-
222-
if (UNEXPECTED(circular_buffer_push(&ASYNC_G(coroutine_queue), &coroutine, true)) == FAILURE) {
223-
async_throw_error("Failed to enqueue coroutine");
224-
return;
225-
}
226-
227-
coroutine->waker->status = ZEND_ASYNC_WAKER_QUEUED;
228-
}
229-
230-
void cancel(zend_coroutine_t *zend_coroutine, zend_object *error, const bool transfer_error, const bool is_safely)
231-
{
232-
// If the coroutine hasn't even started, do nothing.
233-
if (false == ZEND_COROUTINE_IS_STARTED(zend_coroutine) || ZEND_COROUTINE_IS_FINISHED(zend_coroutine)) {
234-
if (transfer_error && error != NULL) {
235-
OBJ_RELEASE(error);
236-
}
237-
238-
return;
239-
}
240-
241-
if (zend_coroutine->waker == NULL) {
242-
zend_async_waker_new(zend_coroutine);
243-
}
244-
245-
if (UNEXPECTED(zend_coroutine->waker == NULL)) {
246-
async_throw_error("Waker is not initialized");
247-
248-
if (transfer_error) {
249-
OBJ_RELEASE(error);
250-
}
251-
252-
return;
253-
}
254-
255-
ZEND_COROUTINE_SET_CANCELLED(zend_coroutine);
256-
257-
// In safely mode, we don't forcibly terminate the coroutine,
258-
// but we do mark it as a Zombie.
259-
if (is_safely && error == NULL) {
260-
ZEND_COROUTINE_SET_ZOMBIE(zend_coroutine);
261-
ZEND_ASYNC_DECREASE_COROUTINE_COUNT
262-
return;
263-
}
264-
265-
const bool is_error_null = (error == NULL);
266-
267-
if (is_error_null) {
268-
error = async_new_exception(async_ce_cancellation_exception, "Coroutine cancelled");
269-
if (UNEXPECTED(EG(exception))) {
270-
return;
271-
}
272-
}
273-
274-
if (zend_coroutine->waker->error != NULL) {
275-
zend_exception_set_previous(error, zend_coroutine->waker->error);
276-
OBJ_RELEASE(zend_coroutine->waker->error);
277-
}
278-
279-
zend_coroutine->waker->error = error;
280-
281-
if (false == transfer_error && false == is_error_null) {
282-
GC_ADDREF(error);
283-
}
284-
}
285-
286182
static void graceful_shutdown(void)
287183
{
288184
start_graceful_shutdown();
@@ -960,14 +856,14 @@ void async_api_register(void)
960856
zend_async_scheduler_register(
961857
PHP_ASYNC_NAME_VERSION,
962858
false,
963-
new_coroutine,
859+
async_new_coroutine,
964860
async_new_scope,
965861
(zend_async_new_context_t)async_context_new,
966862
spawn,
967-
suspend,
863+
async_coroutine_suspend,
968864
async_scheduler_coroutine_enqueue,
969-
resume,
970-
cancel,
865+
async_coroutine_resume,
866+
async_coroutine_cancel,
971867
graceful_shutdown,
972868
get_coroutines,
973869
add_microtask,

coroutine.c

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,121 @@ static zend_string* coroutine_info(zend_async_event_t *event)
414414
}
415415
}
416416

417+
void async_coroutine_suspend(const bool from_main)
418+
{
419+
if (UNEXPECTED(from_main)) {
420+
// If the Scheduler was never used, it means no coroutines were created,
421+
// so execution can be finished without doing anything.
422+
if (circular_buffer_is_empty(&ASYNC_G(microtasks)) && zend_hash_num_elements(&ASYNC_G(coroutines)) == 0) {
423+
return;
424+
}
425+
426+
async_scheduler_main_coroutine_suspend();
427+
return;
428+
}
429+
430+
async_scheduler_coroutine_suspend(NULL);
431+
}
432+
433+
void async_coroutine_resume(zend_coroutine_t *coroutine, zend_object * error, const bool transfer_error)
434+
{
435+
if (UNEXPECTED(coroutine->waker == NULL)) {
436+
async_throw_error("Cannot resume a coroutine that has not been suspended");
437+
return;
438+
}
439+
440+
if (error != NULL) {
441+
if (coroutine->waker->error != NULL) {
442+
zend_exception_set_previous(error, coroutine->waker->error);
443+
OBJ_RELEASE(coroutine->waker->error);
444+
}
445+
446+
coroutine->waker->error = error;
447+
448+
if (false == transfer_error) {
449+
GC_ADDREF(error);
450+
}
451+
}
452+
453+
if (UNEXPECTED(coroutine->waker->status == ZEND_ASYNC_WAKER_QUEUED)) {
454+
return;
455+
}
456+
457+
if (UNEXPECTED(circular_buffer_push(&ASYNC_G(coroutine_queue), &coroutine, true)) == FAILURE) {
458+
async_throw_error("Failed to enqueue coroutine");
459+
return;
460+
}
461+
462+
coroutine->waker->status = ZEND_ASYNC_WAKER_QUEUED;
463+
}
464+
465+
void async_coroutine_cancel(zend_coroutine_t *zend_coroutine, zend_object *error, const bool transfer_error, const bool is_safely)
466+
{
467+
// If the coroutine finished, do nothing.
468+
if (ZEND_COROUTINE_IS_FINISHED(zend_coroutine)) {
469+
if (transfer_error && error != NULL) {
470+
OBJ_RELEASE(error);
471+
}
472+
473+
return;
474+
}
475+
476+
if (zend_coroutine->waker == NULL) {
477+
zend_async_waker_new(zend_coroutine);
478+
}
479+
480+
if (UNEXPECTED(zend_coroutine->waker == NULL)) {
481+
async_throw_error("Waker is not initialized");
482+
483+
if (transfer_error) {
484+
OBJ_RELEASE(error);
485+
}
486+
487+
return;
488+
}
489+
490+
ZEND_COROUTINE_SET_CANCELLED(zend_coroutine);
491+
492+
if (false == ZEND_COROUTINE_IS_STARTED(zend_coroutine)) {
493+
zend_coroutine->waker->status = ZEND_ASYNC_WAKER_IGNORED;
494+
zend_coroutine->exception = error;
495+
496+
if (false == transfer_error) {
497+
GC_ADDREF(error);
498+
}
499+
500+
return;
501+
}
502+
503+
// In safely mode, we don't forcibly terminate the coroutine,
504+
// but we do mark it as a Zombie.
505+
if (is_safely && error == NULL) {
506+
ZEND_COROUTINE_SET_ZOMBIE(zend_coroutine);
507+
ZEND_ASYNC_DECREASE_COROUTINE_COUNT
508+
return;
509+
}
510+
511+
const bool is_error_null = (error == NULL);
512+
513+
if (is_error_null) {
514+
error = async_new_exception(async_ce_cancellation_exception, "Coroutine cancelled");
515+
if (UNEXPECTED(EG(exception))) {
516+
return;
517+
}
518+
}
519+
520+
if (zend_coroutine->waker->error != NULL) {
521+
zend_exception_set_previous(error, zend_coroutine->waker->error);
522+
OBJ_RELEASE(zend_coroutine->waker->error);
523+
}
524+
525+
zend_coroutine->waker->error = error;
526+
527+
if (false == transfer_error && false == is_error_null) {
528+
GC_ADDREF(error);
529+
}
530+
}
531+
417532
static void coroutine_dispose(zend_async_event_t *event)
418533
{
419534
async_coroutine_t *coroutine = (async_coroutine_t *) event;
@@ -513,7 +628,7 @@ static zend_object *coroutine_object_create(zend_class_entry *class_entry)
513628
return &coroutine->std;
514629
}
515630

516-
zend_coroutine_t *new_coroutine(zend_async_scope_t *scope)
631+
zend_coroutine_t *async_new_coroutine(zend_async_scope_t *scope)
517632
{
518633
zend_object * object = coroutine_object_create(async_ce_coroutine);
519634

coroutine.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,12 @@ struct _async_coroutine_s {
4949
};
5050

5151
void async_register_coroutine_ce(void);
52-
zend_coroutine_t *new_coroutine(zend_async_scope_t *scope);
52+
zend_coroutine_t *async_new_coroutine(zend_async_scope_t *scope);
5353
void async_coroutine_cleanup(zend_fiber_context *context);
5454
void async_coroutine_finalize(zend_fiber_transfer *transfer, async_coroutine_t * coroutine);
55+
void async_coroutine_suspend(const bool from_main);
56+
void async_coroutine_resume(zend_coroutine_t *coroutine, zend_object * error, const bool transfer_error);
57+
void async_coroutine_cancel(zend_coroutine_t *zend_coroutine, zend_object *error, const bool transfer_error, const bool is_safely);
5558
bool async_coroutine_context_set(zend_coroutine_t * z_coroutine, zval *key, zval *value);
5659
bool async_coroutine_context_get(zend_coroutine_t * z_coroutine, zval *key, zval *result);
5760
bool async_coroutine_context_has(zend_coroutine_t * z_coroutine, zval *key);

0 commit comments

Comments
 (0)