Skip to content
This repository has been archived by the owner on Dec 16, 2019. It is now read-only.

Commit

Permalink
Copy closures defined by included classes
Browse files Browse the repository at this point in the history
  • Loading branch information
sirsnyder committed Jan 12, 2018
1 parent 1af7671 commit 43ffd00
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 27 deletions.
55 changes: 28 additions & 27 deletions src/prepare.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);

This comment has been minimized.

Copy link
@dktapps

dktapps Aug 6, 2019

Contributor

This seems wasteful. Wouldn't it make more sense to simply copy closures after copying classes?


zend_hash_apply_with_arguments(
&prepared->function_table,
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions tests/assets/ExternalClosureDefinition.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

class ExternalClosureDefinition extends \Threaded {
public function load() {
$sync = function () {
var_dump('Hello World');
};
$sync();
}
}
49 changes: 49 additions & 0 deletions tests/closure-delayed-include.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
--TEST--
Closure copying of an included closure
--DESCRIPTION--
We need to copy closures which are defined and bound by included classes
--FILE--
<?php

class Foo extends \Thread {
/** @var bool */
public $running;

/** @var \Threaded */
private $shared;

public function __construct(\Threaded $shared) {
$this->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"

0 comments on commit 43ffd00

Please sign in to comment.