From 43ffd00a70dd6c737af8b3a1e827f20ca5e033b9 Mon Sep 17 00:00:00 2001 From: Bastian Schneider Date: Fri, 12 Jan 2018 16:59:48 +0100 Subject: [PATCH] Copy closures defined by included classes --- src/prepare.c | 55 +++++++++++----------- tests/assets/ExternalClosureDefinition.php | 10 ++++ tests/closure-delayed-include.phpt | 49 +++++++++++++++++++ 3 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 tests/assets/ExternalClosureDefinition.php create mode 100644 tests/closure-delayed-include.phpt diff --git a/src/prepare.c b/src/prepare.c index 57ee7611..5dd1d008 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -405,6 +405,33 @@ static inline int pthreads_prepared_entry_function_prepare(zval *bucket, int arg return ZEND_HASH_APPLY_KEEP; } /* }}} */ +/* {{{ */ +static inline void pthreads_prepare_closures(pthreads_object_t *thread) { + Bucket *bucket; + + ZEND_HASH_FOREACH_BUCKET(PTHREADS_CG(thread->creator.ls, function_table), bucket) { + zend_function *function = Z_PTR(bucket->val), + *prepared; + zend_string *named; + + + if (function->common.fn_flags & ZEND_ACC_CLOSURE) { + if (zend_hash_exists(CG(function_table), bucket->key)) { + continue; + } + + named = zend_string_new(bucket->key); + prepared = pthreads_copy_function(function); + + if (!zend_hash_add_ptr(CG(function_table), named, prepared)) { + destroy_op_array((zend_op_array*) prepared); + } + + zend_string_release(named); + } + } ZEND_HASH_FOREACH_END(); +} /* }}} */ + /* {{{ */ zend_class_entry* pthreads_prepared_entry(pthreads_object_t* thread, zend_class_entry *candidate) { return pthreads_prepared_entry_internal(thread, candidate, 1); @@ -438,6 +465,7 @@ zend_class_entry* pthreads_prepared_entry_internal(pthreads_object_t* thread, ze zend_string_release(lookup); return NULL; } + pthreads_prepare_closures(thread); zend_hash_apply_with_arguments( &prepared->function_table, @@ -583,33 +611,6 @@ static inline void pthreads_prepare_functions(pthreads_object_t* thread) { } ZEND_HASH_FOREACH_END(); } /* }}} */ -/* {{{ */ -static inline void pthreads_prepare_closures(pthreads_object_t *thread) { - Bucket *bucket; - - ZEND_HASH_FOREACH_BUCKET(PTHREADS_CG(thread->creator.ls, function_table), bucket) { - zend_function *function = Z_PTR(bucket->val), - *prepared; - zend_string *named; - - - if (function->common.fn_flags & ZEND_ACC_CLOSURE) { - if (zend_hash_exists(CG(function_table), bucket->key)) { - continue; - } - - named = zend_string_new(bucket->key); - prepared = pthreads_copy_function(function); - - if (!zend_hash_add_ptr(CG(function_table), named, prepared)) { - destroy_op_array((zend_op_array*) prepared); - } - - zend_string_release(named); - } - } ZEND_HASH_FOREACH_END(); -} /* }}} */ - /* {{{ */ static inline void pthreads_prepare_classes(pthreads_object_t* thread) { zend_class_entry *entry; diff --git a/tests/assets/ExternalClosureDefinition.php b/tests/assets/ExternalClosureDefinition.php new file mode 100644 index 00000000..aa17fa44 --- /dev/null +++ b/tests/assets/ExternalClosureDefinition.php @@ -0,0 +1,10 @@ +shared = $shared; + } + + public function run() { + $this->running = true; + + require __DIR__ .'/assets/ExternalClosureDefinition.php'; + + $this->shared['loader'] = new ExternalClosureDefinition(); + $this->synchronized(function () { + while($this->running) { + $this->wait(0); + } + }); + } +} + +$shared = new \Threaded(); + +$foo = new Foo($shared); +$foo->start(); + +while(true) { + if(!isset($shared['loader'])) { + continue; + } + $closureDefinition = $shared['loader']; + $closureDefinition->load(); + break; +} +$foo->running = false; +$foo->notify() && $foo->join(); +--EXPECT-- +string(11) "Hello World" \ No newline at end of file