Skip to content

Commit f15cd75

Browse files
committed
Do not hold fiber after suspension
1 parent f989012 commit f15cd75

File tree

2 files changed

+31
-15
lines changed

2 files changed

+31
-15
lines changed

Zend/tests/fibers/destructors_005.phpt

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,53 @@ register_shutdown_function(function () {
88
});
99

1010
class Cycle {
11-
public static $counter = 0;
1211
public $self;
13-
public function __construct() {
12+
public function __construct(public int $id) {
1413
$this->self = $this;
1514
}
1615
public function __destruct() {
17-
$id = self::$counter++;
18-
printf("%d: Start destruct\n", $id);
16+
printf("%d: Start destruct\n", $this->id);
1917
try {
20-
if ($id === 0) {
18+
if ($this->id === 0) {
19+
/* Fiber will be collected by GC because it's not referenced */
20+
Fiber::suspend(new stdClass);
21+
} else if ($this->id === 1) {
22+
/* Fiber will be dtor during shutdown */
23+
global $f2;
24+
$f2 = Fiber::getCurrent();
2125
Fiber::suspend(new stdClass);
2226
}
2327
} finally {
24-
printf("%d: End destruct\n", $id);
28+
printf("%d: End destruct\n", $this->id);
2529
}
2630
}
2731
}
2832

29-
$f = new Fiber(function () {
30-
new Cycle();
31-
new Cycle();
33+
$refs = [];
34+
$f = new Fiber(function () use (&$refs) {
35+
$refs[] = WeakReference::create(new Cycle(0));
36+
$refs[] = WeakReference::create(new Cycle(1));
37+
$refs[] = WeakReference::create(new Cycle(2));
3238
gc_collect_cycles();
3339
});
3440

3541
$f->start();
3642

43+
gc_collect_cycles();
44+
45+
foreach ($refs as $id => $ref) {
46+
printf("%d: %s\n", $id, $ref->get() ? 'Live' : 'Collected');
47+
}
48+
3749
?>
3850
--EXPECT--
51+
2: Start destruct
52+
2: End destruct
3953
0: Start destruct
54+
0: End destruct
4055
1: Start destruct
41-
1: End destruct
56+
0: Collected
57+
1: Live
58+
2: Collected
4259
Shutdown
43-
0: End destruct
60+
1: End destruct

Zend/zend_gc.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,10 +1838,6 @@ static zend_always_inline zend_result gc_call_destructors(uint32_t idx, uint32_t
18381838
if (UNEXPECTED(fiber != NULL && GC_G(dtor_fiber) != fiber)) {
18391839
/* We resumed after suspension */
18401840
gc_check_possible_root((zend_refcounted*)&obj->gc);
1841-
1842-
GC_DELREF(&fiber->std);
1843-
gc_check_possible_root((zend_refcounted*)&fiber->std.gc);
1844-
18451841
return FAILURE;
18461842
}
18471843
}
@@ -1901,6 +1897,9 @@ static zend_never_inline void gc_call_destructors_in_fiber(uint32_t end)
19011897
GC_TRACE("destructor fiber suspended by destructor");
19021898
GC_G(dtor_fiber) = NULL;
19031899
GC_G(dtor_idx)++;
1900+
/* We do not own the fiber anymore. It may be collected if the
1901+
* application does not reference it. */
1902+
zend_object_release(&fiber->std);
19041903
fiber = gc_create_destructor_fiber();
19051904
continue;
19061905
} else {

0 commit comments

Comments
 (0)