Skip to content

Commit

Permalink
Support coroutine switch in autoload
Browse files Browse the repository at this point in the history
  • Loading branch information
twose committed Nov 7, 2023
1 parent 56d6ffe commit beffeb4
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 0 deletions.
1 change: 1 addition & 0 deletions ext/include/swow_coroutine.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ CAT_GLOBALS_STRUCT_BEGIN(swow_coroutine) {
zval z_transfer_data;
zend_object *exception;
cat_bool_t bailout;
HashTable *in_autoload;
} CAT_GLOBALS_STRUCT_END(swow_coroutine);

typedef zval *(*swow_coroutine_resume_t)(swow_coroutine_t *s_coroutine, zval *z_data);
Expand Down
60 changes: 60 additions & 0 deletions ext/src/swow_coroutine.c
Original file line number Diff line number Diff line change
Expand Up @@ -2567,6 +2567,56 @@ static cat_msec_t swow_coroutine_msec_time(void)
(((cat_msec_t) tp.tv_usec) / 1000));
}

/* hook autoload */

static zend_class_entry *(*original_zend_autoload)(zend_string *name, zend_string *lc_name);

typedef struct swow_coroutine_autoload_context_s {
cat_queue_node_t node;
cat_coroutine_t *coroutine;
zend_class_entry *ce;
} swow_coroutine_autoload_context_t;

static zend_class_entry *swow_coroutine_autoload(zend_string *name, zend_string *lc_name)
{
ZEND_ASSERT(EG(in_autoload) != NULL);
zend_hash_del(EG(in_autoload), lc_name);

if (UNEXPECTED(SWOW_COROUTINE_G(in_autoload) == NULL)) {
ALLOC_HASHTABLE(SWOW_COROUTINE_G(in_autoload));
zend_hash_init(SWOW_COROUTINE_G(in_autoload), 8, NULL, NULL, 0);
}
zval *z_queue = zend_hash_find(SWOW_COROUTINE_G(in_autoload), lc_name);
if (z_queue != NULL) {
swow_coroutine_autoload_context_t context;
context.coroutine = CAT_COROUTINE_G(current);
context.ce = NULL;
cat_queue_push_back((cat_queue_t *) Z_PTR_P(z_queue), &context.node);
cat_coroutine_yield(NULL, NULL);
cat_queue_remove(&context.node);
return context.ce;
}
cat_queue_t queue;
cat_queue_init(&queue);
zval _z_queue;
z_queue = &_z_queue;
ZVAL_PTR(z_queue, &queue);

(void) zend_hash_add(SWOW_COROUTINE_G(in_autoload), zend_string_copy(lc_name), z_queue);
zend_class_entry * ce = original_zend_autoload(name, lc_name);
(void) zend_hash_del(SWOW_COROUTINE_G(in_autoload), lc_name);

swow_coroutine_autoload_context_t *pending_context = NULL;
while ((pending_context = cat_queue_front_data(&queue, swow_coroutine_autoload_context_t, node)) != NULL) {
pending_context->ce = ce;
cat_coroutine_schedule(pending_context->coroutine, COROUTINE, "Autoload");
}

zend_string_release(lc_name);
zend_hash_add_empty_element(EG(in_autoload), lc_name);
return ce;
}

zend_result swow_coroutine_module_init(INIT_FUNC_ARGS)
{
if (!cat_coroutine_module_init()) {
Expand Down Expand Up @@ -2628,6 +2678,10 @@ zend_result swow_coroutine_module_init(INIT_FUNC_ARGS)
zend_set_user_opcode_handler(ZEND_CATCH, swow_coroutine_catch_handler);
# endif

/* hook autoload */
original_zend_autoload = zend_autoload;
zend_autoload = swow_coroutine_autoload;

#ifdef SWOW_COROUTINE_MOCK_FIBER_CONTEXT
memset(&swow_coroutine_dummy_execute_data_for_internal, 0, sizeof(swow_coroutine_dummy_execute_data_for_internal));
memset(&swow_coroutine_dummy_function_for_internal, 0, sizeof(swow_coroutine_dummy_function_for_internal));
Expand Down Expand Up @@ -2691,6 +2745,12 @@ zend_result swow_coroutine_runtime_shutdown(SHUTDOWN_FUNC_ARGS)
{
SWOW_COROUTINE_G(runtime_state) = SWOW_COROUTINE_RUNTIME_STATE_IN_SHUTDOWN;

if (SWOW_COROUTINE_G(in_autoload)) {
zend_hash_destroy(SWOW_COROUTINE_G(in_autoload));
FREE_HASHTABLE(SWOW_COROUTINE_G(in_autoload));
SWOW_COROUTINE_G(in_autoload) = NULL;
}

swow_utils_handlers_release(&SWOW_COROUTINE_G(deadlock_handlers));

/* close main s_coroutine */
Expand Down
8 changes: 8 additions & 0 deletions ext/tests/swow_coroutine/autoload/Foo.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace SwowTestYieldInAutoload;

class Foo
{

}
37 changes: 37 additions & 0 deletions ext/tests/swow_coroutine/autoload/yield_in_autoload.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--TEST--
swow_coroutine:
--SKIPIF--
<?php
require __DIR__ . '/../../include/skipif.php';
?>
--FILE--
<?php
require __DIR__ . '/../../include/bootstrap.php';

use Swow\Coroutine;
use Swow\Sync\WaitReference;
use SwowTestYieldInAutoload\Foo;

$wr = new WaitReference();

spl_autoload_register(function (string $class): void {
usleep(1000); // coroutine context switch
require_once __DIR__ . '/foo.inc';
});

for ($i = 0; $i < 3; ++$i) {
Coroutine::run(static function () use ($wr): void {
var_dump(new Foo());
});
}

$wr::wait($wr);

?>
--EXPECTF--
object(%s\Foo)#%d (0) {
}
object(%s\Foo)#%d (0) {
}
object(%s\Foo)#%d (0) {
}

0 comments on commit beffeb4

Please sign in to comment.