From 8d0df960fad9677ce43edef4598885ff4415ade5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 24 Apr 2023 20:48:42 +0100 Subject: [PATCH] First look at preferring autoload over class copying this is currently unfinished, and it will attempt to fire the autoloader for every class when INHERIT_ALL is used, which is not intended. the aim is to avoid class copying wherever possible, since copying classes is a source of stability issues. this change also allows sidestepping #73 for named classes. --- src/object.c | 20 ++++++++++++++------ src/prepare.c | 13 +++++++++---- src/routine.c | 37 +++++++++++++++++++------------------ src/worker.c | 4 +++- 4 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/object.c b/src/object.c index 2d1799da..da939843 100644 --- a/src/object.c +++ b/src/object.c @@ -224,13 +224,21 @@ zend_bool pthreads_globals_object_connect(pthreads_zend_object_t* address, zend_ if (!ce) { /* we may not know the class, can't use ce directly from zend_object because it is from another context */ - ce = pthreads_prepare_single_class(&pthreads->owner, pthreads->std.ce); + zend_try{ + ce = pthreads_prepare_single_class(&pthreads->owner, pthreads->std.ce); + } zend_catch { + //beware of autoloading errors + ce = NULL; + valid = 0; + } zend_end_try(); + } + if (ce) { + PTHREADS_ZG(connecting_object) = pthreads; + object_init_ex(object, ce); + PTHREADS_ZG(connecting_object) = NULL; + connection = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + zend_hash_index_update_ptr(&PTHREADS_ZG(resolve), (zend_ulong)connection->ts_obj, connection); } - PTHREADS_ZG(connecting_object) = pthreads; - object_init_ex(object, ce); - PTHREADS_ZG(connecting_object) = NULL; - connection = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); - zend_hash_index_update_ptr(&PTHREADS_ZG(resolve), (zend_ulong)connection->ts_obj, connection); } } } diff --git a/src/prepare.c b/src/prepare.c index 060d9aff..e048fb76 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -611,10 +611,15 @@ static zend_class_entry* pthreads_create_entry(const pthreads_ident_t* source, z return NULL; } - if (candidate->type == ZEND_INTERNAL_CLASS - || candidate->ce_flags & ZEND_ACC_PRELOADED - ) { - return zend_lookup_class(candidate->name); + if ((candidate->ce_flags & ZEND_ACC_ANON_CLASS) == 0) { + //call autoloaders if available for named classes + prepared = zend_lookup_class(candidate->name); + if (prepared) { + return prepared; + } else if (candidate->type == ZEND_INTERNAL_CLASS || candidate->ce_flags & ZEND_ACC_PRELOADED) { + zend_error_noreturn(E_CORE_ERROR, "Internal and preloaded classes should always be able to be looked up"); + return NULL; + } } lookup = zend_string_tolower(candidate->name); diff --git a/src/routine.c b/src/routine.c index 3ba7d5d1..a54acdc8 100644 --- a/src/routine.c +++ b/src/routine.c @@ -29,29 +29,34 @@ static void pthreads_routine_free(pthreads_routine_arg_t* r) { } /* }}} */ /* {{{ */ -static inline zend_bool pthreads_routine_run_function(pthreads_zend_object_t* object, pthreads_zend_object_t* connection, zval* work) { +static inline zend_bool pthreads_routine_run_function(pthreads_zend_object_t* object, zval* zv) { zend_function* run; pthreads_call_t call = PTHREADS_CALL_EMPTY; zval zresult; zend_execute_data execute_data; + memset(&execute_data, 0, sizeof(execute_data)); + ZVAL_UNDEF(&zresult); + ZVAL_UNDEF(zv); - if (pthreads_connect(object, connection) != SUCCESS) { - return 0; - } + zend_try { + object_init_ex(zv, pthreads_prepare_single_class(&object->owner, object->std.ce)); - if (pthreads_monitor_check(&object->ts_obj->monitor, PTHREADS_MONITOR_ERROR)) { - return 0; - } + pthreads_zend_object_t* connection = PTHREADS_FETCH_FROM(Z_OBJ_P(zv)); - ZVAL_UNDEF(&zresult); + if (pthreads_connect(object, connection) != SUCCESS) { + return 0; + } - pthreads_monitor_add(&object->ts_obj->monitor, PTHREADS_MONITOR_RUNNING); + if (pthreads_monitor_check(&object->ts_obj->monitor, PTHREADS_MONITOR_ERROR)) { + return 0; + } - if (work) - pthreads_store_write(Z_OBJ_P(work), &PTHREADS_G(strings).worker, &PTHREADS_ZG(this), PTHREADS_STORE_NO_COERCE_ARRAY); + pthreads_monitor_add(&object->ts_obj->monitor, PTHREADS_MONITOR_RUNNING); + + if (Z_OBJ_P(zv) != Z_OBJ_P(&PTHREADS_ZG(this))) + pthreads_store_write(Z_OBJ_P(zv), &PTHREADS_G(strings).worker, &PTHREADS_ZG(this), PTHREADS_STORE_NO_COERCE_ARRAY); - zend_try{ if ((run = zend_hash_find_ptr(&connection->std.ce->function_table, PTHREADS_G(strings).run))) { if (run->type == ZEND_USER_FUNCTION) { EG(current_execute_data) = &execute_data; @@ -101,9 +106,7 @@ static void* pthreads_routine(pthreads_routine_arg_t* routine) { pthreads_queue done_tasks_cache; zend_first_try{ - ZVAL_UNDEF(&PTHREADS_ZG(this)); - object_init_ex(&PTHREADS_ZG(this), pthreads_prepare_single_class(&thread->owner, thread->std.ce)); - pthreads_routine_run_function(thread, PTHREADS_FETCH_FROM(Z_OBJ_P(&PTHREADS_ZG(this))), NULL); + pthreads_routine_run_function(thread, &PTHREADS_ZG(this)); if (PTHREADS_IS_WORKER(thread)) { zval task; @@ -112,9 +115,7 @@ static void* pthreads_routine(pthreads_routine_arg_t* routine) { while (pthreads_worker_next_task(thread->worker_data, &done_tasks_cache, &task) != PTHREADS_MONITOR_JOINED) { zval that; - pthreads_zend_object_t* work = PTHREADS_FETCH_FROM(Z_OBJ(task)); - object_init_ex(&that, pthreads_prepare_single_class(&work->owner, work->std.ce)); - pthreads_routine_run_function(work, PTHREADS_FETCH_FROM(Z_OBJ(that)), &that); + pthreads_routine_run_function(PTHREADS_FETCH_FROM(Z_OBJ(task)), &that); pthreads_worker_add_garbage(thread->worker_data, &done_tasks_cache, &that); zval_ptr_dtor(&that); } diff --git a/src/worker.c b/src/worker.c index 8fac922d..4cc37e05 100644 --- a/src/worker.c +++ b/src/worker.c @@ -90,7 +90,9 @@ void pthreads_worker_add_garbage(pthreads_worker_data_t *worker_data, pthreads_q pthreads_queue_push(&worker_data->gc, worker_data->running); worker_data->running = NULL; pthreads_monitor_unlock(worker_data->monitor); - pthreads_queue_push_new(done_tasks_cache, work_zval); + if (!Z_ISUNDEF_P(work_zval)) { //we may have failed to init the local connection object due to an autoloading error + pthreads_queue_push_new(done_tasks_cache, work_zval); + } } else { ZEND_ASSERT(0); }